From 38fb7d1217765763fec12f87fe6577917ba08291 Mon Sep 17 00:00:00 2001 From: weixing02 Date: Thu, 10 May 2018 15:14:25 +0800 Subject: [PATCH] Add some theory for hsigmoid documentation --- .gitignore | 1 + hsigmoid/README.md | 52 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9492cff0..e6438c7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store *.pyc .*~ +.vscode/ diff --git a/hsigmoid/README.md b/hsigmoid/README.md index 619fc190..0c107b3f 100644 --- a/hsigmoid/README.md +++ b/hsigmoid/README.md @@ -4,17 +4,63 @@ # Hsigmoid加速词向量训练 ## 背景介绍 -在自然语言处理领域中,传统做法通常使用one-hot向量来表示词,比如词典为['我', '你', '喜欢'],可以用[1,0,0]、[0,1,0]和[0,0,1]这三个向量分别表示'我'、'你'和'喜欢'。这种表示方式比较简洁,但是当词表很大时,容易产生维度爆炸问题;而且任意两个词的向量是正交的,向量包含的信息有限。为了避免或减轻one-hot表示的缺点,目前通常使用词向量来取代one-hot表示,词向量也就是word embedding,即使用一个低维稠密的实向量取代高维稀疏的one-hot向量。训练词向量的方法有很多种,神经网络模型是其中之一,包括CBOW、Skip-gram等,这些模型本质上都是一个分类模型,当词表较大即类别较多时,传统的softmax将非常消耗时间。PaddlePaddle提供了Hsigmoid Layer、NCE Layer,来加速模型的训练过程。本文主要介绍如何使用Hsigmoid Layer来加速训练,词向量相关内容请查阅PaddlePaddle Book中的[词向量章节](https://github.com/PaddlePaddle/book/tree/develop/04.word2vec)。 +在自然语言处理领域中,传统做法通常使用one-hot向量来表示词,比如词典为['我', '你', '喜欢'],可以用[1,0,0]、[0,1,0]和[0,0,1]这三个向量分别表示'我'、'你'和'喜欢'。这种表示方式比较简洁,但是当词表很大时,容易产生维度爆炸问题;而且任意两个词的向量是正交的,向量包含的信息有限。为了避免或减轻one-hot表示的缺点,目前通常使用词向量来取代one-hot表示,词向量也就是word embedding,即使用一个低维稠密的实向量取代高维稀疏的one-hot向量。训练词向量的方法有很多种,神经网络模型是其中之一,包括CBOW、Skip-gram等,这些模型本质上都是一个分类模型,当词表较大即类别较多时,传统的softmax将非常消耗时间,因为不仅需要计算每个词汇的softmax概率,而且还需要进行十分耗时的归一化计算。PaddlePaddle提供了Hsigmoid Layer、NCE Layer,来加速模型的训练过程。本文主要介绍如何使用Hsigmoid Layer来加速训练,词向量相关内容请查阅PaddlePaddle Book中的[词向量章节](https://github.com/PaddlePaddle/book/tree/develop/04.word2vec)。 ## Hsigmoid Layer -Hsigmoid Layer引用自论文\[[1](#参考文献)\],Hsigmoid指Hierarchical-sigmoid,原理是通过构建一个分类二叉树来降低计算复杂度,二叉树中每个叶子节点代表一个类别,每个非叶子节点代表一个二类别分类器。例如我们一共有4个类别分别是0、1、2、3,softmax会分别计算4个类别的得分,然后归一化得到概率。当类别数很多时,计算每个类别的概率非常耗时,Hsigmoid Layer会根据类别数构建一个平衡二叉树,如下: +Hsigmoid Layer引用自论文\[[1](#参考文献)\],Hsigmoid指Hierarchical-sigmoid,原理是通过构建一个分类二叉树来降低计算复杂度,二叉树中每个叶子节点代表一个类别,每个非叶子节点代表一个二类别分类器。假设我们一共有4个类别分别是0、1、2、3,softmax会分别计算4个类别的得分,然后归一化得到概率。当类别数很多时,计算每个类别的概率非常耗时,Hsigmoid Layer会根据类别数构建一个完全二叉树,利用该二叉树替代原来从隐藏层到输出softmax层的映射,如下图所示:


图1. (a)为平衡二叉树,(b)为根节点到类别1的路径

