我挺喜欢机器学习这个方向,但这方面的经历实在不多:读研时上过《机器学习》的课,一塌糊涂,后来毕设所谓的研究中用过聚类算法;工作后仅用过朴素贝叶斯算法;再后来就是自己偶尔看过几页书了。所以本篇可能连术语也不太准确,但大致思想应该不差。
深度学习有多火不用再说了,而它能火的一大原因可能要归功于Embedding,也就是所谓的word2vec/w2v。
word2vec的特点
word2vec最重要的一点是,用低维向量表达(编码)了相似关系。
以前的one-hot编码(叫“独热编码”)是没有相似关系的,比如词汇表有1万个词,用one-hot编码时每个词的编码就是这样:
我--->[1,0,0,0,...,0]的--->[0,1,0,0,...,0]了--->[0,0,1,0,...,0]...哈--->[0,0,0,0,....1]
这种情况下有多种问题:每两个词之间的距离都相同,所以也就无所谓哪两个是相似的;另外就是词向量维度太高,这意味着模型节点太多,肯定不利于算法快速收敛;最后,向量中几乎全是0,深度学习训练时有可能梯度消失问题很严重。
word2vec恰好能解决上面的问题:“机器学习”的向量和“深度学习”的向量比较相近(相似),但和“肯德基”就相距远得很多;维度一般几百(这个不太确定,只是见youtube的一篇论文中embedding是256维,“词汇表”大小是100百,当然youtube的所谓词汇表是视频);word2vec是“稠密”的向量,也就是其中为0的值很少(很难出现恰好为0浮点数)。另外它还有一个多少有点惊人的特点就是向量间能进行加减运算,比如,w2v(“国王”) - w2v(“男人”) + w2v(“女人”) = w2v(“女王”),这和one-hot相比简直先进太多了。
深度学习
有监督学习的三大要素是“模型”,“损失函数”和“训练算法”,所谓训练就是用训练算法在模型空间里找到使损失函数最小化(最大似然相似是找最大)的一个模型。深度学习也是有监督学习,所以它也要有这三要素。
深度学习/神经网络的模型都是这个样子的:
图1 神经网络最左侧的浅黄色的节点是“输入层”,中间两层浅灰度色的叫“隐层”,最右侧的红色节点是“输出层”,每两层之间各个节点之间都有连线,这好像是叫全连接。除输入层外的各层节点都接收多个输入;各层的每个节点都输出一个值,输入层就输出原始的样例的值;每条连线都有一个权重值w,连线上前一层的节点乘以w后的值被累加到连线下一层节点的输入上;前一层各节点都乘以权重累加到下一层各节点后,这两层计算结束,下一层以累加后的值作为输出值;一层一层计算直到输出层输出一个向量,其每维对应各个红色节点的输出。为了得到非线性输出,隐层节点在输出值之前要经过一个非线性函数,现在常用的是ReLU或sigmoid。神经网络能表示很大的模型空间,训练模型就是要在其中找到我们想要的模型。
常用的损失函数有均方误差,交叉熵等;神经网络的训练算法是反射传播,就是先将样例一个一个地喂给网络的输入层,经过上面的运算流程最后在输出层得到一个向量,损失函数再以这个向量和样例的标签值为参数计算得到误差,将这个误差再向后一层一层地求导并更新各层权重。这样不断地训练直到各层权重达到一个稳定值(一个局部最优值),这些权重加上模型各层节点数就能确定网络模型的全部结构了。
我写的这些可能本来就懂的能看懂,不懂的还是不懂,毕竟我也是门外汉,可能讲不明白。
把神经网络看成矩阵运算对理解w2v非常有帮助,比如假设上图中第一层和第二层各有m和n个节点,它们之间的权重就可以用一个m*n矩阵W12(m, n)表示:
w(1, 1), w(1, 2), ..., w(1, n)
w(2, 1), w(2, 2), ..., w(2, n)
...
w(m, 1), w(m, 2), ..., w(m, n)
其中w(i,j)表示第一层的第i个节点和第二层第j个节点连线上的权重。假设第三,第四层分别有n和k个节点,那么二三层和三四层之间的矩阵可以表示为W23(n, n)和W34(n, k)。再假设有一个m维的输入向量X,那输出向量Y可以表示为:
Y= X * W12(m, n) * W23(n, n) * W34(n, k)
其中*表示矩阵乘法。这个流程叫“前向传播”。
w2v在深度学习怎么用?
从上面可以看出,深度学习的前向传播本质就是矩阵运行,而w2v能把词或其它东西表示成一个稠密相似向量,这对深度学习太有帮助了。
我了解的w2v在深度学习中有两种用法:
a) 向量叠加。比如用户喜欢多个文章或视频,那么就可以把它们相应的向量加到一起作为神经网络的输入。这样做是有意义的,因为w2v的向量可以加减运算。这太神奇了。
b)向量串连。比如youtube的论文中将看过和搜索过的视频的向量串连到一起输入给网络,这好像说不出什么意义但觉得也没有问题。
w2v的原理
w2v最初是用于训练词向量,后来才扩展到item2vec。
假设有一个由词w组成的长度为T的句子:w(1), w(2), ..., w(T)。w2v的想法很自然,就是位置越是接近的词越有可能是相似/相近的。这个想法要先形式化才能进行运算。要表示可能性当然是用概率。假设w(i)和w(j)位置很近,那我们应该将概率p( w(j)/w(i) )最大化,也就是看到w(i)后非常有可能看到w(j)---毕竟它们两个真实地出在在了样例中,我们当然有理由将这个概率最大化。将很多对这样的“词对”放到一起,就成了要最大化这个式子:
这也就是将所有词对的概率乘积最大化,这个思想就叫“最大似然相似”。实际中要对上式求对数,这样将相乘转换为相加,方便运算:
将上述思路再具体化一下就是,对于一个词w(t),在它前后各取c个词作为要预测的词,那么上面的求和公式就变成这样:
(1)
有了上面的基础,理解这个式子应该不成问题。这个公式就对应所谓的"skip-gram"模型,也就是根据一个”中心词”去推断它上下文中其它的词。
接下来是w2v中最精彩的部分!
上面只是公式没法运算,因为还不知道怎么去表示这个概率,所以也就什么也干不了。
a) 首先,w2v的目的是将词用向量表示,所以不妨先以假设词w(i)对应一个向量v(i)。
b) w2v的目标是让相近的词有相近的向量,对应到概率就是p(w(j)/w(i))较大,对应到向量v(i)和v(j)就是它们的点积越大。
c) 最后,如果概率还有点印象的话应该还记得概率之和为1。
综合上面的思路,我当初写下了如下的公式:
我差一点就写对了。这个公式有问题就是可能导致概率为负,对于训练可能也不友好。w2v论文中用的是这样的:
(2)
下标为I和O的向量分别是输入向量和输出向量,求各中的“W”表示词汇表大小(也就是训练集中出现的词的数量),exp表示自然指数运算。相比我写的最大不同是多了自然指数运算。这个公式在算法里叫“softmax”。关于输入向量和输出向量是什么一会就能明白。
w2v最为神奇的地方可能就是式子(2)可以转化为一个神经网络:
图中,输入是V维的每个词的one-hot编码向量,隐层是N个节点,输出是V维的要预测的词的one-hot编译向量;输入层和隐层之间是V*N的矩阵M(V,N),隐层和输出层之间是N*V的矩阵M(N, V)。
重点来了。
因为输入是one-hot编码的V维向量,所以这个向量与M(V, N)相乘后就只留下M(V,N)中的一行(如果是M乘以V就成了M中的一列),不妨把这一行记为R(1, V)。这个过程对应到网络结构图时,就是只保留了V维向量中为1的节点到隐层各节点上的权重。R(1, V)为1*N向量,它再与矩阵M(N, V)的每一列分别点积相乘,得到1*V的向量O(1,V)。不难想像,R(1, V)就是对应公式(2)中的输入向量,M(N, V)的每一列就是对应公式(2)的输出向量。根据公式2,对词汇表中的每个词分别计算概率,概率值最大的就是训练要输出的词。这个词如果和样例中的词一致,那损失函数输出0,否则就非0。整个训练过程就是根据公式(1)和(2)不断地计算预测值,再计算损失函数,再用反射传播更新连线上的权重,直到损失达到一定值或满足其它设定的结束条件。
最终训练结束时将得到两个矩阵,输入矩阵W(V,N)和输出矩阵W(N,V),w2v的论文中就以输入矩阵W(V,N)中的行(或列)向量作为最终结果,用于embedding什么的。知乎上有人讨论说用输出矩阵W(N,V)也可以。从网络结构不难看出,它是左右对称的,训练过程也可以说是对称更新的,所以用输出矩阵应该也可以。
以上就是w2v的原理。除此之外,原始论文还考虑负采样,高频词和短语的问题,不一一介绍了。
文中有从网络中拿的图片,侵权必删。
网友评论