许多优秀算法有一个特点:简单高效,word2vec正属于此类。简单的一个hidden layer,外加高效的negative sample,就能取得很不错的embedding效果。
当然最靠谱的算法实现就是word2vec作者给出的源码,在实际应用中,不论是词embedding或者行为序列embedding,获得的效果都不错。今天谈论一下tensorflow word2vec的使用感受。
个人认为在算法应用中,最重要的是数据的收集,预处理和特征工程。没有正确可靠的数据,再好的算法也是巧妇难为无米之炊,如果只是单纯走通算法,在实际落地中,意义很小。一个算法如果线上表现不好,一方面是参数调整,更多的是要考虑数据处理是否有问题。
word2vec用tensorflow来实现,代码很简洁,负采样也有现成实现nce_loss。但我最感兴趣的是数据处理的方式,官方给出的demo是基于skip-gram + negative sample,材料中对数据处理也没有详述,在实际应用中,有下面几点感受:
- 设置vocabulary_size这个参数不合适,word2vec的c源码是设置了min_count,这样的好处是只保留频繁的单词,因为频繁,所以训练才会充分,那些频率低的单词的训练结果置信度很低,会降低整体embedding的可靠程度。这里设置vocabulary_size就不合理了,虽然按照频次倒排,但无法排除频率低的单词。
- generate_batch的实现有点别扭,比如global data_index,让代码显得很松散,还有collections.deque的使用,让代码读起来不清晰。
- num_steps参数不合适,在训练过程中,需要打印中间结果信息,方便检验运行是否正确。用num_steps来衡量训练迭代充分与否不恰当,这和vocabulary_size一个道理,num_steps设置多少才算合理呢?在word2vec的c源码是设置了epoch这个参数,使得可以一轮一轮地用数据训练模型,简单明了。
在实际应用中,我也对上面几点进行了修改,贴合原word2vec的数据处理方式,线上效果不错。tensorflow-word2vec-demo有这样的不足,觉得是因为word2vec的离线效果不好衡量,一般都是训练结束,用tsne可视化一下,看起来很炫就结束了。而原word2vec的c实现是经过了工业界检验的,里面有很多小trick,这些都是线上迭代的结晶,看起来不显眼,却是不可或缺,许多trick的堆叠引起质变,pure的算法实现与此相比在线上的表现差距巨大。
此外,在实际线上应用的感受是,skip-gram模型是优于cbow模型的。因为本身是做推荐算法的,个人觉得word2vec也是一种协同思想,最后embedding的结果是单词间共现关系的体现。在cbow模型中,$mean(context)\rightarrow target$这会丢失许多信息,使得训练并不充分。而cbow对于语言模型,也挺奇怪,上下文的语义就是平均吗。。有点粗鲁。RNN的LSTM就设立了各种gate来学习context,很精巧。