我正在使用gensim和doc2vec进行文本分类。我使用了两个数据集来测试这个模型,一个是Stack Exchange数据集,另一个是Reddit数据集。我试图对来自某个特定主题的子论坛/Stack Exchange站点的帖子进行分类,并使用来自其他不相关子论坛/Stack Exchange站点的帖子作为负面例子进行分类。
我使用了10k个帖子的数据集来训练模型,并使用5k个帖子的测试集,其中50%为正面例子,50%为负面例子。然后我使用infer_vector和most_similar函数来将条目分类为正面或负面。在训练模型之前,我对数据进行了预处理,删除了任何单词、符号、链接等,只保留了最重要的单词来训练模型。以下是用于训练模型的代码。
df = pd.read_csv("fulltrainingset.csv")df.columns.values[0] = "A"tagged_data = [TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]) for i, _d in enumerate(df["A"])]epoch_list = [1,5,10,15,25,50,100,200,300,400]size_list = [1,5,10,15,25,50,100,200,300]for x in epoch_list: for y in size_list: vec_size = y max_epochs = x minimum_count = 1 mode = 0 window_ = 15 negative_sampling = 5 subsampling = 1e-5 alpha = 0.025 minalpha = 0.00025 model = Doc2Vec(alpha=alpha, min_alpha=minalpha, vector_size=vec_size, dm=mode, min_count=minimum_count, window =window_, sample=subsampling ,hs =negative_sampling) model.build_vocab(tagged_data) for epoch in range(max_epochs): print('iteration {0}'.format(epoch)) model.train(tagged_data, total_examples=model.corpus_count, epochs=model.epochs)#self.epochs model.alpha -= 0.0002 model.min_alpha = model.alpha model.save(str(y)+"s_"+str(x)+"e.model")
这种方法是有效的,我可以从中获得结果,但我希望知道是否有其他训练方法可以获得更好的结果。目前我只是训练了多个具有不同epochs和vector_sizes的模型,然后使用infer_vector和most_similar函数来查看most_similar条目返回的向量得分是否大于某个特定值,但在训练模型方面是否有改进的方法?
另外,为了获得更好的结果,我以相同的方式训练了另一个模型,使用更大的数据集(100k+条目)。当我使用这个模型在相同的数据集上时,产生的结果与在较小数据集上训练的模型类似但更差。我原本以为更多的训练数据会改善结果而不是使其变差,有人知道这是为什么吗?
此外,为了进一步测试,我创建了一个新的但更大的测试集(15k条目),结果甚至比原始测试集更差。这个测试集中的数据虽然是独特的,但与原始测试集中使用的数据类型相同,却产生了更差的结果,这可能是什么原因?
df = pd.read_csv("all_sec_tweets.csv")df.columns.values[0] = "A"tagged_data = [TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]) for i, _d in enumerate(df["A"])]epoch_list = [1,5,10,15,25,50,100]size_list = [1,5,10,15,25,50,100]for x in epoch_list: for y in size_list: vec_size = y max_epochs = x mode = 0 window_ = 5 subsampling = 1e-5 model = Doc2Vec(vector_size=vec_size, dm=mode, window =window_, sample=subsampling,epochs=max_epochs) model.build_vocab(tagged_data) model.train(tagged_data,total_examples=model.corpus_count,epochs=model.epochs) model.save(str(y)+"s_"+str(x)+"e.model")
回答:
听起来你是在为每个论坛的“进入/退出”决策训练一个单独的Doc2Vec
模型,然后使用一套临时的infer_vector()
/most_similar()
操作来做出决策。
这是一种非常粗糙、临时性的方法,你应该研究一下更正式的文本分类方法的介绍,其中有一个明确的特征发现步骤(可能包括为你的文本创建Doc2Vec
向量,或其他技术),然后是一个明确的分类器训练步骤,最后是评估步骤。
(你可能还会在那个时候训练包含来自所有论坛的标记训练例子的更大模型,以及选择多个可能类别的分类器。)
此外,你的Doc2Vec
训练中存在几个错误或非最优的地方,包括:
-
在自己的循环中多次调用
train()
几乎总是误导的,或者改变默认的alpha
/min_alpha
值。你当前的代码实际上是在每次调用时对数据进行model.epochs
(5)次传递,并且常常将alpha
减少0.0002
数百次(进入无意义的负值)。只调用一次train()
,使用所需的epochs
数量,使用默认的alpha
/min_alpha
值,它会做正确的事情。(并且:不要相信任何在线教程/示例建议上述循环调用。) -
你的
hs=5
会开启严格的开/关层次softmax模式,但保留了默认的negative=5
参数——所以你的模型将使用负采样和层次softmax训练的组合(非标准且可能无用且缓慢)。最好使用某个negative
值和hs=0
(用于纯负采样),或negative=0, hs=1
(用于纯层次softmax)。或者,除非/直到一切都已经工作并且你想深入优化,否则就坚持使用默认值(negative=5, hs=0
)。 -
min_count=1
很少是最佳选择:这些模型通常会从丢弃稀有词中受益。
在纠正这些问题后,你可能会发现更多的数据通常会带来预期的改进结果。(如果那时仍然没有,那么请再次检查所有文本预处理/分词是否正确完成,在训练、推理和评估时——如果你仍然遇到问题,或许那时可以发布一个新问题,提供更多关于预期改进反而得分更差的具体信息/数字。)