达观杯文本智能处理(3)

Word2vec词向量原理与实践

斯坦福NLP视频

1. 什么是word2vec

word2vec工具主要包含两个模型:跳字模型(skip-gram)和连续词袋模型(continuous bag of words,简称CBOW),以及两种高效训练的方法:负采样(negative sampling)和层序softmax(hierarchical softmax)。值得一提的是,word2vec词向量可以较好地表达不同词之间的相似和类比关系。

自然语言是一套用来表达含义的复杂系统。在这套系统中,词是表义的基本单元。在机器学习中,如何使用向量表示词?顾名思义,词向量是用来表示词的向量,通常也被认为是词的特征向量。近年来,词向量已逐渐成为自然语言处理的基础知识。

NLP(自然语言处理)里面,最细粒度的是 词语,词语组成句子,句子再组成段落、篇章、文档。所以处理 NLP 的问题,首先就要拿词语开刀。词语,是人类的抽象总结,是符号形式的(比如中文、英文、拉丁文等等),所以需要把他们转换成数值形式,或者说——嵌入到一个数学空间里,这种嵌入方式,就叫词嵌入(word embedding),而 Word2vec,就是词嵌入( word embedding) 的一种。简单点来说就是把一个词语转换成对应向量的表达形式,来让机器读取数据。
Word2Vec模型实际上分为了两个部分,第一部分为建立模型,第二部分是通过模型获取嵌入词向量。Word2Vec的整个建模过程实际上与自编码器(auto-encoder)的思想很相似,即先基于训练数据构建一个神经网络,当这个模型训练好以后,我们并不会用这个训练好的模型处理新的任务,我们真正需要的是这个模型通过训练数据所学得的参数,例如隐层的权重矩阵——后面我们将会看到这些权重在Word2Vec中实际上就是我们试图去学习的“word vectors”。

2. NLP词的表示方法类型

1、词的独热表示one-hot
用词向量来表示词并不是word2vec的首创,在很久之前就出现了。最早的词向量是很冗长的,它使用是词向量维度大小为整个词汇表的大小,对于每个具体的词汇表中的词,将对应的位置置为1。比如我们有5个词组成的词汇表,词”Queen”在词汇表中的序号为2, 那么它的词向量就是(0,1,0,0,0)。同样的道理,词”Woman”是序号3,词向量就是(0,0,0,1,0)。这种词向量的编码方式我们一般叫做one hot representation.

One hot representation用来表示词向量非常简单,但是却有很多问题。1、任意两个词之间都是孤立的,根本无法表示出在语义层面上词语词之间的相关信息,而这一点是致命的。2、我们的词汇表一般都非常大,比如达到百万级别,这样每个词都用百万维的向量来表示简直是内存的灾难。能不能把词向量的维度变小呢?

2、词的分布式表示 distributed representation
Dristributed representation可以解决One hot representation的问题,它的思路是通过训练,将每个词都映射到一个较短的词向量上来。所有的这些词向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系。这个较短的词向量维度是多大呢?这个一般需要我们在训练时自己来指定。
词的分布式表示主要可以分为三类:基于矩阵的分布表示、基于聚类的分布表示和基于神经网络的分布表示。

3. 神经网络语言模型

a) Neural Network Language Model ,NNLM
b) Log-Bilinear Language Model, LBL
c) Recurrent Neural Network based Language Model,RNNLM
d) Collobert 和 Weston 在2008 年提出的 C&W 模型
e) Mikolov 等人提出了 CBOW( Continuous Bagof-Words)和 Skip-gram 模型
如今我们主要用到的是CBOW和Skip-gram模型。
1. CBOW
CBOW(Continuous Bag-of-Word Model)又称连续词袋模型,是一个三层神经网络。如下图所示,该模型的特点是输入已知上下文,输出对当前单词的预测。
达观杯文本智能处理(3)_第1张图片
其中,w表示语料库C中任意一个词。
首先输入的是one-hot向量,第一层是一个全连接层,然后没有激活函数,输出层是一个softmax层,输出一个概率分布,表示词典中每个词出现的概率。
我们并不关心输出的内容,训练完成后第一个全连接层的参数就是word embedding。
2. Skip-gram
Skip-gram只是逆转了CBOW的因果关系而已,即已知当前词语,预测上下文。

达观杯文本智能处理(3)_第2张图片
我们会发现Word2Vec模型是一个超级大的神经网络(权重矩阵规模非常大)。

举个例子,我们拥有10000个单词的词汇表,我们如果想嵌入300维的词向量,那么我们的输入-隐层权重矩阵和隐层-输出层的权重矩阵都会有 10000 x 300 = 300万个权重,在如此庞大的神经网络中进行梯度下降是相当慢的。更糟糕的是,你需要大量的训练数据来调整这些权重并且避免过拟合。百万数量级的权重矩阵和亿万数量级的训练样本意味着训练这个模型将会是个灾难。

下面主要介绍两种方法优化训练过程

