自然语言处理从小白到大白系列(2)word Embedding从one-hot到word2vec

我们知道,对于我们的计算机来说,没有办法像人一样理解自然语言,在人工智能领域,这还有很长一段路要走,就算要直接处理自然语言,都很困难。因此,人们想办法把自然语言用数字的方式表示,便于计算和分析,这就是为什么要做词嵌入:word embedding。本文将从以下的方面讲述word embedding:

  • one-hot
  • 词的分布式表示
  • word2vec
  • glove
  • fast-text
  • word2vec 代码分析

1. one-hot encoding

对于one-hot,也称独热向量编码,是一种十分常用的类别处理手段,当特征是离散的,无序的,就可以通过one hot 进行特征数字化,比如一个特征有高、中、低三个值,通过独热编码,就可以分别编码为001,010,100。
one hot 可以通过如下方式在Python中方便地实现。

from sklearn import processing

enc = preprocessing.OneHotEncoder()  
enc.fit([[0,0,3],[1,1,0],[0,2,1],[1,0,2]])  #这里一共有4个数据,3种特征
 
array = enc.transform([[0,1,3]]).toarray()  #这里使用一个新的数据来测试
   
print (array)   # [[ 1  0  0  1  0  0  0  0  1]]

有同学可能会纳闷,我们为啥不直接对特征的各个值编码1,2,3,4呢,这样岂不更方便?这是因为我们如果这样编码,就引入了一定的数量大小关系,而原来的特征值之间是并列的,可能是国别,可能是性别,这些特征值之间没有大小的关系;另外,通过one hot编码,能够保证各个特征之间的空间距离也是合理的,如采用欧氏距离,各个特征值之间就是等距的。
然后我们如果通过one hot编码自然语言,会产生什么样的效果呢?假设词表有50000的大小,那么对于每一个词,我们都应该开一个50000维度的向量,然后其中有一个维度的值为1,其余的都是0。我们可能已经发现了其中的缺点,

  1. 这个词向量是十分稀疏的,浪费了很大的存储空间,
  2. 我们不能发现各个词之间的相互关系,因为每个词的向量都是正交的,独立的。
    因此我们需要一种更好的表示方法:分布式表示

2. 分布式表示

词的分布式表示这个名字(distributed representation)就是相对于one hot 表示而来的,可以理解为,onehot表示把所有的词都集中在了一个维度上,而分布式表示,就是一个词在各个维度上都分布有,分散了某种风险,增加了某些信息量。
分布式表示有什么好处呢,我想下面这个图大家应该都见过,简单来说就是可以表示出两个词之间的空间距离远近五个词在两个向量空间中的位置
当然,对于分布式表示来说,每个词的向量大大缩短(相比one hot编码),可以通过计算两个词之间的空间距离,这个距离可能能表征词义,语法上的相似性。
事实证明词向量的好坏也决定着下游任务的上限。那么既然这种分布式表示有如此多的好处,那么怎样才能获得好的分布式词向量呢?在相当长的一段时间,或者说目前仍然用得十分广泛的一种方法,就是word2vec。

3. word2vec

word2vec网上的资料多如牛毛,我这里也没有必要把他们的抄一遍过来,但是我在网上看到的最好的资料,应该是《word2vec中的数学原理详解》那份资料:
在这里插入图片描述
在这里插入图片描述
光看目录就知道都是干货了,如果有需要的,我上传到GitHub上,大家可以自取:https://github.com/wujie0001/NLP-learning
,github上会持续更新关于机器学习,NLP等资料,大家可以小小star一下。
这里把word2vec讲一下吧,看了我这个大致的梗概,有个大体的思路,去看上面的资料,可能会更容易。word2vec里面构建词向量的基本假设就是:相似的词,经常会同时出现。(也叫共现),基于这样一个思想,word2vec可以建立模型来实现它。
在这里插入图片描述
如上图所示,一种是CBOW模型,一种是Skip-gram模型,两个模型的区别是前者通过周边的词对中心词进行预测,更具体的说是将周边的词向量进行加和,得到了中间的词;而skip gram是通过中心词,预测周围的词。一般来说,skip gram的效果似乎还比CBOW的效果好一些。以下讲几个需要注意的细节部分:

  • hierarchical softmax
  • negative sampling

