欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

word2vec原理&代码 详细全面总结

程序员文章站 2022-06-15 14:42:08
...

本文介绍word2vec必备基础知识,原理,结构,模型训练及代码。

表示学习:将研究对象的语义信息表示为稠密低维实值向量。在该低维向量空间中,2个对象距离越近则说明其语义相似度越高。
word2vec:2013年,由Google团队提出。word2vec 是一种词嵌入(word embedding)技术,即把一个词语转换成其对应的向量表达,进而方便计算机处理。word2vec是词嵌入技术发展的重要里程碑。

一、统计语言模型—必备基础知识

统计语言模型(Statistical Language Model)是自然语言处理的基础模型,是从概率统计角度出发,解决自然语言上下文相关的特性的数学模型。统计语言模型的核心就是判断一个句子在文本中出现的概率

假定SS表示某个有意义的句子,由一连串特定顺序排列的词(ω1,ω2,,ωn)(\omega_{1}, \omega _{2}, \ldots, \omega_{n})组成,nn是句子的长度。将SS在文本中出现概率表示为P(S)P(S),则P(S)=P(ω1,ω2,,ωn)P(S)=P(\omega_{1}, \omega _{2}, \ldots, \omega_{n})

利用条件概率公式:

P(ω1,ω2,,ωn)=P(ω1)P(ω1ω2)P(ω3ω1,ω2)P(ωnω1,ω2,ωn1)P(\omega_{1}, \omega _{2}, \ldots, \omega_{n})=P(\omega_{1})\cdot P(\omega_{1}|\omega_{2})\cdot P(\omega_{3}|\omega_{1},\omega_{2}) \ldots P(\omega_{n}|\omega_{1},\omega_{2} \ldots, \omega_{n-1})
将序列的联合概率转化为一系列条件概率的乘积。那么问题变成了如何去预测这些给定previous words下的条件概率P(ω1,ω2,ωn1)P(\omega_{1},\omega_{2} \ldots, \omega_{n-1})

nn太大时,上式难以计算。因此在此基础上马尔可夫提出了,一种马尔可夫假设:假设一个词出现的概率只与前面N-1个词相关。当N=2时(只考虑前一个词),就是简单的二元模型(Bigram Model),N=3(只考虑前2个词),三元模型(Trigram Model),当N=N时(考虑前N-1个词),就是常说的N元模型(N-gram Model)。

二、词的表示学习类型

1. 独热编码 one hot

one hot 向量,维度大小为整个词汇表的大小,对于每个具体的词汇表中的词,将对应的位置设置为1,其他位置为0。如,句子*(今年,夏天,超级,热),词语夏天*的one hot向量为(0,1,0,0).
独热编码的缺点:稀疏(很多0)、孤立(无法表示出在语义层面上词语之间的相关信息)、高维(词汇表很大时,词向量高维)。

2. 分布式表示学习 distributed representation

这里分布式可以理解为单看向量的某个维度没有意义,但综合起来就能表示词的意义,解决了one hot存在的问题。例:某个词的向量表示 [0.31343242, 0.65464122, 0.12343425, …, -1.324344]

词的分布式表示主要可以分为三类:基于矩阵的分布表示、基于聚类的分布表示和基于神经网络的分布表示。
接下来只介绍word2vec,一种基于神经网络的分布表示。

三、 word2vec

word2vec 包含两个模型:跳字模型(skip-gram)和连续词袋模型(continuous bag of words,简称CBOW);
两种高效训练的方法:负采样(negative sampling)和层序softmax(hierarchical softmax)。

1. CBOW

CBOW 是一个三层神经网络(所以word2vec称为浅层模型,浅层向量表示)。如下图所示,该模型的特点是输入已知上下文,输出对当前单词的预测。

word2vec原理&代码 详细全面总结
输入层
假设所有训练数据所构成的词典大小为VV。现在输入数据为“今年夏天超级热”,分词后将每个词表示为VV维的one hot向量,设某个词的输入向量/one hot向量表示为x1Vx_{1*V}。现假设根据上下文*“今年,超级,热”来预测中心词“夏天”*。

然后网络初始化权重,该权重为一个矩阵表示为WVNW_{V*N},其中NN为词向量的维度。该权重矩阵也称为投影矩阵,投影到词空间的矩阵。(多次迭代后的结果也就是我们要的词向量矩阵)

隐藏层
分别将输入层的4个词的向量*投影矩阵,即 x1Vx_{1*V} * WVNW_{V*N},将这4个结果相加后求平均,即得到隐藏层的结果h1Nh_{1*N}
然后将h1Nh_{1*N}乘以另一个投影矩阵WNVW'_{N*V},将结果传播到输出层。

输出层
使用**函数softmax,输出结果one hot 向量O1VO_{1*V}。将该one hot 向量与true label“夏天”的向量做比较,然后进行误差反向传播,不断迭代优化权重矩阵,最终即得到我们要的词向量矩阵(每行为一个词所对应的词向量,维度为N,V个词就有V行)。

注意:这里有两个矩阵WVNW_{V*N}WNVW'_{N*V},一般使用前者作为我们的词向量矩阵,也可以使用后者,或两者相加求平均。

word2vec原理&代码 详细全面总结
目标为最大化对数似然函数
目标为使得每个P(ωiContext(ωi))P(\omega_{i}|Context(\omega_{i}))最大,根据以上统计语言模型,可知道是相乘。这里取对数可转化为相加,方便计算。
word2vec原理&代码 详细全面总结

2. skip gram