1.负采样(negative sampling)
负采样(negative sampling)解决了这个问题,它是用来提高训练速度并且改善所得到词向量的质量的一种方法。不同于原本每个训练样本更新所有的权重,负采样每次让一个训练样本仅仅更新一小部分的权重,这样就会降低梯度下降过程中的计算量。至于具体的细节我在这里就不在介绍了
2.层序softmax也是解决这个问题的一种方法。基于Hierarchical Softmax的。

Hierarchical softmax

word2vec对这个模型做了改进,首先,对于从输入层到隐藏层的映射,没有采取神经网络的线性变换加激活函数的方法,而是采用简单的对所有输入词向量求和并取平均的方法。

第二个改进就是从隐藏层到输出的softmax层这里的计算量个改进。为了避免要计算所有词的softmax概率,word2vec采样了霍夫曼树来代替从隐藏层到输出softmax层的映射。

和之前的神经网络语言模型相比,我们的霍夫曼树的所有内部节点就类似之前神经网络隐藏层的神经元,其中,根节点的词向量对应我们的投影后的词向量,而所有叶子节点就类似于之前神经网络softmax输出层的神经元,叶子节点的个数就是词汇表的大小。在霍夫曼树中,隐藏层到输出层的softmax映射不是一下子完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为”Hierarchical Softmax”。

基于Hierarchical Softmax的模型梯度计算
基于Hierarchical Softmax的CBOW模型
基于Hierarchical Softmax的Skip-Gram模型
使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率。

Negative Sampling

Negative Sampling就是这么一种求解word2vec模型的方法,它摒弃了霍夫曼树,采用了Negative Sampling(负采样)的方法来求解。

基于Negative Sampling的模型梯度计算
Negative Sampling负采样方法
基于Negative Sampling的CBOW模型
基于Negative Sampling的Skip-Gram模型## gensim.models.Word2Vec需要注意的参数有:

sentences: 我们要分析的语料,可以是一个列表,或者从文件中遍历读出。后面我们会有从文件读出的例子。
size: 词向量的维度,默认值是100。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度。

window:即词向量上下文最大距离,这个参数在我们的算法原理篇中标记为c,window越大,则和某一词较远的词也会产生上下文关系。默认值为5。在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。对于一般的语料这个值推荐在[5,10]之间。

sg: 即我们的word2vec两个模型的选择了。如果是0, 则是CBOW模型,是1则是Skip-Gram模型,默认是0即CBOW模型。

hs: 即我们的word2vec两个解法的选择了,如果是0, 则是Negative Sampling,是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax。默认是0即Negative Sampling。

negative:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间。这个参数在我们的算法原理篇中标记为neg。

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一起调参,来选择合适的三个值。
代码实现:

'''
将原始数据的word特征数字化为doc2vec特征,并将结果保存到本地

article特征可做类似处理

'''
import pandas as pd
import numpy as np
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
import time
import pickle

t_start = time.time()

"""=====================================================================================================================
0 辅助函数 
"""

def sentence2list(sentence):
    s_list = sentence.strip().split() #strip()去掉首尾空格,split()将字符串以空格切分成列表
    return s_list

"""=====================================================================================================================
1 加载原始数据
"""
df_train=pd.read_csv('train_set.csv')
df_test=pd.read_csv('test_set.csv')

df_train.drop(columns='article', inplace=True)
df_test.drop(columns='article', inplace=True)

# 按行拼接df_train和df_test
df_all = pd.concat(objs=[df_train, df_test], axis=0, sort=True)

# 获取train文件中的特征class
y_train = (df_train['class'] - 1).values

df_all['word_list'] = df_all['word_seg'].apply(sentence2list)
texts = df_all['word_list'].tolist()

"""=====================================================================================================================
2 特征工程
"""
print('2 特征工程')
# 将原始数据数字化为doc2vec

documents = [TaggedDocument(doc, [i]) for i, doc in enumerate(texts)]
model = Doc2Vec(documents, size=200, window=5, min_count=3, workers=4, iter=25)
docvecs = model.docvecs

x_train = []
for i in range(0, 102277):
    x_train.append(docvecs[i])
x_train = np.array(x_train)

x_test = []
for j in range(102277, 204554):
    x_test.append(docvecs[j])
x_test = np.array(x_test)

"""=====================================================================================================================
3 保存至本地
"""
print('3 保存特征')
data = (x_train, y_train, x_test)

with open('doc2vec_word.pkl', 'wb') as f:
	pickle.dump(data,f) 

t_end = time.time()
print("共耗时:{}min".format((t_end-t_start)/60))

Gensim是一款用于处理NLP的python包,用于从原始的非结构化的文本中,无监督地学习到文本隐层的主题向量表达。

它支持包括TF-IDF,LSA,LDA,和word2vec在内的多种主题模型算法,
支持流式训练,并提供了诸如相似度计算,信息检索等一些常用任务的API接口

使用gensim做Word2vec时,只需调用gensim.models.Word2Vec()函数即可,这里主要介绍一些模型内部的参数,参考link

参考:

https://www.jianshu.com/p/da235893e4a5
https://blog.csdn.net/yu5064/article/details/79601683
https://blog.csdn.net/qq_39446239/article/details/89069343
https://lingmoumou.github.io/p/2019/04/09/40163d71/#more

你可能感兴趣的:(达观杯文本智能处理)