使用 doc2vec 和 gensim 的文本分类模型

text classification model using doc2vec and gensim

我正在使用 gensim 和 doc2vec 进行文本分类。我正在使用两个数据集对此进行测试,一个是堆栈交换数据集和一个 Reddit 数据集。我正在尝试对来自一个 subreddit/stackexchange 站点的某个特定主题的帖子进行分类,然后使用来自其他不相关 subreddit/stackexchange 站点的帖子作为负面示例。

我正在使用包含 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")

这个方法有效,我可以从中得到结果,但我想知道是否有不同的训练方式可以达到更好的效果。目前我只是训练许多具有不同时期和 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")

听起来好像您正在为每个论坛的 "in"/"out" 决定训练一个单独的 Doc2Vec 模型,然后使用一组即兴的 infer_vector()/most_similar() 操作做出决定。

这是一种非常粗略的临时方法,您应该研究更正式的文本分类方法的介绍,其中有明确的特征发现步骤(可能包括创建 Doc2Vec 向量对于您的文本或其他技术),然后是分类器训练的明确步骤,然后是评估。

(那时您可能还会训练更大的模型,其中包括来自所有论坛的带标签的训练示例,以及从众多可能中选择一个的分类器 类。)

另外,您的 Doc2Vec 训练中有几处错误或不理想,包括:

  • 在您自己的循环中多次调用 train() 或更改默认的 alpha/min_alpha 值几乎总是被误导。您当前的代码实际上是 model.epochs (5) 传递每次调用的数据,并且经常将 alpha 递减 0.0002 数百次(变为无意义的负值)。只需调用一次 train(),使用所需数量的 epochs,默认值为 alpha/min_alpha,它就会做正确的事情。 (并且:不要相信在线 tutorial/example 建议的上述循环调用。)

  • 你的 hs=5 将打开严格的 on/off hierarchical-softmax 模式,但保留默认的 negative=5 参数 - 所以你的模型将使用负采样和分层 softmax 训练的(非标准且可能无用且缓慢)组合。最好使用一些 negative 值和 hs=0(对于纯负采样)或 negative=0, hs=1(对于纯分层 softmax)。或者只是坚持使用默认设置 (negative=5, hs=0) unless/until 一切都已经正常工作,并且您想进行更深入的优化。

  • min_count=1 很少是最佳选择:这些模型通常受益于丢弃稀有词。

纠正这些问题后,您可能会发现更多的数据往往会带来通常预期的改进结果。 (如果当时没有,请仔细检查所有文本 preprocessing/tokenization 在训练、推理和评估时是否正确完成——如果你仍然有问题,也许 post 一个新的那么问题,更多 specifics/numbers 关于预期改进的地方反而得分更差。)