Thi*_*eur 5 python nlp machine-learning gensim word2vec
我正在构建一个 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()
Run Code Online (Sandbox Code Playgroud)
我试图为这样的模型找到合适的时代数:
print(train_w2v_model(1))
=>> 86898.2109375
print(train_w2v_model(100))
=>> 5025273.0
Run Code Online (Sandbox Code Playgroud)
我发现结果非常违反直觉。我不明白增加 epoch 的数量会导致性能下降。这似乎不是函数的误解,get_latest_training_loss因为我观察到函数的结果most_similar更好,只有 1 个 epoch :
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)]
Run Code Online (Sandbox Code Playgroud)
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)]
Run Code Online (Sandbox Code Playgroud)
关于它为什么会这样的任何见解?我认为增加 epoch 的数量肯定会对训练损失产生积极影响。
首先,至少通过 gensim-3.8.1(2019 年 9 月),对跑步训练损失的报告有点半生不熟。它只是所有时期所有损失的运行总和 - 因此总是增加 - 而不是每个时期可能减少的损失。有一个长期悬而未决的修复,仍然需要一些工作,但在添加之前,报告的数字需要与早期数字进行额外比较,以检测任何时代到时代的减少。
但还要注意:即使是 per-epoch 损失也不是用于外部目的的模型质量/性能的直接衡量标准。这只是一个指标,培训是否仍然有助于其内部优化任务。
其次,如果实际上模型在外部评估中变得更糟——比如most_similar()结果是否与人类估计相匹配——随着更多的训练,那么这通常表明过度拟合正在发生。也就是说,(可能过大)模型正在记住(可能过小)训练数据的特征,从而以不再泛化到更大的感兴趣世界的方式更好地实现其内部优化目标。
对于 word2vec 训练集来说,总共 50 万个单词是相当少的,但是如果您还打算只训练一个小词汇表(因此每个单词仍然有许多不同的示例)并使用小维度的向量,那么这可能是有用的。
不清楚你的计算min_count是什么,但请注意,通过缩小模型来增加它可以对抗过度拟合。但还要注意,任何出现次数少于该阈值的单词在训练期间都将被完全忽略,从而使您的有效训练数据量更小。
同样,不清楚embedding_size您在使用什么,但是尝试为小词汇量制作“非常大”的向量非常容易过度拟合,因为向量有足够的“空间”来记住训练细节。较小的向量会强制对模型进行某种“压缩”,从而导致更可能泛化的学习。(我非常粗略的经验法则,完全没有严格建立,是永远不要使用大于预期词汇量平方根的密集嵌入大小。因此,对于 10K 个标记,不超过 100 维向量。)
其他观察结果,可能与您的问题无关,但可能对您的目标感兴趣:
window=100是非典型的,似乎远大于您的平均文本大小(约 14 个字)——如果意图是所有标记都应该影响所有其他标记,而不考虑距离(可能是因为源数据本质上是无序的),那是合适的,并且您还不如做得更大(比如 100 万)。另一方面,如果标记的直接邻居比同一文本中的其他标记更相关,则较小的窗口会有意义。
没有充分的理由使用batch_words=100——它只会减慢训练速度,而且如果实际上你有任何超过 100 个单词的文本,它会人为地分解它们(从而取消上述巨大window值的任何好处)。(将此保留为默认值。)
该train()方法将只使用total_examples, or total_words,但不能同时使用 - 所以你只需要指定一个
由于看起来您可能正在使用更像是类别推荐而不是纯自然语言的东西,您可能还想修改ns_exponent参数的非默认值- 检查类文档中关于该参数的文档注释和参考论文更多细节。