我正在为数据集构建类别推荐的 Word2Vec 模型,该数据集由约 35.000 个句子组成,总共约 500.000 个单词,但只有约 3.000 个不同的单词。 我基本上是这样构建模型的:
def train_w2v_model(df, epochs):
w2v_model = Word2Vec(min_count=5,
window=100,
size=230,
sample=0,
workers=cores-1,
batch_words=100)
vocab = df['sentences'].apply(list)
w2v_model.build_vocab(vocab)
w2v_model.train(vocab, total_examples=w2v_model.corpus_count, total_words=w2v_model.corpus_total_words, epochs=epochs, compute_loss=True)
return w2v_model.get_latest_training_loss()
我试图为这样的模型找到正确的纪元数:
print(train_w2v_model(1))
=>> 86898.2109375
print(train_w2v_model(100))
=>> 5025273.0
我发现结果非常违反直觉。
我不明白增加纪元数量如何导致性能下降。
这似乎不是对函数 get_latest_training_loss
的误解,因为我观察到函数 most_similar
的结果只需 1 个时期就更好了:
100 纪元:
w2v_model.wv.most_similar(['machine_learning'])
=>> [('salesforce', 0.3464601933956146),
('marketing_relationnel', 0.3125850558280945),
('batiment', 0.30903393030166626),
('go', 0.29414454102516174),
('simulation', 0.2930642068386078),
('data_management', 0.28968319296836853),
('scraping', 0.28260597586631775),
('virtualisation', 0.27560457587242126),
('dataviz', 0.26913416385650635),
('pandas', 0.2685554623603821)]
1 纪元:
w2v_model.wv.most_similar(['machine_learning'])
=>> [('data_science', 0.9953729510307312),
('data_mining', 0.9930223822593689),
('big_data', 0.9894922375679016),
('spark', 0.9881765842437744),
('nlp', 0.9879133701324463),
('hadoop', 0.9834049344062805),
('deep_learning', 0.9831978678703308),
('r', 0.9827396273612976),
('data_visualisation', 0.9805369973182678),
('nltk', 0.9800992012023926)]
有什么关于它为什么会这样的见解吗?我认为增加纪元数肯定会对训练损失产生积极影响。
最佳答案
首先,至少在 gensim-3.8.1(2019 年 9 月)中,运行训练损失的报告是一个半生不熟的功能。它只是所有时期的所有损失的运行总和 - 因此总是增加 - 而不是每个时期的损失可能会减少。有一个悬而未决的fix that still needs a little work ,但在添加之前,报告的数字需要与早期数字进行额外比较,以检测任何纪元之间的减少。
但还要注意:即使是每个时期的损失也不能直接衡量用于外部目的的模型质量/性能。这只是培训是否仍然有助于其内部优化任务的一个指标。
其次,如果实际上模型在外部评估中变得更糟(例如 most_similar()
结果是否与人类估计相匹配),并且经过更多训练,那么这通常表明发生了过度拟合。也就是说,(可能过大的)模型正在内存(可能过小的)训练数据的特征,从而以不再泛化到更大的感兴趣世界的方式更好地实现其内部优化目标。
对于 word2vec 训练集来说,500K 总单词量相当小,但如果您也打算只训练较小的词汇量(因此每个单词仍然有许多不同的示例),并且使用较小维度的单词,那么这可能是有用的向量。
尚不清楚计算出的 min_count
是多少,但请注意,通过缩小模型来增加它可以防止过度拟合。但还要注意,任何出现次数少于该阈值的单词都将在训练过程中被完全忽略,从而使您的有效训练数据大小更小。
同样,不清楚您正在使用什么embedding_size
,但是尝试为小词汇量创建“非常大”的向量非常容易过度拟合,因为向量有足够的“空间”记住训练细节。较小的向量会对模型施加某种“压缩”,从而使学习更有可能泛化。 (我的非常粗略的经验法则,一点也不严格建立,就是永远不要使用大于预期词汇大小的平方根的密集嵌入大小。因此,对于 10K 个标记,不超过 100 维向量。)
其他观察结果,可能与您的问题无关,但可能对您的目标感兴趣:
window=100
是非典型的,并且似乎远大于平均文本大小(约 14 个字) - 如果意图是所有标记都应该影响所有其他标记,而不考虑距离(也许是因为源数据本质上是无序的),这是合适的,您也可以做得更大(比如 100 万)。另一方面,如果一个标记的直接邻居比同一文本中的其他标记更相关,那么较小的窗口就有意义。没有充分的理由使用
batch_words=100
- 它只会减慢训练速度,而且如果实际上您有超过 100 个单词的文本,它会人为地将它们分解(从而抵消了上面巨大的window
值带来的任何好处)。 (将此保留为默认值。)train()
方法将仅使用total_examples
或total_words
,但不能同时使用两者 - 因此您只需指定一个因为看起来您可能正在使用更像类别推荐而不是纯自然语言的东西,您可能还想修改
ns_exponent
参数的非默认值 - 检查class docs 中的文档评论和引用论文有关该参数的更多详细信息。
关于python - Gensim Word2Vec 模型因增加 epoch 数而变得更糟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58186670/