原因
无论是CBOW模型还是Skip-gram模型, 输出层都是预测出一个单词. 由于语料库中词语的数量巨大, 因此直接使用softmax输出预测结果是几乎不可行的. 所以需要使用Hierarchical Softmax方法对输出层结构进行优化.
霍夫曼树
Hierarchical Softmax结构使用霍夫曼树来进行优化, 有必要了解霍夫曼树的原理.
霍夫曼树的构建过程如下:
输入: n个结点(这里每个结点代表一个单词), 对应的权值向量为(w1,w2,⋯,wn)
过程
将所有的n个结点每一个看成一棵树, 共有n棵树, 每棵树的结点都只有一个. 组成森林
在森林中选取根节点权值最小的两棵树进行合并, 得到一棵新的树. 原来的两棵树分别作为新书的左右子树, 新树的根节点权重为左右子树的根节点权重之和. 然后将原来的两棵树删除
霍夫曼树的特点: 权重高的叶子结点靠近根节点, 编码值较短; 权重低的远离根节点, 编码值较长. 因此整体的编码效率会提高.
霍夫曼树应用于word2vec
将霍夫曼树应用在投影层(Projection Layer)到输出层之间, 用霍夫曼树的结构代替了softmax层的映射. 避免了计算字典中所有单词的softmax概率, 在每个结点只需要判断左右两个行进方向, 沿着树一直走到样本单词对应的叶子结点, 整体结构示例如下:
这种霍夫曼树形状的神经网络结构为:
非叶子结点相当于一个神经元, 有自身的参数向量, 长度与设定的词嵌入向量的长度相同. 二分类决策输出0
或1
, 0
表示选择左子树, 1
表示选择右子树.
每个叶子结点代表语料库中的一个单词, 因此叶子结点的数量就是语料库词汇表中单词的数量.
每个结点(除了根节点, 包括非叶子结点和叶子结点)都可以用0
和1
唯一地编码
投影层到输出层不是一下完成的, 而是沿着树一步步完成的, 结果的路径对应着一个结点的编码序列
Hierarchical Softmax模型的梯度计算
引入符号
对于每个非叶子结点, 判断下一步的行进方向. 由于每个非叶子结点都是一个神经元, 因此每个神经元都会进行感知机+sigmoid激活函数的操作, 即:
用逻辑回归常用的形式, 写在一起有:
求最大似然, 对每个样本, 带入偏导数表达式求得函数在该参数上的增长梯度, 使用梯度上升法更新参数. 这里有两个参数:
关于Hierarchical Softmax结构还有几点需要注意的地方:
作为一个层级形式的神经网络结构, 与平常使用的结构(DNN)不同的地方是, 每一层神经元的输出结果都是一个标量, 用作选择下一步前进的方法, 而不是产生向量继续输入到这个结点的子树中去
基于Hierarchical Softmax的CBOW模型
CBOW模型结合Hierarchical Softmax中需要注意的部分.
整体总结如下:
过程
随机初始化所有词的词向量, 所有非叶子结点的参数向量
基于Hierarchical Softmax的Skip-Gram模型
因此整个过程总结如下:
过程:
随机初始化所有词的词向量, 所有非叶子结点的参数向量
参考
pw: 从根节点出发到达词w对应的叶子结点的路径
lw: 路径pw中包含的结点个数, 也即是层数
p1w,p2w,⋯,plww: 路径pw中包含的结点
d2w,⋯,dlww: djw∈{0,1}, j=1,2,⋯,lw, djw表示路径pw中第j个结点对应的编码(根节点无编码)
θ1w,θ2w,⋯,θlw−1w: 路径pw中对应的非叶子结点的参数向量
P(+)=σ(xwTθ)=1+e−xwTθ1
因此对应一个(w, Context(w))样本, 对应的条件概率(似然函数)为:
p(w∣Context(w))=j=2∏lwp(djw∣xw,θj−1w)
从根节点到叶子结点经历了lw−1个结点. 而其中的每一项都是一个逻辑回归:
p(djw∣xw,θj−1w)={σ(xwTθj−1w),1−σ(xwTθj−1w),djw=0djw=1
p(djw∣xw,θj−1w)=[σ(xwTθj−1w)]1−djw[1−σ(xwTθj−1w)]djw
L=log∏j=2lwP(djw∣xw,θj−1w)=j=2∑lw((1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)])
每个结点的参数向量θj−1w, 求得偏导数为:
∂θj−1w∂L=(1−djw)σ(xwTθj−1w)(σ(xwTθj−1w)(1−σ(xwTθj−1w)xw−djw1−σ(xwTθj−1w)(σ(xwTθj−1w)(1−σ(xwTθj−1w)xw=(1−djw)(1−σ(xwTθj−1w))xw−djwσ(xwTθj−1w)xw=(1−djw−σ(xwTθj−1w))xw
单词w对应的嵌入参数向量xw, 这就是我们最终需要的单词对应的词向量. 求得到偏导数为
∂xw∂L=j=2∑lw(1−djw−σ(xwTθj−1w))θj−1w
因此每个结点的输入也就不是上层的结果, 而都是输入层单词w对应的嵌入参数向量xw, 整个路径中的所有神经元的输入都是这个向量
定义上下文的单侧窗口大小为c, 对于每个中心词, 其前面的c个词和后面的c个词都作为CBOW模型的输入.
从输入层到隐藏层的映射为对中心词w周围的2c个词的词向量求和并平均, 也可以只求和不平均, 并没有什么区别, 因此在最后梯度上升时的学习率与这里求平均可以结合在一起. 因此得到:
xw=i=1∑2cxi
然后通过梯度上升法来更新θj−1w和xw, 这里的xw向量是2c个单词之和. 更新形式为:
θj−1w=θj−1w+η(1−djw−σ(xwTθj−1w))xw
xw=xw+ηj=2∑lw(1−djw−σ(xwTθj−1w))θj−1w(i=1,2..,2c)
输入: 训练语料样本, 上下文单侧窗口长度c, 学习率η
输出: 所有词w的词向量xw; 非叶子结点参数θ
对于训练集中的每一个样本(w, Context(w)), 使用梯度上升法进行求解. 这里的Context(w)不是一个单词, 而是中心词w附近的2c个上下文单词
xw=i=1∑2cxi
for j=2 to lw, 计算:
f=σ(xwTθj−1w)
g=(1−djw−f)η
e=e+gθj−1w
θj−1w=θj−1w+gxw
对于Context(w)中包含的每一个词对应的词向量xi,i=1,2,⋯,2c进行相同的更新:
xi=xi+e
Skip-gram只是逆转了CBOW的因果关系而已, 对于CBOW, 我们对p(w∣Context(w))进行最大似然, 对于Skip-Gram就要对p(Context(w)∣w)进行最大似然了:
p(Context(w)∣w)=u∈Context(w)∏p(u∣w)
即求中心词w和上下中每一个词u的条件概率. 这点与CBOW不同. CBOW是将上下文中所有的词加和起来与中心词产生条件概率, 相当于是两个词之间的关系. 而Skip-gram中是中心词与上下文中每一个词的关系, 因此计算要多一层对上下文词的循环.
另外由于CBOW的条件概率为p(w∣Context(w)), 是上下文词预测中心词, 所以每一轮梯度上升中更新的是上下文中所有词的词向量. Skip-gram的条件概率为p(Context(w)∣w), 是中心词预测上下文词, 那么对于上下午中的所有词, 更新的都是中心词w对应的词向量xw. 这样在迭代的过程可能出现不均衡的现象.
从期望条件概率p(u∣w)的角度来讲, 上下文是相互的, 因此对于u和w两个词来说, 相互的条件概率是相同的, 因此就可以转换为对条件概率p(w∣u)期望最大. 这样我们就可以跟CBOW模型一样, 在一个中心词样本中, 对所有上下文词对应的向量进行更新了. 区别只在于多了一个对于上下文词的循环层.
输入: 训练语料样本, 上下文单侧窗口长度c, 学习率η
输出: 所有词w的词向量xw; 非叶子结点参数θ
对于训练集中的每一个样本(w, Context(w)), 使用梯度上升法进行求解. 这里的Context(w)不是一个单词, 而是中心词w附近的2c个上下文单词
for i=1 to 2c, 即对上下文中的每个词:
for j=2 to lw, 计算:
f=σ(xwTθj−1w)
g=(1−djw−f)η
e=e+gθj−1w
θj−1w=θj−1w+gxw
xi=xi+e