1. hierarchical softmax

说到这个层次化的softmax,不得不提的就是Huffman树,那为啥要这个Huffman树呢,难道是吃饱了撑的吗?其实不是的,我们假设一下,如果对于一个网络,比如刚才那个CBOW的网络,输出的层的维度应该是多少呢?其实不难想到,因为我们是一个多分类,假设词表是5w维,那么输出层的节点应该是5w个才对,一个网络的输出层这么多节点,其实还是很不麻烦的一个事情,我们仍然是觉得太多的节点,绝大部分是0,想想有没有压缩一下的办法。那么这里的Huffman树就是一种压缩的方式。
Huffman树是按节点的权重来构建一颗二叉树的,具体来说就是按各个词的词频来构建一个二叉树,如果是经常出现的词,如THE , MY, 等,索引的路径就短,是一个生僻词的话,索引的路径就长。举个例子,如下图:
在这里插入图片描述
对于一个输出的来说,就是多个二分类的任务了,希望最大化正确路径的概率,即把所有的路径上的节点的概率进行连乘,以这个作为目标函数,这个手法是机器学习里面十分常见的。
这里要注意一下,在Huffman树中,我们对除根节点以外的每个非叶子节点都有一个向量 θ \theta θ,这个向量就是作为参数与词向量和进行内积然后二分类的,也就是每个二分类上面的参数。注意要区分的是各个词向量v(w) 和这里的 θ \theta θ,是不同的向量,最后是两个向量都需要训练的。而训练的方法就是梯度上升的方法,即通过固定一个,更新另一个,然后循环这个过程。
hierarchical softmax需要注意的大概就这些内容,细节的地方可以看上面提供的资料,更为详尽。

2. negative sampling

现在来讲讲负例采样的算法,大家可能都知道它是为了提升效率的一种方法,但是究竟如何提升的效率,可能并没有真正地弄懂。
为什么要有负例采样?难道我们的hierarchical softmax还不够快吗,的确是这样的,我们发现hierarchical是一个为了输出层节点不要太多的一种优化,一种妥协,但是我们要想办法另辟蹊径,所以负例采样就出现了,什么是负例采样算法,就是字面意思,随机地采样负样本,不必要每次把所有的负样本都拿来训练。那么每个样本进去都是一个二分类,我们期望是正样本输入的时候,输出正类的概率越大越好;负样本输入的时候,输出正类的概率越小越好,即(1-p)的概率越大越好。如下:
在这里插入图片描述
那么下一个问题是,究竟如何采样?
想象一下,词表中有常用词,也有生僻词,直观地,常用词理应更容易被采样到,而生僻词被采样的概率应该更小才好。因此我们应用词频作为权重进行采样,如何实现的呢?
其实就是把所有词(N个)的词频映射到0-1区间内的一段长度,然后再把0-1的区间等距切分为M段,当然这里的M是远远大于N的。
在这里插入图片描述
我们要采样的时候,就可以产生一系列的[1,M-1]随机数,然后找找映射到哪个词上,那个词就是被采样到的负样本(刚好采到正样本就直接跳过去)。
好了,word2vec其实说难也不难,归根到底还是要沉下心来,慢慢理清楚他的细节。再次墙裂推荐上面的资料,写得真好。下面讲glove。

4. glove

glove词向量相比于word2vec来说,区别是glove词向量是利用的全局的共现信息,而word2vec被诟病的就是利用的信息过于局部,那glove模型是怎么一回事呢?我们可以快速地来看看。
模型的代价函数是这样的:
在这里插入图片描述
这里的 v i T v_i^T viT v j v_j vj是要训练的词向量,而 X i , j X_{i,j} Xi,j是共现矩阵中的词频, b i , b j b_i,b_j

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值