Coggle 30 Days of ML(23年7月)任务六:训练FastText、Word2Vec词向量
任务六:学会训练FastText、Word2Vec词向量
说明:在这个任务中,你将学习如何训练FastText和Word2Vec词向量模型,这些词向量模型可以捕捉文本中的语义信息。
实践步骤:
准备大规模文本语料库。
使用FastText或gensim库中的Word2Vec类,设置相应的参数(如词向量维度、窗口大小、训练迭代次数等)来构建词向量模型。
使用Word2Vec类的build_vocab()方法,构建词汇表。
使用Word2Vec类的train()方法,训练词向量模型。
Word2Vec
word2vec主要包括Skip-Gram和CBOW两种模型。
Skip-Gram是利用一个词语作为输入,来预测它周围的上下文 ,CBOW是利用一个词语的上下文作为输入,来预测这个词语本身 。
word2vec模型其中有两种训练方式:skip-gram与CBOW,此外,还有两种加速训练的trick:hierarchical sofmtmax与negative sampling。
简单情形
输入:one-hot encoder
隐层:对输入的词求和取平均+线性层
输出:隐层
word2vec的本质:是一种降维操作——把词语从 one-hot encoder 形式的表示降维到 Word2vec 形式的表示,是一个|V|分类问题。
训练目标: 极小化负对数似然
Tip: CBOW的窗口内部丢掉了词序信息,但是在窗口滑动过程中是按照通顺的自然语言顺序滑动的,或者样本就是按照一定的语序取出来的,所以最终得出的词向量中会包含一定的语序信息。
Word2vec 的训练trick
Word2vec 本质上是一个语言模型,它的输出节点数是 V 个,对应了 V 个词语,本质上是一个多分类问题,但实际当中,词语的个数非常非常多,会给计算造成很大困难,所以需要用技巧来加速训练。
Word pairs and “phase”: 对常见的单词进行组合或者词组作为单个words来处理(比如"New York","United Stated")
**高频词采样:**对高频词进行抽样来减少训练样本的个数(比如the这个词在很多次的窗口中出现吗,他对其他词语义学习的帮助不大,并且,更多包含the的训练数据远远超出了学习the这个词向量所需要的样本数)
**负采样:**用来提高训练速度并且改善所得到词向量的质量 。
随机选取部分词作为负样本(比如当vocab_size为10000时,训练样本 input word:"fox",output word:"quick" ,在9999个负样本的权重中选择5-20个更新,参数大大减少)。
如何选择negative words?
根据词频进行负采样,出现概率高的单词容易被选为负样本。 每个单词被赋予一个权重。
层次softmax(Hierarchical Softmax)
在进行最优化的求解过程中:从隐藏层到输出的Softmax层的计算量很大,因为要计算所有词的Softmax概率,再去找概率最大的值。
word2vec采用了霍夫曼树来代替从隐藏层到输出softmax层的映射 。
和之前的神经网络语言模型相比,霍夫曼树的所有内部节点就类似之前神经网络隐藏层的神经元,其中,根节点的词向量对应我们的投影后的词向量,而所有叶子节点就类似于之前神经网络softmax输出层的神经元,叶子节点的个数就是词汇表的大小。在霍夫曼树中,隐藏层到输出层的softmax映射不是一下子完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为 Hierarchical Softmax 。
在word2vec中,我们采用了二元逻辑回归的方法,即规定沿着左子树走,那么就是负类(霍夫曼树编码1),沿 着右子树走,那么就是正类(霍夫曼树编码0)。判别正类和负类的方法是使用sigmoid函数, 采用随机梯度上升求解二分类,每计算一个样本更新一次误差函数 。
使用霍夫曼树有什么好处:
首先,由于是二叉树,之前计算量为V
,现在变成了log2V
。
第二,由于使用霍夫曼树是高频的词靠近树根,这样高频词需要更少的时间会被找到,这符合贪心优化思想。
fasttext
fasttext是基于浅层神经网络训练的,其训练方式与word2vec中的CBOW方式如出一辙,fasttext是对整个句子的n-gram特征相加求平均,得到句向量,在根据句向量做分类。
fasttext的输入:embedding过的单词的词向量和n-gram向量
内存考虑:哈希映射,将n-gram映射到固定K个的索引上,相同的索引共享相同的embedding。
fasttext与word2vec对比
fasttext用作分类是有监督的,word2vec是无监督的
fasttext输入部分考虑了n-gram特征,word2vec的输入只有one-hot encoder
fasttext可以表示oov的单词
word2vec的不足:
多义词的问题。
Word2vec 是一种静态的方式,无法针对特定任务做动态优化
fasttext的不足:
fastText很难学出词序对句子语义的影响,对复杂任务还是需要用复杂网络学习任务的语义表达。
gensim中word2vec的使用
首先我们先介绍一下gensim中的word2vec API,官方API介绍如下:
class Word2Vec(utils.SaveLoad): def __init__( self, sentences=None, size=100, alpha=0.025, window=5, min_count=5, max_vocab_size=None, sample=1e-3, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, cbow_mean=1, hashfxn=hash, iter=5, null_word=0, trim_rule=None, sorted_vocab=1, batch_words=MAX_WORDS_IN_BATCH):
在gensim中,word2vec相关的API都在包gensim.models.word2vec中。和算法有关的参数都在类gensim.models.word2vec.Word2Vec中。算法需要注意的参数有:
sentences: 我们要分析的语料,可以是一个列表,或者从文件中遍历读出(通过word2vec提供的LineSentence类来读文件,word2vec.LineSentence(filename))。
vector_size: 词向量的维度,默认值是100。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度。
window:即词向量上下文最大距离,window越大,则和某一词较远的词也会产生上下文关系。默认值为5。在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。对于一般的语料这个值推荐在[5,10]之间。
sg: 即我们的word2vec两个模型的选择了。如果是0, 则是CBOW模型,是1,则是Skip-Gram模型,默认是0,即CBOW模型。
hs: 即我们的word2vec两个解法的选择了,如果是1, 则是Hierarchical Softmax,是0的话并且负采样个数negative大于0, 则是Negative Sampling。默认是0即Negative Sampling。
negative:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间。
cbow_mean: 仅用于CBOW在做投影的时候,为0,则算法中的xw��为上下文的词向量之和,为1则为上下文的词向量的平均值。在我们的原理篇中,是按照词向量的平均值来描述的。个人比较喜欢用平均值来表示xw��,默认值也是1,不推荐修改默认值。
min_count:需要计算词向量的最小词频。这个值可以去掉一些很生僻的低频词,默认是5。如果是小语料,可以调低这个值。
iter: 随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大这个值。
alpha: 在随机梯度下降法中迭代的初始步长。算法原理篇中标记为η,默认是0.025。
min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步长值。随机梯度下降中每轮的迭代步长可以由iter,alpha, min_alpha一起得出。这部分由于不是word2vec算法的核心内容,因此在原理篇我们没有提到。对于大语料,需要对alpha, min_alpha,iter一起调参,来选择合适的三个值。
导入相关库和模块
使用Python导入所需的库和模块。对于FastText,你可以使用FastText库;对于Word2Vec,你可以使用gensim库。
# 导入FastText库 from gensim.models.fasttext import FastText # 导入Word2Vec库 from gensim.models import Word2Vec
在上面的示例中,size
参数表示词向量的维度,window
参数表示词语的上下文窗口大小,min_count
参数表示词语在语料库中的最低出现次数。
构建词汇表
构建词汇表:使用Word2Vec类的 build_vocab()
方法,根据语料库构建词汇表。
这里我们可以根据我们的数据的content,构建一个词汇表,为接下来的训练做准备
contents = train_data['content'].apply(lambda x:x.split(' ')).tolist() # contents字段 model = Word2Vec(min_count=1) model.build_vocab(contents) # prepare the model vocabulary
训练模型
训练词向量模型:使用Word2Vec类的 train()
方法,对词向量模型进行训练。
# 训练Word2Vec词向量模型 model.train(contents, total_examples=model.corpus_count, epochs=model.epochs) # train word vectors model.save("word2vec.model")
在上面的示例中,cpmtents 是训练数据,total_examples 表示语料库的总样本数,epochs 表示训练迭代次数。这些也可以在定义模型的到时候修改一下参数,这里我们使用的是默认参数
训练过程会根据语料库中的文本数据来更新词向量模型的权重和参数,使得模型能够学习到词语之间的语义信息。
完成以上步骤后,你将得到训练好的FastText或Word2Vec词向量模型,可以使用它们来获取词语的向量表示,进行词语相似度计算、文本分类等自然语言处理任务。
预训练模型
Gensim在Gensim-data资源库中附带了几个已经预先训练好的模型
为了能得到更好的结果,所以如果利用一些预训练的Word2Vec可能会得到更好的结果,所以这里我们也可以下载一些已有的模型
import gensim.downloader print(list(gensim.downloader.info()['models'].keys())) # 在gensim-data中显示所有可用的模型
['fasttext-wiki-news-subwords-300', 'conceptnet-numberbatch-17-06-300', 'word2vec-ruscorpora-300', 'word2vec-google-news-300', 'glove-wiki-gigaword-50', 'glove-wiki-gigaword-100', 'glove-wiki-gigaword-200', 'glove-wiki-gigaword-300', 'glove-twitter-25', 'glove-twitter-50', 'glove-twitter-100', 'glove-twitter-200', '__testing_word2vec-matrix-synopsis']
glove_vectors = gensim.downloader.load('glove-twitter-25') # 下载 "glove-twitter-25 "的嵌入 print(glove_vectors.most_similar('twitter')) # 照常使用下载的向量
在这里我们使用的还是word2vec的模型,所以选取一个比较好的word2vec的模型进行微调,不过这里也会有一个缺陷,由于比赛的数据是已经经过处理的,所以其实很难看出原有的意思表示,所以来说,不一定能得到一个比较好的结果,不过可以先进行尝试
使用训练好的模型预测
import gensim model = gensim.models.Word2Vec.load('word2vec.model') #查看某个字词的向量: print(model['5212']) #查看与该词最接近的其他词汇及相似度: print(model.most_similar(['0'])) #查看两个词之间的相似度: model.similarity('5212','0')
[-5.3622725e-04 2.3643016e-04 5.1033497e-03 9.0092728e-03 -9.3029495e-03 -7.1168090e-03 6.4588715e-03 8.9729885e-03 -5.0154282e-03 -3.7633730e-03 7.3805046e-03 -1.5334726e-03 -4.5366143e-03 6.5540504e-03 -4.8601604e-03 -1.8160177e-03 2.8765798e-03 9.9187379e-04 -8.2852151e-03 -9.4488189e-03 7.3117660e-03 5.0702621e-03 6.7576934e-03 7.6286553e-04 6.3508893e-03 -3.4053659e-03 -9.4640255e-04 5.7685734e-03 -7.5216386e-03 -3.9361049e-03 -7.5115822e-03 -9.3004224e-04 9.5381187e-03 -7.3191668e-03 -2.3337698e-03 -1.9377422e-03 8.0774352e-03 -5.9308959e-03 4.5161247e-05 -4.7537349e-03 -9.6035507e-03 5.0072931e-03 -8.7595871e-03 -4.3918253e-03 -3.5099984e-05 -2.9618264e-04 -7.6612402e-03 9.6147414e-03 4.9820566e-03 9.2331432e-03 -8.1579182e-03 4.4957972e-03 -4.1370774e-03 8.2453492e-04 8.4986184e-03 -4.4621779e-03 4.5175003e-03 -6.7869616e-03 -3.5484887e-03 9.3985079e-03 -1.5776539e-03 3.2137157e-04 -4.1406299e-03 -7.6826881e-03 -1.5080094e-03 2.4697948e-03 -8.8802812e-04 5.5336617e-03 -2.7429771e-03 2.2600652e-03 5.4557943e-03 8.3459523e-03 -1.4537406e-03 -9.2081428e-03 4.3705511e-03 5.7178497e-04 7.4419067e-03 -8.1328390e-04 -2.6384138e-03 -8.7530091e-03 -8.5655687e-04 2.8265619e-03 5.4014279e-03 7.0526553e-03 -5.7031228e-03 1.8588186e-03 6.0888622e-03 -4.7980524e-03 -3.1072616e-03 6.7976285e-03 1.6314745e-03 1.8991709e-04 3.4736372e-03 2.1777629e-04 9.6188262e-03 5.0606038e-03 -8.9173913e-03 -7.0415614e-03 9.0145587e-04 6.3925339e-03] [('4952', 0.37755849957466125), ('2195', 0.3286932408809662), ('4369', 0.32638630270957947), ('5137', 0.3003348112106323), ('4682', 0.29854971170425415), ('4130', 0.27968209981918335), ('97', 0.2749629318714142), ('339', 0.27286359667778015), ('3541', 0.27277031540870667), ('4780', 0.2706093490123749)] -0.027750365