CBOW 是一个三层神经网络。如下图所示,该模型的特点是已知当前词语,预测上下文。训练过程类似,这里不再赘述。
word2vec原理&代码 详细全面总结

训练优化方法

注意到,实际中词汇表一般很大,那么Word2Vec模型是一个超级大的神经网络(权重矩阵规模非常大)。
两种方法优化训练过程:负采样(negative sampling)和层序softmax(hierarchical softmax)

(1)负采样
负采样核心思想:不考虑出现概率低的词,保证频次越高的样本越容易被采样出来
(softmax分出来的类别数目是整个词汇表的大小,那么是否可以减小?)详见word2vec的负采样

(2)hierarchical softmax
hierarchical softmax的核心内容是将词汇表中的每个词使用哈夫曼树(Huffman Tree)进行编码,出现概率越高的符号使用较短的编码(层次越浅),出现概率低的符号则使用较长的编码(层次越深)。这样做,可以使得最终是在做一层层的二分类。详见基于hierarchical softmax的word2vec

四、word2vec代码实现

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
功能:使用word2vec将分词后的数据进行文本向量化,保存词语的索引字典、词向量,然后保存为pkl文件
word2vec:
	1.预训练语料:已分词的语料,输入格式为txt(一行为一个样本)或list of list
	2.建立一个空的模型对象;遍历一次语料库建立词典;第二次遍历语料库建立并训练模型(初始化词向量,逐句的读取一系列的词,用梯度下降法更新词向量)
	3.可保存的:模型;根据语料得到的索引字典{索引数字: 单词},词向量(后两者通过pickle库保存)
	4.模型评估:词的向量表示,词与词之间的相似度,与某个词最相近的前N个词
"""

import pickle
import logging
import gensim
from gensim.models import Word2Vec, word2vec
from gensim.corpora.dictionary import Dictionary

addr = 'E:/word2vec/'

# 将日志输出到控制台
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) 


#==========================1.读取预训练语料=======================================
print("选择分词后的文本作为训练语料...")
#这里输入数据格式为txt,一行为一个样本
sentences = word2vec.LineSentence(r"E:/word2vec/seg_sent.txt")

#=====================2.训练Word2vec模型(可修改参数)...====================
print('训练Word2vec模型(可自定义参数)...')
model = Word2Vec(sentences,
                 size=100,  # 词向量维度
                 min_count=5,  # 词频阈值
                 window=5)  # 窗口大小
'''
参数解读
#sg=1是skip—gram算法,对低频词敏感,默认sg=0为CBOW算法
#size是特征向量的维度。
#window是句子中当前词与目标词之间的最大距离,3表示在目标词前看3-b个词,后面看b个词(b在0-3之间随机)
#min_count是对词进行过滤,频率小于min-count的单词则会被忽视,默认值为5。
#negative和sample可根据训练结果进行微调,sample表示更高频率的词被随机下采样到所设置的阈值,默认值为1e-3,
#negative: 如果>0,则会采用negativesamping,用于设置多少个noise words
#hs=1表示层级softmax将会被使用,默认hs=0且negative不为0,则负采样将会被选择使用。
#workers是线程数,此参数只有在安装了Cpython后才有效,否则只能使用单核
'''
print(u"保存w2v模型...")
model.save(addr + 'w2v_100.model')  # 保存模型
print("保存w2v模型的位置: ", addr + 'w2v_100.model', '\n')


'''
模型评估
print('计算与词A的最近似的(前10个)词:')
model.most_similar("wordA",top n=10))#计算与该词最近似的词,top n指定排名前n的词

print('计算词A和词B的相似度:')
model.similarity("wordA","wordB") 

print('获取词A的词向量:')
model ['wordA']
'''
#===================3.创建词语字典,并返回word2vec模型中词语的索引,词向量================
def create_dictionaries(p_model):
    gensim_dict = Dictionary()  # 创建词语词典
    gensim_dict.doc2bow(p_model.wv.vocab.keys(), allow_update=True)
    w2dict_index = {v: k + 1 for k, v in gensim_dict.items()}  # 词语+索引。词语的索引,从1开始编号
    w2index_dict = {k + 1: v for k, v in gensim_dict.items()}  # 索引+词语。词语的索引,从1开始编号
    w2vec = {word: p_model[word] for word in w2dict_index.keys()}  # 词语的词向量
    return w2dict_index, w2index_dict, w2vec


#====================4.从训练好的模型中提取出索引字典、词向量字典index_dict,==========================
dict_index, index_dict, word_vectors= create_dictionaries(model)
#注意,后续将词向量输入到模型中(如CNN)训练时,实际输入为每个词/词向量的索引

#===========================5.使用 pickle 存储序列化数据 ====================================
#pickle是一个非常方便的库 可以将py的字典、列表等等程序运行过程中的对象存储为实体数据存储为pkl文件
print(u"保存x_dict_indexpkl.pkl文件...")
output = open(addr + "w2v_100.pkl", 'wb')
pickle.dump(dict_index, output)  # 索引字典,{单词: 索引数字}
pickle.dump(index_dict, output)  #索引字典,{索引数字: 单词}
pickle.dump(word_vectors, output)  # 词向量字典
output.close()
print("保存pkl文件的位置: ", addr + "w2v_100.pkl", '\n')


if __name__ == "__main__":
    pass

词嵌入技术的发展

word2vec之后其他词嵌入技术:fastText,GloVe,BERT等

参考文献

https://blog.csdn.net/yu5064/article/details/79601683
https://www.jianshu.com/p/d8bfaae28fa9
https://zhuanlan.zhihu.com/p/53194407