-二叉树中每个非叶子节点是一个二类别分类器(sigmoid),如果类别是0,则取左子节点继续分类判断,反之取右子节点,直至达到叶节点。按照这种方式,每个类别均对应一条路径,例如从root到类别1的路径编码为0、1。训练阶段我们按照真实类别对应的路径,依次计算对应分类器的损失,然后综合所有损失得到最终损失。预测阶段,模型会输出各个非叶节点分类器的概率,我们可以根据概率获取路径编码,然后遍历路径编码就可以得到最终预测类别。传统softmax的计算复杂度为N(N为词典大小),Hsigmoid可以将复杂度降至log(N),详细理论细节可参照论文\[[1](#参考文献)\]。 +在二叉树中,原先从隐藏层到输出层的映射变成了从根节点沿着路径直到对应词汇的叶子节点的计算,例如图(b)表示为从根节点root到类别1的路径,该路径共经历了两个分支,每个分支都是一次二分类计算。既然是二分类计算,我们可以分别用0和1表示“向左走”或“向右走”,那么从根节点root到类别1的编码路径就是```0、1```。我们在每一个非叶子节点上使用sigmoid来判别分类,以1表示正类,以0表示负类,那么每个节点的正类(向右走)分类概率可以表示为: + +$$P(+)=\sigma(x_w^T \theta)=\frac{1}{1+e^{-x_w^T \theta}}$$ + +其中$x_w$是当前节点的词向量,$\theta$是当前非叶子节点的模型参数。 + +既然分类为正类(向右走)的概率已经求得,那么分类为负类(向左走)的概率就为: + +$$P(-)=1-P(+)=1-\sigma(x_w^T \theta)=1-\frac{1}{1+e^{-x_w^T \theta}}$$ + +简而言之,$P(+)$和$P(-)$控制着当前节点向右走和向左走的概率,如果$P(+)$较大,则当前节点就有更大的可能向右走;反之,如果$P(-)$较大,则当前节点就有更大的可能向左走。走对于图(b)中的案例,如果要从根节点root出发找到类别1,那么我们会希望root节点的$P(-)$较大,并希望第二个节点的$P(+)$较大,将它们进行乘积运算得到: + +$$\prod_{i=1}^{2}P(i)=(1-\sigma(x_w^T \theta_{1}))(\sigma(x_w^T \theta_{2}))$$ + +上述公式其实是一个极大似然函数,容易看出极大似然函数与词向量$x_w$以及每个非叶子节点的参数$\theta_i$有关,我们希望通过最大化极大似然函数来不断更新每个词向量和每个模型参数。 + +有了极大似然函数,我们就可以进行梯度的计算,为了更准确地描述计算过程,首先定义一些相关符号: + +- $\omega$:表示词典中的一个词汇 +- $x_{\omega}$:表示输入的词向量 +- $l_{\omega}$:表示从根节点到目标词$\omega$的路径包含的节点数,也就是编码长度 +- $\theta_i^{\omega}$:表示某个词$\omega$对应的路径上的第i个节点的参数,其中$i=1,2,3,...,l_{\omega}-1$ +- $d_j^{\omega}\in{\{0, 1\}}$:表示某个词$\omega$对应的路径上第j个结点的编码,其中$i=2,3,4,...,l_{\omega}$ + +有了上述定义,根据词汇$\omega$在二叉树中的对应路径,可以得到极大似然函数: + +$$P(\omega|x_{\omega})=\prod_{j=2}^{l_{\omega}}p(d_j^{\omega}|x_{\omega}, \theta{_{j-1}^{\omega}})$$ + +其中 + +$$p(d_j^{\omega}|x_{\omega}, \theta_{j-1}^{\omega})=[\sigma(x_w^T \theta_{j-1}^\omega)]^{1-d_j^{\omega}} * [1-\sigma(x_w^T \theta_{j-1}^\omega))]^{d_j^{\omega}}$$ + +所以对于单个样本词汇$\omega$的对数似然函数$L$可以表示为: + +$$L=log \prod_{j=2}^{l_\omega}p(d_j^{\omega}|x_{\omega}, \theta_{j-1}^{\omega})=\prod_{j=2}^{l_\omega} (1-d_j^{\omega}) log [\sigma(x_w^T \theta_{j-1}^\omega)] + d_j^{\omega} log [1-\sigma(x_w^T \theta_{j-1}^\omega)]$$ + +得到单个样本词汇$\omega$的对数似然函数$L$之后,我们希望将其最大化,所以采用梯度上升的方式来更新参数,对参数$\theta_{j-1}^\omega$以及词向量$x_\omega$的梯度进行求解,可以分别得到: + +$$\frac{\partial L}{\partial \theta_{j-1}^{\omega}} +=(1-d_j^{\omega}-\sigma(x_w^T \theta_{j-1}^\omega))x_\omega$$ + +$$\frac{\partial L}{\partial x_\omega} +=(1-d_j^{\omega}-\sigma(x_w^T \theta_{j-1}^\omega))\theta_{j-1}^{\omega}$$ + +根据求解的梯度就可以对模型参数$\theta_{j-1}^\omega$以及词向量$x_\omega$进行迭代更新。 + +至此,Hsigmoid Layer的前向传播和反向传播梯度计算过程介绍完毕,传统softmax的计算复杂度为N(N为词典大小),而Hsigmoid可以将复杂度降至log(N),更详细的理论细节可参照论文\[[1](#参考文献)\]。 ## 数据准备 ### PTB数据 -- GitLab