<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>自然语言处理 on Zeqiang Fang | 方泽强</title><link>https://zeqiang.fun/categories/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/</link><description>Recent content in 自然语言处理 on Zeqiang Fang | 方泽强</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sat, 31 Oct 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://zeqiang.fun/categories/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/" rel="self" type="application/rss+xml"/><item><title>文本相似度 (Text Similarity)</title><link>https://zeqiang.fun/cn/2020/10/text-similarity/</link><pubDate>Sat, 31 Oct 2020 00:00:00 +0000</pubDate><guid>https://zeqiang.fun/cn/2020/10/text-similarity/</guid><description><![CDATA[
        <p>文本相似度是指衡量两个文本的相似程度，相似程度的评价有很多角度：单纯的字面相似度（例如：我和他 v.s. 我和她），语义的相似度（例如：爸爸 v.s. 父亲）和风格的相似度（例如：我喜欢你 v.s. 我好喜欢你耶）等等。</p>
<h2 id="文本表示角度">文本表示角度</h2>
<h3 id="统计模型">统计模型</h3>
<h4 id="文本切分">文本切分</h4>
<p>在中文和拉丁语系中，文本的直观表示就存在一定的差异，拉丁语系中词与词之间存在天然的分隔符，而中文则没有。</p>
<blockquote>
<p>I can eat glass, it doesn&rsquo;t hurt me.<br>
我能吞下玻璃而不伤身体。</p>
</blockquote>
<p>因此针对拉丁语系的文本切分相对中文容易许多。</p>
<ul>
<li><strong>N 元语法</strong></li>
</ul>
<p>N-gram (N 元语法) 是一种文本表示方法，指文中连续出现的 $n$ 个词语。N-gram 模型是基于 $n-1$ 阶马尔科夫链的一种概率语言模型，可以通过前 $n-1$ 个词对第 $n$ 个词进行预测。以 <code>南京市长江大桥</code> 为例，N-gram 的表示如下：</p>
<pre><code>一元语法（unigram）：南/京/市/长/江/大/桥
二元语法（bigram）：南京/京市/市长/长江/江大/大桥
三元语法（trigram）：南京市/京市长/市长江/长江大/江大桥
</code></pre>
<pre><code class="language-python">import re
from nltk.util import ngrams

s = '南京市长江大桥'
tokens = re.sub(r'\s', '', s)

list(ngrams(tokens, 1))
# [('南',), ('京',), ('市',), ('长',), ('江',), ('大',), ('桥',)]

list(ngrams(tokens, 2))
# [('南', '京'), ('京', '市'), ('市', '长'),
#  ('长', '江'), ('江', '大'), ('大', '桥')]

list(ngrams(tokens, 3, pad_left=True, pad_right=True, left_pad_symbol='&lt;s&gt;', right_pad_symbol='&lt;/s&gt;'))
# [('&lt;s&gt;', '&lt;s&gt;', '南'),
#  ('&lt;s&gt;', '南', '京'),
#  ('南', '京', '市'),
#  ('京', '市', '长'),
#  ('市', '长', '江'),
#  ('长', '江', '大'),
#  ('江', '大', '桥'),
#  ('大', '桥', '&lt;/s&gt;'),
#  ('桥', '&lt;/s&gt;', '&lt;/s&gt;')]
</code></pre>
<ul>
<li><strong>分词</strong></li>
</ul>
<p>分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。在英文的行文中，单词之间是以空格作为自然分界符的，而中文只是字、句和段能通过明显的分界符来简单划界，唯独词没有一个形式上的分界符，虽然英文也同样存在短语的划分问题，不过在词这一层上，中文比之英文要复杂得多、困难得多。</p>
<pre><code class="language-python">s = '南京市长江大桥'

# jieba
# https://github.com/fxsjy/jieba
import jieba

list(jieba.cut(s, cut_all=False))
# ['南京市', '长江大桥']

list(jieba.cut(s, cut_all=True))
# ['南京', '南京市', '京市', '市长', '长江', '长江大桥', '大桥']

list(jieba.cut_for_search(s))
# ['南京', '京市', '南京市', '长江', '大桥', '长江大桥']

# THULAC
# https://github.com/thunlp/THULAC-Python
import thulac

thulac_ins = thulac.thulac()

thulac_ins.cut(s)
# [['南京市', 'ns'], ['长江', 'ns'], ['大桥', 'n']]

# PKUSEG
# https://github.com/lancopku/PKUSeg-python
import pkuseg

seg = pkuseg.pkuseg(postag=True)

seg.cut(s)
# [('南京市', 'ns'), ('长江', 'ns'), ('大桥', 'n')]

# HanLP
# https://github.com/hankcs/HanLP
import hanlp

tokenizer = hanlp.load('LARGE_ALBERT_BASE')

tokenizer(s)
# ['南京市', '长江', '大桥']
</code></pre>
<h4 id="主题模型">主题模型</h4>
<p>除了对文本进行切分将切分后结果全部用于表示文本外，还可以用部分字词表示一篇文档。主题模型（Topic Model）在机器学习和自然语言处理等领域是用来在一系列文档中发现抽象主题的一种统计模型。</p>
<p><img src="/images/cn/2020-10-31-text-similarity/what-is-topic-model.png" alt="What is Topic Model"></p>
<p>直观来讲，如果一篇文章有一个中心思想，那么一些特定词语会更频繁的出现。比方说，如果一篇文章是在讲狗的，那“狗”和“骨头”等词出现的频率会高些。如果一篇文章是在讲猫的，那“猫”和“鱼”等词出现的频率会高些。而有些词例如“这个”、“和”大概在两篇文章中出现的频率会大致相等。但真实的情况是，一篇文章通常包含多种主题，而且每个主题所占比例各不相同。因此，如果一篇文章 10% 和猫有关，90% 和狗有关，那么和狗相关的关键字出现的次数大概会是和猫相关的关键字出现次数的 9 倍。</p>
<p>一个主题模型试图用数学框架来体现文档的这种特点。主题模型自动分析每个文档，统计文档内的词语，根据统计的信息来断定当前文档含有哪些主题，以及每个主题所占的比例各为多少 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
<ul>
<li><strong>TF-IDF</strong></li>
</ul>
<p>TF-IDF 是 Term Frequency - Inverse Document Frequency 的缩写，即“词频-逆文本频率”。TF-IDF 可以用于评估一个字词在语料中的一篇文档中的重要程度，基本思想是如果某个字词在一篇文档中出现的频率较高，而在其他文档中出现频率较低，则认为这个字词更能够代表这篇文档。</p>
<p>形式化地，对于文档 $y$ 中的字词 $x$ 的 TF-IDF 重要程度可以表示为：</p>
<p><code>$$ w_{x, y} = tf_{x, y} \times \log \left(\dfrac{N}{df_{x}}\right) $$</code></p>
<p>其中，<code>$tf_{x, y}$</code> 表示字词 <code>$x$</code> 在文档 <code>$y$</code> 中出现的频率，<code>$df_x$</code> 为包含字词 <code>$x$</code> 的文档数量，<code>$N$</code> 为语料中文档的总数量。</p>
<p>以 <a href="https://github.com/liuhuanyong/MusicLyricChatbot">14 万歌词语料</a> 为例，通过 TF-IDF 计算周杰伦的《简单爱》中最重要的 3 个词为 <code>['睡着', '放开', '棒球']</code>。</p>
<ul>
<li><strong>BM25</strong></li>
</ul>
<p>BM25 算法的全称为 Okapi BM25，是一种搜索引擎用于评估查询和文档之间相关程度的排序算法，其中 BM 是 Best Match 的缩写。</p>
<p>对于一个给定的查询 <code>$Q$</code>，包含的关键词为 <code>$q_1, \cdots, q_n$</code>，一个文档 <code>$D$</code> 的 BM25 值定义为：</p>
<p><code>$$ \operatorname{score}(D, Q)=\sum_{i=1}^{n} \operatorname{IDF}\left(q_{i}\right) \cdot \frac{f\left(q_{i}, D\right) \cdot\left(k_{1}+1\right)}{f\left(q_{i}, D\right)+k_{1} \cdot\left(1-b+b \cdot \frac{|D|}{\text { avgdl }}\right)} $$</code></p>
<p>其中，<code>$f\left(q_{i}, D\right)$</code> 表示 <code>$q_i$</code> 在文档 <code>$D$</code> 中的词频，<code>$|D|$</code> 表示文档 <code>$D$</code> 中的词数，<code>$\text{avgdl}$</code> 表示语料中所有文档的平均长度。<code>$k_1$</code> 和 <code>$b$</code> 为自由参数，通常取值为 <code>$k_1 \in \left[1.2, 2.0\right], b = 0.75$</code> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。<code>$\operatorname{IDF} \left(q_i\right)$</code> 表示词 <code>$q_i$</code> 的逆文档频率，通常计算方式如下：</p>
<p><code>$$ \operatorname{IDF}\left(q_{i}\right)=\ln \left(\frac{N-n\left(q_{i}\right)+0.5}{n\left(q_{i}\right)+0.5}+1\right) $$</code></p>
<p>其中，<code>$N$</code> 为语料中文档的总数量，<code>$n \left(q_i\right)$</code> 表示包含 <code>$q_i$</code> 的文档数量。</p>
<p>BM25 算法是对 TF-IDF 算法的优化，在词频的计算上，BM25 限制了文档 <code>$D$</code> 中关键词 <code>$q_i$</code> 的词频对评分的影响。为了防止词频过大，BM25 将这个值的上限设置为 <code>$k_1 + 1$</code>。</p>
<p><img src="/images/cn/2020-10-31-text-similarity/bm25-tf-1.png" alt=""></p>
<p>同时，BM25 还引入了平均文档长度 <code>$\text{avgdl}$</code>，不同的平均文档长度 <code>$\text{avgdl}$</code> 对 TF 分值的影响如下图所示：</p>
<p><img src="/images/cn/2020-10-31-text-similarity/bm25-tf-2.png" alt=""></p>
<ul>
<li><strong>TextRank</strong></li>
</ul>
<p>TextRank <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> 是基于 PageRank <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> 算法的一种关键词提取算法。PageRank 最早是用于 Google 的网页排名，因此以公司创始人拉里·佩奇（Larry Page）的姓氏来命名。PageRank 的计算公式如下：</p>
<p><code>$$ S\left(V_{i}\right)=(1-d)+d * \sum_{V_{j} \in I n\left(V_{i}\right)} \frac{1}{\left|O u t\left(V_{j}\right)\right|} S\left(V_{j}\right) $$</code></p>
<p>其中，<code>$V_i$</code> 表示任意一个网页，<code>$V_j$</code> 表示链接到网页 <code>$V_i$</code> 的网页，<code>$S \left(V_i\right)$</code> 表示网页 <code>$V_i$</code> 的 PageRank 值，<code>$In \left(V_i\right)$</code> 表示网页 <code>$V_i$</code> 所有的入链集合，<code>$Out \left(V_j\right)$</code> 表示网页 <code>$V_j$</code> 所有的出链集合，<code>$|\cdot|$</code> 表示集合的大小，<code>$d$</code> 为阻尼系数，是为了确保每个网页的 PageRank 值都大于 0。</p>
<p>TextRank 由 PageRank 改进而来，计算公式如下：</p>
<p><code>$$ WS \left(V_{i}\right)=(1-d)+d * \sum_{V_{j} \in In\left(V_{i}\right)} \frac{w_{j i}}{\sum_{V_{k} \in Out\left(V_{j}\right)} w_{j k}} WS \left(V_{j}\right) $$</code></p>
<p>相比于 PageRank 公式增加了权重项 <code>$W_{ji}$</code>，用来表示两个节点之间的边的权重。TextRank 提取关键词的算法流程如下：</p>
<ol>
<li>将文本进行切分得到 <code>$S_i = \left[t_{i1}, t_{i2}, \cdots, t_{in}\right]$</code>。</li>
<li>将 <code>$S_i$</code> 中大小为 <code>$k$</code> 的滑动窗口中的词定义为共现关系，构建关键词图 <code>$G = \left(V, E\right)$</code>。</li>
<li>根据 TextRank 的计算公式对每个节点的值进行计算，直至收敛。</li>
<li>对节点的 TextRank 的值进行倒叙排序，获取前 <code>$n$</code> 个词作为关键词。</li>
</ol>
<ul>
<li><strong>LSA, PLSA, LDA &amp; HDP</strong></li>
</ul>
<p><strong>潜在语义分析（LSA, Latent Semantic Analysis）</strong><sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> 的核心思想是将文本的高维词空间映射到一个低维的向量空间，我们称之为隐含语义空间。降维可以通过<a href="/cn/2017/12/evd-svd-and-pca/">奇异值分解（SVD）</a>实现，令 <code>$X$</code> 表示语料矩阵，元素 <code>$\left(i, j\right)$</code> 表示词 <code>$i$</code> 和文档 <code>$j$</code> 的共现情况（例如：词频）：</p>
<p><code>$$ X = \mathbf{d}_{j} \cdot \mathbf{t}_{i}^{T} = \left[\begin{array}{c} x_{1, j} \\ \vdots \\ x_{i, j} \\ \vdots \\ x_{m, j} \end{array}\right] \cdot \left[\begin{array}{ccccc} x_{i, 1} &amp; \ldots &amp; x_{i, j} &amp; \ldots &amp; x_{i, n} \end{array}\right] = \left[\begin{array}{ccccc} x_{1,1} &amp; \ldots &amp; x_{1, j} &amp; \ldots &amp; x_{1, n} \\ \vdots &amp; \ddots &amp; \vdots &amp; \ddots &amp; \vdots \\ x_{i, 1} &amp; \ldots &amp; x_{i, j} &amp; \ldots &amp; x_{i, n} \\ \vdots &amp; \ddots &amp; \vdots &amp; \ddots &amp; \vdots \\ x_{m, 1} &amp; \ldots &amp; x_{m, j} &amp; \ldots &amp; x_{m, n} \end{array}\right] $$</code></p>
<p>利用奇异值分解：</p>
<p><code>$$ X = U \Sigma V^{T} $$</code></p>
<p>取最大的 <code>$K$</code> 个奇异值，则可以得到原始矩阵的近似矩阵：</p>
<p><code>$$ \widetilde{X} =U \widetilde{\Sigma} V^{T} $$</code></p>
<p>在处理一个新的文档时，可以利用下面的公式将原始的词空间映射到潜在语义空间：</p>
<p><code>$$ \tilde{x} =\tilde{\Sigma} ^{-1} V^{T} x_{test} $$</code></p>
<p>LSA 的优点：</p>
<ol>
<li>低维空间可以刻画同义词</li>
<li>无监督模型</li>
<li>降维可以减少噪声，使特征更加鲁棒</li>
</ol>
<p>LSA 的缺点：</p>
<ol>
<li>未解决多义词问题</li>
<li>计算复杂度高，增加新文档时需要重新训练</li>
<li>没有明确的物理解释</li>
<li>高斯分布假设不符合文本特征（词频不为负）</li>
<li>维度的确定是 Ad hoc 的</li>
</ol>
<p><strong>概率潜语义分析（Probabilistic Latent Semantic Analysis, PLSA）</strong><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> 相比于 LSA 增加了概率模型，每个变量以及相应的概率分布和条件概率分布都有明确的物理解释。</p>
<p>PLSA 认为一篇文档可以由多个主题混合而成，而每个主题都是词上的概率分布，文章中的每个词都是由一个固定的主题生成的，如下图所示：</p>
<p><img src="/images/cn/2020-10-31-text-similarity/plsa.png" alt=""></p>
<p>针对第 <code>$m$</code> 篇文档 <code>$d_m$</code> 中的每个词的生成概率为：</p>
<p><code>$$ p\left(w \mid d_{m}\right)=\sum_{z=1}^{K} p(w \mid z) p\left(z \mid d_{m}\right)=\sum_{z=1}^{K} \varphi_{z w} \theta_{m z} $$</code></p>
<p>因此整篇文档的生成概率为：</p>
<p><code>$$ p\left(\vec{w} \mid d_{m}\right)=\prod_{i=1}^{n} \sum_{z=1}^{K} p\left(w_{i} \mid z\right) p\left(z \mid d_{m}\right)=\prod_{i=1}^{n} \sum_{z=1}^{K} \varphi_{z w_{i}} \theta_{d z} $$</code></p>
<p>PLSA 可以利用 EM 算法求得局部最优解。</p>
<p>PLSA 优点：</p>
<ol>
<li>定义了概率模型，有明确的物理解释</li>
<li>多项式分布假设更加符合文本特征</li>
<li>可以通过模型选择和复杂度控制来确定主题的维度</li>
<li>解决了同义词和多义词的问题</li>
</ol>
<p>PLSA 缺点：</p>
<ol>
<li>随着文本和词的增加，PLSA 模型参数也随之线性增加</li>
<li>可以生成语料中的文档的模型，但不能生成新文档的模型</li>
<li>EM 算法求解的计算量较大</li>
</ol>
<p><strong>隐含狄利克雷分布（Latent Dirichlet Allocation, LDA）</strong><sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> 在 PLSA 的基础上增加了参数的先验分布。在 PLSA 中，对于一个新文档，是无法获取 <code>$p \left(d\right)$</code> 的，因此这个概率模型是不完备的。LDA 对于 <code>$\vec{\theta}_m$</code> 和 <code>$\vec{\phi}_k$</code> 都增加了多项式分布的共轭分布狄利克雷分布作为先验，整个 LDA 模型如下图所示：</p>
<p><img src="/images/cn/2020-10-31-text-similarity/lda.png" alt=""></p>
<p>LDA 的参数估计可以通过<a href="/cn/2017/12/mcmc-and-gibbs-sampling/">吉布斯采样</a>实现。PLSA 和 LDA 的更多细节请参见《LDA 数学八卦》<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>。</p>
<p>LDA 在使用过程中仍需要指定主题的个数，而<strong>层次狄利克雷过程（Hierarchical Dirichlet Processes, HDP）</strong><sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> 通过过程的构造可以自动训练出主题的个数，更多实现细节请参考论文。</p>
<p>LSA，PLSA，LDA 和 HDP 之间的演化关系如下图所示：</p>
<p><img src="/images/cn/2020-10-31-text-similarity/lsa-plsa-lda-hdp.png" alt=""></p>
<blockquote>
<p>本节相关代码详见 <a href="https://github.com/leovan/leovan.me/tree/master/scripts/cn/2020-10-31-text-similarity/topic-model.py">这里</a>。</p>
</blockquote>
<h4 id="距离度量">距离度量</h4>
<blockquote>
<p>本节内容源自 <a href="/cn/2019/01/similarity-and-distance-measurement/">相似性和距离度量 (Similarity &amp; Distance Measurement)</a>。</p>
</blockquote>
<p>相似性度量 (Similarity Measurement) 用于衡量两个元素之间的相似性程度或两者之间的距离 (Distance)。距离衡量的是指元素之间的不相似性 (Dissimilarity)，通常情况下我们可以利用一个距离函数定义集合 <code>$X$</code> 上元素间的距离，即：</p>
<p><code>$$ d: X \times X \to \mathbb{R} $$</code></p>
<ul>
<li><strong>Jaccard 系数</strong></li>
</ul>
<p><code>$$ s = \dfrac{\left|X \cap Y\right|}{\left| X \cup Y \right|} = \dfrac{\left|X \cap Y\right|}{\left|X\right| + \left|Y\right| - \left|X \cap Y\right|} $$</code></p>
<p>Jaccard 系数的取值范围为：<code>$\left[0, 1\right]$</code>，0 表示两个集合没有重合，1 表示两个集合完全重合。</p>
<ul>
<li><strong>Dice 系数</strong></li>
</ul>
<p><code>$$ s = \dfrac{2 \left| X \cap Y \right|}{\left|X\right| + \left|Y\right|} $$</code></p>
<p>与 Jaccard 系数相同，Dice 系数的取值范围为：<code>$\left[0, 1\right]$</code>，两者之间可以相互转换 <code>$s_d = 2 s_j / \left(1 + s_j\right), s_j = s_d / \left(2 - s_d\right)$</code>。不同于 Jaccard 系数，Dice 系数的差异函数 <code>$d = 1 - s$</code> 并不是一个合适的距离度量，因为其并不满足距离函数的三角不等式。</p>
<ul>
<li><strong>Tversky 系数</strong></li>
</ul>
<p><code>$$ s = \dfrac{\left| X \cap Y \right|}{\left| X \cap Y \right| + \alpha \left| X \setminus Y \right| + \beta \left| Y \setminus X \right|} $$</code></p>
<p>其中，<code>$X \setminus Y$</code> 表示集合的相对补集。Tversky 系数可以理解为 Jaccard 系数和 Dice 系数的一般化，当 <code>$\alpha = \beta = 1$</code> 时为 Jaccard 系数，当 <code>$\alpha = \beta = 0.5$</code> 时为 Dice 系数。</p>
<ul>
<li><strong>Levenshtein 距离</strong></li>
</ul>
<p>Levenshtein 距离是 <strong>编辑距离 (Editor Distance)</strong> 的一种，指两个字串之间，由一个转成另一个所需的最少编辑操作次数。允许的编辑操作包括将一个字符替换成另一个字符，插入一个字符，删除一个字符。例如将 <strong>kitten</strong> 转成 <strong>sitting</strong>，转换过程如下：</p>
<p><code>$$ \begin{equation*} \begin{split} \text{kitten} \to \text{sitten} \left(k \to s\right) \\ \text{sitten} \to \text{sittin} \left(e \to i\right) \\ \text{sittin} \to \text{sitting} \left(\  \to g\right) \end{split} \end{equation*} $$</code></p>
<p>编辑距离的求解可以利用动态规划的思想优化计算的时间复杂度。</p>
<ul>
<li><strong>Jaro-Winkler 距离</strong></li>
</ul>
<p>对于给定的两个字符串 <code>$s_1$</code> 和 <code>$s_2$</code>，Jaro 相似度定义为：</p>
<p><code>$$ sim = \begin{cases} 0 &amp; \text{if} \  m = 0 \\ \dfrac{1}{3} \left(\dfrac{m}{\left|s_1\right|} + \dfrac{m}{\left|s_2\right|} + \dfrac{m-t}{m}\right) &amp; \text{otherwise} \end{cases} $$</code></p>
<p>其中，<code>$\left|s_i\right|$</code> 为字符串 <code>$s_i$</code> 的长度，<code>$m$</code> 为匹配的字符的个数，<code>$t$</code> 换位数目的一半。如果字符串 <code>$s_1$</code> 和 <code>$s_2$</code> 相差不超过 <code>$\lfloor \dfrac{\max \left(\left|s_1\right|, \left|s_2\right|\right)}{2} \rfloor - 1$</code>，我们则认为两个字符串是匹配的。例如，对于字符串 <strong>CRATE</strong> 和 <strong>TRACE</strong>，仅 <strong>R, A, E</strong> 三个字符是匹配的，因此 <code>$m = 3$</code>，尽管 <strong>C, T</strong> 均出现在两个字符串中，但是他们的距离超过了 1 (即，<code>$\lfloor \dfrac{5}{2} \rfloor - 1$</code>)，因此 <code>$t = 0$</code>。</p>
<p>Jaro-Winkler 相似度给予了起始部分相同的字符串更高的分数，其定义为：</p>
<p><code>$$ sim_w = sim_j + l p \left(1 - sim_j\right) $$</code></p>
<p>其中，<code>$sim_j$</code> 为字符串 <code>$s_1$</code> 和 <code>$s_2$</code> 的 Jaro 相似度，<code>$l$</code> 为共同前缀的长度 (规定不超过 <code>$4$</code>)，<code>$p$</code> 为调整系数 (规定不超过 <code>$0.25$</code>)，Winkler 将其设置为 <code>$p = 0.1$</code>。</p>
<ul>
<li><strong>汉明距离</strong></li>
</ul>
<p>汉明距离为两个<strong>等长字符串</strong>对应位置的不同字符的个数，也就是将一个字符串变换成另外一个字符串所需要<strong>替换</strong>的字符个数。例如：<strong>10<span style="color:#0000ff;">1</span>1<span style="color:#0000ff;">1</span>01</strong> 与 <strong>10<span style="color:#ff0000;">0</span>1<span style="color:#ff0000;">0</span>01</strong> 之间的汉明距离是 2，<strong>“<span style="color:#0000ff;">t</span>o<span style="color:#0000ff;">n</span>e<span style="color:#0000ff;">d</span>”</strong> 与 <strong>“<span style="color:#ff0000;">r</span>o<span style="color:#ff0000;">s</span>e<span style="color:#ff0000;">s</span>”</strong> 之间的汉明距离是 3。</p>
<pre><code class="language-python">import textdistance as td

s1 = '南京市长江大桥'
s2 = '北京市三元桥'

td.jaccard(s1, s2)
# 0.6666666666666666

td.sorensen_dice(s1, s2)
# 0.46153846153846156

td.tversky(s1, s2)
# 0.3

td.levenshtein(s1, s2)
# 4

td.jaro(s1, s2)
# 0.6428571428571429

td.hamming(s1, s2)
# 5
</code></pre>
<h3 id="表示学习">表示学习</h3>
<p>基于表示学习的文本相似度计算方法的思路如下：</p>
<ol>
<li>利用表示学习方法将不定长的文本表示为定长的实值向量。</li>
<li>计算转换后的实值向量相似度，用于表示两个文本的相似度。</li>
</ol>
<p>关于文本表示学习和实值向量相似度计算请参见之前博客：<a href="/cn/2018/10/word-embeddings/">词向量 (Word Embeddings)</a>，<a href="/cn/2019/01/similarity-and-distance-measurement/">相似性和距离度量 (Similarity &amp; Distance Measurement)</a>，<a href="/cn/2020/03/pre-trained-model-for-nlp/">预训练自然语言模型 (Pre-trained Models for NLP)</a>。</p>
<h2 id="文本词法-句法和语义角度">文本词法，句法和语义角度</h2>
<blockquote>
<p>本节主要参考自《基于词法、句法和语义的句子相似度计算方法》<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>。</p>
</blockquote>
<p>一段文本的内容分析由浅及深可以分为词法，句法和语义三个层次。</p>
<ol>
<li>词法，以词为对象，研究包括分词，词性和命名实体等。</li>
<li>句法，以句子为对象，研究包括句子成分和句子结构等。</li>
<li>语义，研究文字所表达的含义和蕴含的知识等。</li>
</ol>
<p>词法和句法可以统一成为语法，如下图所示：</p>
<p><img src="/images/cn/2020-10-31-text-similarity/lexical-syntax.png" alt=""></p>
<h3 id="词法">词法</h3>
<p>词法层以单个句子作为输入，其输出为已标记（词性，命名实体等）的词汇序列。</p>
<p><img src="/images/cn/2020-10-31-text-similarity/lexical-demo.png" alt=""></p>
<p>词汇序列的相似度计算可以采用上文中的距离度量等方式实现。</p>
<h3 id="句法">句法</h3>
<p>句法层用于研究句子各个组成部分及其排列顺序，将文本分解为句法单位，以理解句法元素的排列方式。句法层接收词法层分析后的将其转化为依存图。</p>
<p><img src="/images/cn/2020-10-31-text-similarity/syntax-demo.png" alt=""></p>
<p>对于依存图，我们可以利用三元组 <code>$S = \left(V_1, E, V_2\right)$</code> 表示任意一个依存关系，然后通过统计计算两个文本的依存图的三元组集合之间的相似度来评价句法层的相似度。此外，也可以从树结构的角度直接评价依存句法的相似度，更多细节可参考相关论文 <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup> <sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup>。</p>
<h3 id="语义">语义</h3>
<p>语义层用于研究文本所蕴含的意义。例如“父亲”和“爸爸”在词法层完全不同，但在语义层却具有相同的含义。针对语义相似度的两种深度学习范式如下：</p>
<p><img src="/images/cn/2020-10-31-text-similarity/deep-learning-paradigms-for-text-similarity.png" alt=""></p>
<p>第一种范式首先通过神经网络获取文本的向量表示，再通过向量之间的相似度来衡量文本的语义相似度。这种范式在提取特征时不考虑另一个文本的信息，更适合做大规模的语义相似召回，例如：DSSM <sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup>，ARC-I <sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup>，CNTN <sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup>，LSTM-RNN <sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup> 等。</p>
<p>第二种范式首先通过深度模型提取两个文本的交叉特征，得到匹配信号张量，再聚合为匹配分数。这种范式同时考虑两个文本的输入信息，更适合做小规模的语义相似精排，例如：ARC-II <sup id="fnref1:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup>，MatchPyramid <sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup>，Match-SRNN <sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup>，Duet <sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup> 等。</p>
<h2 id="文本长度角度">文本长度角度</h2>
<p>从文本长度角度出发，我们可以粗略的将文本分类为<strong>短文本</strong>和<strong>长文本</strong>。<strong>短文本</strong>包括“字词”，“短语”，“句子”等相对比较短的文本形式，<strong>长文本</strong>包括“段落”，“篇章”等相对比较长的文本形式。</p>
<h3 id="短文本-v-s-短文本">短文本 v.s. 短文本</h3>
<p>短文本同短文本的常见比较形式有：关键词（字词）同文本标题（句子）的匹配，相似查询（句子）的匹配等。如果单纯的希望获取字符层面的差异，可以通过距离度量进行相似度比较。如果需要从语义的角度获取相似度，则可以利用表示学习对需要比对的文本进行表示，在通过语义向量之间的相似程度来衡量原始文本之间的相似度，详情可参见上文。</p>
<h3 id="短文本-v-s-长文本">短文本 v.s. 长文本</h3>
<p>短文本同长文本的比较多见于文档的搜索，即给定相关的查询（字词），给出最相关的文档（段落和篇章）。对于这类问题常见的解决方式是对长文本利用 TF-IDF，BM25等方法或进行主题建模后，再同查询的关键词进行匹配计算相似度度。</p>
<h3 id="长文本-v-s-长文本">长文本 v.s. 长文本</h3>
<p>长文本同长文本的比较多见于文档的匹配和去重，对于这类问题常见的解决方式是利用关键词提取获取长文本的特征向量，然后利用特征向量之间的相似度衡量对应文本的相似程度。在针对海量文本的去重，还以应用 <a href="/cn/2020/08/nearest-neighbor-search/">SimHash</a> 等技术对文本生成一个指纹，从而实现快速去重。</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://zh.wikipedia.org/wiki/%E4%B8%BB%E9%A2%98%E6%A8%A1%E5%9E%8B">https://zh.wikipedia.org/wiki/主题模型</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Manning, C. D., Schütze, H., &amp; Raghavan, P. (2008). <em>Introduction to information retrieval</em>. Cambridge university press.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Mihalcea, R., &amp; Tarau, P. (2004, July). Textrank: Bringing order into text. In <em>Proceedings of the 2004 conference on empirical methods in natural language processing</em> (pp. 404-411).&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Page, L., Brin, S., Motwani, R., &amp; Winograd, T. (1999). <em>The PageRank citation ranking: Bringing order to the web</em>. Stanford InfoLab.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Deerwester, S., Dumais, S. T., Furnas, G. W., Landauer, T. K., &amp; Harshman, R. (1990). Indexing by latent semantic analysis. <em>Journal of the American society for information science</em>, 41(6), 391-407.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Hofmann, T. (1999, August). Probabilistic latent semantic indexing. In <em>Proceedings of the 22nd annual international ACM SIGIR conference on Research and development in information retrieval</em> (pp. 50-57).&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Blei, D. M., Ng, A. Y., &amp; Jordan, M. I. (2003). Latent dirichlet allocation. <em>Journal of machine Learning research</em>, 3(Jan), 993-1022.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Rickjin(靳志辉). 2013. LDA数学八卦&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Teh, Y. W., Jordan, M. I., Beal, M. J., &amp; Blei, D. M. (2006). Hierarchical dirichlet processes. <em>Journal of the american statistical association</em>, 101(476), 1566-1581.&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>翟社平, 李兆兆, 段宏宇, 李婧, &amp; 董迪迪. (2019). 基于词法, 句法和语义的句子相似度计算方法. <em>东南大学学报: 自然科学版</em>, 49(6), 1094-1100.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Zhang, K., &amp; Shasha, D. (1989). Simple fast algorithms for the editing distance between trees and related problems. <em>SIAM journal on computing</em>, 18(6), 1245-1262.&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Meila, M., &amp; Jordan, M. I. (2000). Learning with mixtures of trees. <em>Journal of Machine Learning Research</em>, 1(Oct), 1-48.&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Huang, P. S., He, X., Gao, J., Deng, L., Acero, A., &amp; Heck, L. (2013, October). Learning deep structured semantic models for web search using clickthrough data. In <em>Proceedings of the 22nd ACM international conference on Information &amp; Knowledge Management</em> (pp. 2333-2338).&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Hu, B., Lu, Z., Li, H., &amp; Chen, Q. (2014). Convolutional neural network architectures for matching natural language sentences. In <em>Advances in neural information processing systems</em> (pp. 2042-2050).&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>Qiu, X., &amp; Huang, X. (2015, June). Convolutional neural tensor network architecture for community-based question answering. In <em>Twenty-Fourth international joint conference on artificial intelligence</em>.&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>Palangi, H., Deng, L., Shen, Y., Gao, J., He, X., Chen, J., &hellip; &amp; Ward, R. (2016). Deep sentence embedding using long short-term memory networks: Analysis and application to information retrieval. <em>IEEE/ACM Transactions on Audio, Speech, and Language Processing</em>, 24(4), 694-707.&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Pang, L., Lan, Y., Guo, J., Xu, J., Wan, S., &amp; Cheng, X. (2016). Text matching as image recognition. In <em>Proceedings of the Thirtieth AAAI Conference on Artificial Intelligence (AAAI'16)</em>. (pp. 2793–2799).&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>Wan, S., Lan, Y., Xu, J., Guo, J., Pang, L., &amp; Cheng, X. (2016, July). Match-SRNN: modeling the recursive matching structure with spatial RNN. In <em>Proceedings of the Twenty-Fifth International Joint Conference on Artificial Intelligence</em> (pp. 2922-2928).&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p>Mitra, B., Diaz, F., &amp; Craswell, N. (2017, April). Learning to match using local and distributed representations of text for web search. In <em>Proceedings of the 26th International Conference on World Wide Web</em> (pp. 1291-1299).&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]></description></item><item><title>隐马尔可夫 (Hidden Markov Model, HMM)，条件随机场 (Conditional Random Fields, CRF) 和序列标注 (Sequence Labeling)</title><link>https://zeqiang.fun/cn/2020/05/hmm-crf-and-sequence-labeling/</link><pubDate>Sat, 02 May 2020 00:00:00 +0000</pubDate><guid>https://zeqiang.fun/cn/2020/05/hmm-crf-and-sequence-labeling/</guid><description><![CDATA[
        <h2 id="隐马尔可夫">隐马尔可夫</h2>
<p>隐马尔可夫模型（Hidden Markov Model，HMM）是一个描述包含隐含未知参数的马尔可夫过程的统计模型。马尔可夫过程（Markov Process）是因俄国数学家安德雷·安德耶维齐·马尔可夫（Андрей Андреевич Марков）而得名一个随机过程，在该随机过程中，给定当前状态和过去所有状态的条件下，其下一个状态的条件概率分布仅依赖于当前状态，通常具备离散状态的马尔可夫过程称之为马尔可夫链（Markov Chain）。因此，马尔可夫链可以理解为一个有限状态机，给定了当前状态为 <code>$S_i$</code> 时，下一时刻状态为 <code>$S_j$</code> 的概率，不同状态之间变换的概率称之为转移概率。下图描述了 3 个状态 <code>$S_a, S_b, S_c$</code> 之间转换状态的马尔可夫链。</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/hmm-markov-chain-example.png" class="lazyload"/>
  
</figure>
<p>隐马尔可夫模型中包含两种序列：随机生成的状态构成的序列称之为状态序列（state sequence），状态序列是不可被观测到的；每个状态对应的观测值组成的序列称之为观测序列（observation sequence）。令 <code>$I = \left(i_1, i_2, \cdots, i_T\right)$</code> 为状态序列，其中 <code>$i_t$</code> 为第 <code>$t$</code> 时刻系统的状态值，对应的有 <code>$O = \left(o_1, o_2, \cdots, o_T\right)$</code> 为观测序列，其中 <code>$o_t$</code> 为第 <code>$t$</code> 时刻系统的观测值，系统的所有可能的状态集合为 <code>$Q = \{q_1, q_2, \cdots, q_N\}$</code>，所有可能的观测集合为 <code>$V= \{v_1, v_2, \cdots, v_M\}$</code>。</p>
<p>隐马尔可夫模型主要由三组参数构成：</p>
<ol>
<li>状态转移矩阵：
<code>$$ A = \left[a_{ij}\right]_{N \times N} $$</code>
其中，
<code>$$ a_{ij} = P \left(i_{t+1} = q_j | i_t = q_i\right), 1 \leq i, j \leq N $$</code>
表示 <code>$t$</code> 时刻状态为 <code>$q_i$</code> 的情况下，在 <code>$t+1$</code> 时刻状态转移到 <code>$q_j$</code> 的概率。</li>
<li>观测概率矩阵：
<code>$$ B = \left[b_j \left(k\right)\right]_{N \times M} $$</code>
其中，
<code>$$ b_j \left(k\right) = P \left(o_t = v_k | i_t = q_j\right), k = 1, 2, \cdots, M, j = 1, 2, \cdots, N $$</code>
表示 <code>$t$</code> 时刻状态为 <code>$q_i$</code> 的情况下，观测值为 <code>$v_k$</code> 的概率。</li>
<li>初始状态概率向量：
<code>$$ \pi = \left(\pi_i\right) $$</code>
其中，
<code>$$ \pi_i = P \left(i_1 = q_i\right), i = 1, 2, \cdots, N $$</code>
表示 <code>$t = 1$</code> 时刻，系统处于状态 <code>$q_i$</code> 的概率。</li>
</ol>
<p>初始状态概率向量 <code>$\pi$</code> 和状态转移矩阵 <code>$A$</code> 决定了状态序列，观测概率矩阵 <code>$B$ </code> 决定了状态序列对应的观测序列，因此马尔可夫模型可以表示为：</p>
<p><code>$$ \lambda = \left(A, B, \pi\right) $$</code></p>
<p>对于马尔可夫模型 <code>$\lambda = \left(A, B, \pi\right)$</code>，通过如下步骤生成观测序列 <code>$\{o_1, o_2, \cdots, o_T\}$</code>：</p>
<ol>
<li>按照初始状态分布 <code>$\pi$</code> 产生状态 <code>$i_1$</code>.</li>
<li>令 <code>$t = 1$</code>。</li>
<li>按照状态 <code>$i_t$</code> 的观测概率分布 <code>$b_{i_t} \left(k\right)$</code> 生成 <code>$o_t$</code>。</li>
<li>按照状态 <code>$i_t$</code> 的状态转移概率分布 <code>$\left\{a_{i_t i_{t+1}}\right\}$</code> 产生状态 <code>$i_{t+1}$</code>，<code>$i_{t+1} = 1, 2, \cdots, N$</code>。</li>
<li>令 <code>$t = t + 1$</code>，如果 <code>$t &lt; T$</code>，转步骤 3；否则，终止。</li>
</ol>
<p>马尔可夫模型在应用过程中有 3 个基本问题 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>：</p>
<ol>
<li>概率计算问题。给定模型 <code>$\lambda = \left(A, B, \pi\right)$</code> 和观测序列 <code>$O = \{o_1, o_2, \cdots, o_T\}$</code>，计算在模型 <code>$\lambda$</code> 下观测序列 <code>$O$</code> 出现的概率 <code>$P\left(O | \lambda \right)$</code>。</li>
<li>学习问题。已知观测序列 <code>$O = \{o_1, o_2, \cdots, o_T\}$</code>，估计模型 <code>$\lambda = \left(A, B, \pi\right)$</code> 参数，使得在该模型下观测序列概率 <code>$P\left(X | \lambda \right)$</code> 最大。即用极大似然估计的方法估计参数。</li>
<li>预测问题，也称为解码（decoding）问题。已知模型 <code>$\lambda = \left(A, B, \pi\right)$</code> 和观测序列 <code>$O = \{o_1, o_2, \cdots, o_T\}$</code>，求对给定观测序列条件概率 <code>$P \left(I | O\right)$</code> 最大的状态序列 <code>$I = \{i_1, i_2, \cdots, i_T\}$</code>。即给定观测序列，求最有可能的对应的状态序列。</li>
</ol>
<h3 id="概率计算">概率计算</h3>
<h4 id="直接计算法">直接计算法</h4>
<p>给定模型 <code>$\lambda = \left(A, B, \pi \right)$</code> 和观测序列 <code>$O = \{o_1, o_2, ..., o_T\}$</code>，计算在模型 <code>$\lambda$</code> 下观测序列 <code>$O$</code> 出现的概率 <code>$P\left(O | \lambda \right)$</code>。最简单的办法就是列举出左右可能的状态序列 <code>$I = \{i_1, i_2, ..., i_T\}$</code>，再根据观测概率矩阵 <code>$B$</code>，计算每种状态序列对应的联合概率 <code>$P \left(O, I | \lambda\right)$</code>，对其进行求和得到概率 <code>$P\left(O | \lambda \right)$</code>。</p>
<p>状态序列 <code>$I = \{i_1, i_2, ..., i_T\}$</code> 的概率是：</p>
<p><code>$$ P \left(I | \lambda \right) = \pi_{y_1} \prod_{t = 1}^{T - 1} a_{{i_t}{i_{t+1}}} $$</code></p>
<p>对于固定的状态序列 <code>$I = \{i_1, i_2, ..., i_T\}$</code>，观测序列 <code>$O = \{o_1, o_2, ..., o_T\}$</code> 的概率是：</p>
<p><code>$$ P \left(O | I, \lambda \right) = \prod_{t = 1}^{T} b_{i_t} \left(o_t\right) $$</code></p>
<p><code>$O$</code> 和 <code>$I$</code> 同时出现的联合概率为：</p>
<p><code>$$ \begin{split} P \left(O, I | \lambda \right) &amp;= P \left(O | I, \lambda \right) P \left(I | \lambda \right) \\ &amp;= \pi_{y_1} \prod_{t = 1}^{T - 1} a_{{i_t}{i_{t+1}}} \prod_{t = 1}^{T} b_{i_t} \left(o_t\right) \end{split} $$</code></p>
<p>然后，对于所有可能的状态序列 <code>$I$</code> 求和，得到观测序列 <code>$O$</code> 的概率 <code>$P \left(O | \lambda\right)$</code>，即：</p>
<p><code>$$ \begin{split} P\left(O | \lambda \right) &amp;= \sum_{I} P \left(O | I, \lambda \right) P \left(I | \lambda \right)  \\ &amp;= \sum_{i_1, i_2, \cdots, i_T} \pi_{y_1} \prod_{t = 1}^{T - 1} a_{{i_t}{i_{t+1}}} \prod_{t = 1}^{T} b_{i_t} \left(o_t\right) \end{split} $$</code></p>
<p>但利用上式的计算量很大，是 <code>$O \left(T N^T\right)$</code> 阶的，这种算法不可行。</p>
<h4 id="前向算法">前向算法</h4>
<p><strong>前向概率</strong>：给定马尔可夫模型 <code>$\lambda$</code>，给定到时刻 <code>$t$</code> 部分观测序列为 <code>$o_1, o_2, \cdots, o_t$</code> 且状态为 <code>$q_i$</code> 的概率为前向概率，记作：</p>
<p><code>$$ \alpha_t \left(i\right) = P \left(o_1, o_2, \cdots, o_t, i_t = q_i | \lambda\right) $$</code></p>
<p>可以递推地求得前向概率 <code>$\alpha_t \left(i\right)$</code> 及观测序列概率 <code>$P \left(O | \lambda\right)$</code>，前向算法如下：</p>
<ol>
<li>初值
<code>$$ \alpha_{1}(i)=\pi_{i} b_{i}\left(o_{1}\right), \quad i=1,2, \cdots, N $$</code></li>
<li>递推，对 <code>$t = 1, 2, \cdots, T-1$</code>
<code>$$ \alpha_{t+1}(i)=\left[\sum_{j=1}^{N} \alpha_{t}(j) a_{j i}\right] b_{i}\left(o_{t+1}\right), \quad i=1,2, \cdots, N $$</code></li>
<li>终止
<code>$$ P(O | \lambda)=\sum_{i=1}^{N} \alpha_{T}(i) $$</code></li>
</ol>
<h4 id="后向算法">后向算法</h4>
<p><strong>后向概率</strong>：给定隐马尔可夫模型 <code>$\lambda$</code>，给定在时刻 <code>$t$</code> 状态为 <code>$q_i$</code> 的条件下，从 <code>$t+1$</code> 到 <code>$T$</code> 的部分观测序列为 <code>$o_{t+1}, o_{t+2}, \cdots, o_T$</code> 的概率为后向概率，记作：</p>
<p><code>$$ \beta_{t}(i)=P\left(o_{t+1}, o_{t+2}, \cdots, o_{T} | i_{t}=q_{i}, \lambda\right) $$</code></p>
<p>可以递推地求得后向概率 <code>$\alpha_t \left(i\right)$</code> 及观测序列概率 <code>$P \left(O | \lambda\right)$</code>，后向算法如下：</p>
<ol>
<li>初值
<code>$$ \beta_{T}(i)=1, \quad i=1,2, \cdots, N $$</code></li>
<li>递推，对 <code>$t = T-1, T-2, \cdots, 1$</code>
<code>$$ \beta_{t}(i)=\sum_{j=1}^{N} a_{i j} b_{j}\left(o_{t+1}\right) \beta_{t+1}(j), \quad i=1,2, \cdots, N $$</code></li>
<li>终止
<code>$$ P(O | \lambda)=\sum_{i=1}^{N} \pi_{i} b_{i}\left(o_{1}\right) \beta_{1}(i) $$</code></li>
</ol>
<h3 id="学习算法">学习算法</h3>
<h4 id="监督学习算法">监督学习算法</h4>
<p>假设以给训练数据包含 <code>$S$</code> 个长度相同的观测序列和对应的状态序列 <code>$\left\{\left(O_1, I_1\right), \left(O_2, I_2\right), \cdots, \left(O_S, I_S\right)\right\}$</code>，那么可以利用极大似然估计法来估计隐马尔可夫模型的参数。</p>
<p>设样本中时刻 <code>$t$</code> 处于状态 <code>$i$</code> 时刻 <code>$t+1$</code> 转移到状态 <code>$j$</code> 的频数为 <code>$A_{ij}$</code>，那么转移概率 <code>$a_{ij}$</code> 的估计是：</p>
<p><code>$$ \hat{a}_{i j}=\frac{A_{i j}}{\sum_{j=1}^{N} A_{i j}}, \quad i=1,2, \cdots, N ; \quad j=1,2, \cdots, N $$</code></p>
<p>设样本中状态为 <code>$j$</code> 并观测为 <code>$k$</code> 的频数是 <code>$B_{jk}$</code>，那么状态为 <code>$j$</code> 观测为 <code>$k$</code> 的概率 <code>$b_j \left(k\right)$</code> 的估计是：</p>
<p><code>$$ \hat{b}_{j}(k)=\frac{B_{j k}}{\sum_{k=1}^{M} B_{j k}}, \quad j=1,2, \cdots, N ; \quad k=1,2, \cdots, M $$</code></p>
<p>初始状态概率 <code>$\pi_i$</code> 的估计 <code>$\hat{\pi}_i$</code> 为 <code>$S$</code> 个样本中初始状态为 <code>$q_i$</code> 的频率。</p>
<h4 id="无监督学习算法">无监督学习算法</h4>
<p>假设给定训练数据值包含 <code>$S$</code> 个长度为 <code>$T$</code> 的观测序列 <code>$\left\{O_1, O_2, \cdots, O_S\right\}$</code> 而没有对应的状态序例，目标是学习隐马尔可夫模型 <code>$\lambda = \left(A, B, \pi\right)$</code> 的参数。我们将观测序列数据看做观测数据 <code>$O$</code>，状态序列数据看作不可观测的隐数据 <code>$I$</code>，那么马尔可夫模型事实上是一个含有隐变量的概率模型：</p>
<p><code>$$ P(O | \lambda)=\sum_{I} P(O | I, \lambda) P(I | \lambda) $$</code></p>
<p>它的参数学习可以由 EM 算法实现。EM 算法在隐马尔可夫模型学习中的具体实现为 Baum-Welch 算法：</p>
<ol>
<li>初始化。对 <code>$n = 0$</code>，选取 <code>$a_{i j}^{(0)}, b_{j}(k)^{(0)}, \pi_{i}^{(0)}$</code>，得到模型 <code>$\lambda^{(0)}=\left(A^{(0)}, B^{(0)}, \pi^{(0)}\right)$</code>。</li>
<li>递推。对 <code>$n = 1, 2, \cdots$</code>：
<code>$$ \begin{aligned} a_{i j}^{(n+1)} &amp;= \frac{\sum_{t=1}^{T-1} \xi_{t}(i, j)}{\sum_{t=1}^{T-1} \gamma_{t}(i)} \\ b_{j}(k)^{(n+1)} &amp;= \frac{\sum_{t=1, o_{t}=v_{k}}^{T} \gamma_{t}(j)}{\sum_{t=1}^{T} \gamma_{t}(j)} \\ \pi_{i}^{(n+1)} &amp;= \gamma_{1}(i) \end{aligned} $$</code>
右端各按照观测 <code>$O=\left(o_{1}, o_{2}, \cdots, o_{T}\right)$</code> 和模型 <code>$\lambda^{(n)}=\left(A^{(n)}, B^{(n)}, \pi^{(n)}\right)$</code> 计算，
<code>$$ \begin{aligned} \gamma_{t}(i) &amp;= \frac{\alpha_{t}(i) \beta_{t}(i)}{P(O | \lambda)}=\frac{\alpha_{t}(i) \beta_{t}(i)}{\sum_{j=1}^{N} \alpha_{t}(j) \beta_{t}(j)} \\ \xi_{t}(i, j) &amp;= \frac{\alpha_{t}(i) a_{i j} b_{j}\left(o_{t+1}\right) \beta_{t+1}(j)}{\sum_{i=1}^{N} \sum_{j=1}^{N} \alpha_{t}(i) a_{i j} b_{j}\left(o_{t+1}\right) \beta_{t+1}(j)} \end{aligned} $$</code></li>
<li>终止。得到模型参数 <code>$\lambda^{(n+1)}=\left(A^{(n+1)}, B^{(n+1)}, \pi^{(n+1)}\right)$</code>。</li>
</ol>
<h3 id="预测算法">预测算法</h3>
<h4 id="近似算法">近似算法</h4>
<p>近似算法的思想是，在每个时刻 <code>$t$</code> 选择在该时刻最有可能出现的状态 <code>$i_t^*$</code>，从而得到一个状态序列 <code>$I^{*}=\left(i_{1}^{*}, i_{2}^{*}, \cdots, i_{T}^{*}\right)$</code>，将它作为预测的结果。给定隐马尔可夫模型 <code>$\lambda$</code> 和观测序列 <code>$O$</code>，在时刻 <code>$t$</code> 处于状态 <code>$q_i$</code> 的概率 <code>$\gamma_t \left(i\right)$</code> 是：</p>
<p><code>$$ \gamma_{t}(i)=\frac{\alpha_{t}(i) \beta_{t}(i)}{P(O | \lambda)}=\frac{\alpha_{t}(i) \beta_{t}(i)}{\sum_{j=1}^{N} \alpha_{t}(j) \beta_{t}(j)} $$</code></p>
<p>在每一时刻 <code>$t$</code> 最有可能的状态 <code>$i_t^*$</code> 是：</p>
<p><code>$$ i_{t}^{*}=\arg \max _{1 \leqslant i \leqslant N}\left[\gamma_{t}(i)\right], \quad t=1,2, \cdots, T $$</code></p>
<p>从而得到状态序列 <code>$I^{*}=\left(i_{1}^{*}, i_{2}^{*}, \cdots, i_{T}^{*}\right)$</code>。</p>
<p>近似算法的优点是计算简单，其缺点是不能保证预测的状态序列整体是最有可能的状态序列，因为预测的状态序列可能有实际不发生的部分。事实上，上述方法得到的状态序列中有可能存在转移概率为0的相邻状态，即对某些 <code>$i, j, a_{ij} = 0$</code> 。尽管如此，近似算法仍然是有用的。</p>
<h4 id="维特比算法">维特比算法</h4>
<p>维特比算法（Viterbi Algorithm）实际是用动态规划（Dynamic Programming）解隐马尔可夫模型预测问题，即用动态规划求概率最大路径（最优路径）。这时一条路径对应着一个状态序列。</p>
<p>首先导入两个变量 <code>$\sigma$</code> 和 <code>$\Psi$</code>。定义在时刻 <code>$t$</code> 状态为 <code>$i$</code> 的所有单个路径 <code>$\left(i_1, i_2, \cdots, i_t\right)$</code> 中概率最大值为：</p>
<p><code>$$ \delta_{t}(i)=\max _{i_{1}, i_{2}, \cdots, i_{t-1}} P\left(i_{t}=i, i_{t-1}, \cdots, i_{1}, o_{t}, \cdots, o_{1} | \lambda\right), \quad i=1,2, \cdots, N $$</code></p>
<p>由定义可得变量 <code>$\sigma$</code> 的递推公式：</p>
<p><code>$$ \begin{aligned} \delta_{t+1}(i) &amp;=\max _{i_{1}, i_{2}, \cdots, i_{t}} P\left(i_{t+1}=i, i_{t}, \cdots, i_{1}, o_{t+1}, \cdots, o_{1} | \lambda\right) \\ &amp;=\max _{1 \leqslant j \leqslant N}\left[\delta_{t}(j) a_{j i}\right] b_{i}\left(o_{t+1}\right), \quad i=1,2, \cdots, N ; \quad t=1,2, \cdots, T-1 \end{aligned} $$</code></p>
<p>定义在时刻 <code>$t$</code> 状态为 <code>$i$</code> 的所有单个路径 <code>$\left(i_1, i_2, \cdots, i_{t-1}, i\right)$</code> 中概率最大的路径的第 <code>$t - 1$</code> 个结点为：</p>
<p><code>$$ \Psi_{t}(i)=\arg \max _{1 \leqslant j \leqslant N}\left[\delta_{t-1}(j) a_{j i}\right], \quad i=1,2, \cdots, N $$</code></p>
<p>维特比算法流程如下：</p>
<ol>
<li>初始化
<code>$$ \begin{array}{c} \delta_{1}(i)=\pi_{i} b_{i}\left(o_{1}\right), \quad i=1,2, \cdots, N \\ \Psi_{1}(i)=0, \quad i=1,2, \cdots, N \end{array} $$</code></li>
<li>递推。对 <code>$t = 2, 3, \cdots, T$</code>
<code>$$ \begin{array}{c} \delta_{t}(i)=\max _{1 \leqslant j \leqslant N}\left[\delta_{t-1}(j) a_{j i}\right] b_{i}\left(o_{t}\right), \quad i=1,2, \cdots, N \\ \Psi_{t}(i)=\arg \max _{1 \leqslant j \leqslant N}\left[\delta_{t-1}(j) a_{j i}\right], \quad i=1,2, \cdots, N \end{array} $$</code></li>
<li>终止。
<code>$$ \begin{array}{c} P^{*}=\max _{1 \leqslant i \leqslant N} \delta_{T}(i) \\ i_{T}^{*}=\arg \max _{1 \leqslant i \leqslant N}\left[\delta_{T}(i)\right] \end{array} $$</code></li>
<li>最优路径回溯。对 <code>$t = T - 1, T - 2, \cdots, 1$</code>
<code>$$ i_{t}^{*}=\Psi_{t+1}\left(i_{t+1}^{*}\right) $$</code></li>
</ol>
<p>求的最优路径 <code>$I^{*}=\left(i_{1}^{*}, i_{2}^{*}, \cdots, i_{T}^{*}\right)$</code>。</p>
<h2 id="条件随机场">条件随机场</h2>
<p>概率无向图模型（Probabilistic Undirected Graphical Model）又称为马尔可夫随机场（Markov Random Field），是一个可以由无向图表示的联合概率分布。概率图模型（Probabilistic Graphical Model）是由图表示的概率分布，设有联合概率分布 <code>$P \left(Y\right), Y \in \mathcal{Y}$</code> 是一组随机变量。由无向图 <code>$G = \left(V, E\right)$</code> 表示概率分布 <code>$P \left(Y\right)$</code>，即在图 <code>$G$</code> 中，结点 <code>$v \in V$</code> 表示一个随机变量 <code>$Y_v, Y = \left(Y_v\right)_{v \in V}$</code>，边 <code>$e \in E$</code> 表示随机变量之间的概率依赖关系。</p>
<p><strong>成对马尔可夫性</strong>：设 <code>$u$</code> 和 <code>$v$</code> 是无向图 <code>$G$</code> 中任意两个没有边连接的结点，结点 <code>$u$</code> 和 <code>$v$</code> 分别对应随机变量 <code>$Y_u$</code> 和 <code>$Y_v$</code>。其他所有结点为 <code>$O$</code>，对应的随机变量组是 <code>$Y_O$</code>。成对马尔可夫是指给定随机变量组 <code>$Y_O$</code> 的条件下随机变量 <code>$Y_u$</code> 和 <code>$Y_v$</code> 是条件独立的，即：</p>
<p><code>$$ P\left(Y_{u}, Y_{v} | Y_{O}\right)=P\left(Y_{u} | Y_{O}\right) P\left(Y_{v} | Y_{O}\right) $$</code></p>
<p><strong>局部马尔可夫性</strong>：设 <code>$v \in V$</code> 是无向图 <code>$G$</code> 中任意一个结点，<code>$W$</code> 是与 <code>$v$</code> 有边连接的所有结点，<code>$O$</code> 是 <code>$v$</code> 和 <code>$W$</code> 以外的其他所有结点。<code>$v$</code> 表示的随机变量是 <code>$Y_v$</code>，<code>$W$</code> 表示的随机变量组是 <code>$Y_W$</code>，<code>$O$</code> 表示的随机变量组是 <code>$Y_O$</code>。局部马尔可夫性是指在给定随机变量组 <code>$Y_W$</code> 的条件下随机变量 <code>$Y_v$</code> 与随机变量组 <code>$Y_O$</code> 是独立的，即：</p>
<p><code>$$ P\left(Y_{v}, Y_{O} | Y_{W}\right)=P\left(Y_{v} | Y_{W}\right) P\left(Y_{O} | Y_{W}\right) $$</code></p>
<p>在 <code>$P \left(Y_O | Y_W\right) &gt; 0$</code> 时，等价地：</p>
<p><code>$$ P\left(Y_{v} | Y_{W}\right)=P\left(Y_{v} | Y_{W}, Y_{O}\right) $$</code></p>
<p>局部马尔可夫性如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/local-markov.png" class="lazyload"/>
  
</figure>
<p><strong>全局马尔可夫性</strong>：设结点结合 <code>$A, B$</code> 是在无向图 <code>$G$</code> 中被结点集合 <code>$C$</code> 分开的任意结点集合，如下图所示。结点集合 <code>$A, B$</code> 和 <code>$C$</code> 所对应的随机变量组分别是 <code>$Y_A, Y_B$</code> 和 <code>$Y_C$</code>。全局马尔可夫性是指给定随机变量组 <code>$Y_C$</code> 条件下随机变量组 <code>$Y_A$</code> 和 <code>$Y_B$</code> 是条件独立的，即：</p>
<p><code>$$ P\left(Y_{A}, Y_{B} | Y_{C}\right)=P\left(Y_{A} | Y_{C}\right) P\left(Y_{B} | Y_{C}\right) $$</code></p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/global-markov.png" class="lazyload"/>
  
</figure>
<p><strong>概率无向图模型</strong>定义为：设有联合概率分布 <code>$P \left(Y\right)$</code>，由无向图 <code>$G = \left(V, E\right)$</code> 表示，在图 <code>$G$</code> 中，结点表示随机变量，边表示随机变量之间的依赖关系。如果联合概率分布 <code>$P \left(Y\right)$</code> 满足成对、局部或全局马尔可夫性，就称此联合概率分布为概率无向图模型（Probabilistic Undirected Graphical Model），或马尔可夫随机场（Markov Random Field）。</p>
<p><strong>团与最大团</strong>：无向图 <code>$G$</code> 中任何两个结点均有边连接的结点子集称为团（Clique）。若 <code>$C$</code> 是无向图 <code>$G$</code> 的一个团，并且不能再加进任何一个 <code>$G$</code> 的结点时期成为一个更大的团，则称此 <code>$C$</code> 为最大团（Maximal Clique）。</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/clique.png" class="lazyload"/>
  <figcaption><p class="figcaption">无向图的团和最大团</p></figcaption>
</figure>
<p>上图表示 4 个结点组成的无向图。图中有 2 个结点组成的团有 5 个：<code>$\left\{Y_1, Y_2\right\}$</code>，<code>$\left\{Y_2, Y_3\right\}$</code>，<code>$\left\{Y_3, Y_4\right\}$</code>，<code>$\left\{Y_4, Y_2\right\}$</code> 和 <code>$\left\{Y_1, Y_3\right\}$</code>。有 2 个最大团：<code>$\left\{Y_1, Y_2, Y_3\right\}$</code> 和 <code>$\left\{Y_2, Y_3, Y_4\right\}$</code>。而 <code>$\left\{Y_1, Y_2, Y_3, Y_4\right\}$</code> 不是一个团，因为 <code>$Y_1$</code> 和 <code>$Y_4$</code> 没有边连接。</p>
<p>将概率无向图模型的联合概率分布表示为其最大团上的随机变量的函数的乘积形式的操作，称为概率无向图模型的因子分解。给定无向图模型，设其无向图为 <code>$G$</code>，<code>$C$</code> 为 <code>$G$</code> 上的最大团，<code>$Y_C$</code> 表示 <code>$C$</code> 对应的随机变量。那么概率无向图模型的联合概率分布 <code>$P \left(Y\right)$</code> 可以写作图中所有最大团 <code>$C$</code> 上的函数 <code>$\Psi_C \left(Y_C\right)$</code> 的乘积形式，即：</p>
<p><code>$$ P(Y)=\frac{1}{Z} \prod_{C} \Psi_{C}\left(Y_{C}\right) $$</code></p>
<p>其中，<code>$Z$</code> 是规范化因子：</p>
<p><code>$$ Z=\sum_{Y} \prod_{C} \Psi_{C}\left(Y_{C}\right) $$</code></p>
<p>规范化因子保证 <code>$P \left(Y\right)$</code> 构成一个概率分布。函数 <code>$\Psi_C \left(Y_C\right)$</code> 称为<strong>势函数</strong>，这里要求势函数 <code>$\Psi_C \left(Y_C\right)$</code> 是严格正的，通常定义为指数函数：</p>
<p><code>$$ \Psi_{C}\left(Y_{C}\right)=\exp \left\{-E\left(Y_{C}\right)\right\} $$</code></p>
<p>概率无向图模型的因子分解由这个 Hammersley-Clifford 定理来保证。</p>
<p><strong>条件随机场</strong>（Conditional Random Field）是给定随机变量 <code>$X$</code> 条件下，随机变量 <code>$Y$</code> 的马尔可夫随机场。设 <code>$X$</code> 与 <code>$Y$</code> 是随机变量，<code>$P \left(Y | X\right)$</code> 是给定 <code>$X$</code> 的条件下 <code>$Y$</code> 的条件概率分布。若随机变量 <code>$Y$</code> 构成一个有无向图 <code>$G = \left(V, E\right)$</code> 表示的马尔可夫随机场，即：</p>
<p><code>$$ P\left(Y_{v} | X, Y_{w}, w \neq v\right)=P\left(Y_{v} | X, Y_{w}, w \sim v\right) $$</code></p>
<p>对任意结点 <code>$v$</code> 成立，则称条件概率分布 <code>$P \left(Y | X\right)$</code> 为条件随机场。其中，<code>$w \sim v$</code> 表示在图 <code>$G = \left(V, E\right)$</code> 中与结点 <code>$v$</code> 有边连接的所有结点 <code>$w$</code>，<code>$w \neq v$</code> 表示结点 <code>$v$</code> 以外的所有结点，<code>$Y_v, Y_u$</code> 与 <code>$Y_w$</code> 为结点 <code>$v, u$</code> 和 <code>$w$</code> 对应的随机变量。</p>
<p>定义中并没有要求 <code>$X$</code> 和 <code>$Y$</code> 具有相同的结构，一般假设 <code>$X$</code> 和 <code>$Y$</code> 有相同的图结构，下图展示了无向图的线性链情况，即：</p>
<p><code>$$ G=(V=\{1,2, \cdots, n\}, E=\{(i, i+1)\}), \quad i=1,2, \cdots, n-1 $$</code></p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/linear-crf-1.png" class="lazyload"/>
  <figcaption><p class="figcaption">线性链条件随机场</p></figcaption>
</figure>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/linear-crf-2.png" class="lazyload"/>
  <figcaption><p class="figcaption">X 和 Y 有相同的图结构的线性链条件随机场</p></figcaption>
</figure>
<p>此情况下，<code>$X=\left(X_{1}, X_{2}, \cdots, X_{n}\right), Y=\left(Y_{1}, Y_{2}, \cdots, Y_{n}\right)$</code>，最大团是相邻两个结点的集合。</p>
<p><strong>线性链条件随机场</strong>：设 <code>$X=\left(X_{1}, X_{2}, \cdots, X_{n}\right), Y=\left(Y_{1}, Y_{2}, \cdots, Y_{n}\right)$</code> 均为线性链表示的随机变量序列，若在给定随机变量序列 <code>$X$</code> 的条件下，随机变量序列 <code>$Y$</code> 的条件概率分布 <code>$P \left(Y | X\right)$</code> 构成条件随机场，即满足马尔可夫性：</p>
<p><code>$$ \begin{array}{c} P\left(Y_{i} | X, Y_{1}, \cdots, Y_{i-1}, Y_{i+1}, \cdots, Y_{n}\right)=P\left(Y_{i} | X, Y_{i-1}, Y_{i+1}\right) \\ i=1,2, \cdots, n \quad (\text { 在 } i=1 \text { 和 } n \text { 时只考虑单边 }) \end{array} $$</code></p>
<p>则称 <code>$P \left(Y | X\right)$</code> 为线性链条件随机场。在标注问题中，<code>$X$</code> 表示输入观测序列，<code>$Y$</code> 表示对应的输出标记序列或状态序列。</p>
<p>根据 Hammersley-Clifford 定理，设 <code>$P \left(Y | X\right)$</code> 为线性链条件随机场，则在随机变量 <code>$X$</code> 取值为 <code>$x$</code> 的条件下，随机变量 <code>$Y$</code> 取值为 <code>$y$</code> 的条件概率有如下形式：</p>
<p><code>$$ P(y | x)=\frac{1}{Z(x)} \exp \left(\sum_{i, k} \lambda_{k} t_{k}\left(y_{i-1}, y_{i}, x, i\right)+\sum_{i, l} \mu_{l} s_{l}\left(y_{i}, x, i\right)\right) $$</code></p>
<p>其中，</p>
<p><code>$$ Z(x)=\sum_{y} \exp \left(\sum_{i, k} \lambda_{k} t_{k}\left(y_{i-1}, y_{i}, x, i\right)+\sum_{i, l} \mu_{l} s_{l}\left(y_{i}, x, i\right)\right) $$</code></p>
<p>其中，<code>$t_k$</code> 和 <code>$s_l$</code> 是特征函数，<code>$\lambda_k$</code> 和 <code>$\mu_l$</code> 是对应的权值。<code>$Z \left(x\right)$</code> 是规范化因子，求和是在所有可能的输出序列上进行的。</p>
<p>条件随机场的概率计算，学习算法和预测算法类似隐马尔可夫模型，在此不进行过多赘述，有兴趣的同学可以参见 <sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
<p>综上所述，隐马尔可夫模型和条件随机场的主要联系和区别如下：</p>
<ol>
<li>HMM 是概率有向图，CRF 是概率无向图</li>
<li>HMM 是生成模型，CRF 是判别模型</li>
</ol>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/relationship-between-nb-lr-hmm-lcrf-gdm-gcrf.png" class="lazyload"/>
  <figcaption><p class="figcaption">图片来源：An Introduction to Conditional Random Fields</p></figcaption>
</figure>
<p>如上图所示，上面部分为生成式模型，下面部分为判别式模型，生成式模型尝试构建联合分布 <code>$P \left(Y, X\right)$</code>，而判别模型则尝试构建条件分布 <code>$P \left(Y | X\right)$</code>。</p>
<h2 id="序列标注">序列标注</h2>
<p>序列标注（Sequence Labeling）是自然语言处理中的一项重要任务，对于给定的文本序列需要给出对应的标注序列。常见的序列标注任务包含：组块分析（Chunking），词性标注（Part-of-Speech，POS）和命名实体识别（Named Entity Recognition，NER）。</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/pos-ner-demo.png" class="lazyload"/>
  
</figure>
<p>上图为一段文本的词性标注和命名实体识别的结果。</p>
<h3 id="词性标注">词性标注</h3>
<p>词性标注是指为分词结果中的每个单词标注一个正确的词性，即确定每个词是名词、动词、形容词或其他词性的过程。</p>
<p>一些常用中文标注规范如下：</p>
<ol>
<li>北京大学现代汉语语料库基本加工规范 <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></li>
<li>北大语料库加工规范：切分·词性标注·注音 <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></li>
<li>计算所汉语词性标记集 3.0（ICTPOS 3.0）<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></li>
<li>The Part-Of-Speech Tagging Guidelines for the Penn Chinese Treebank (3.0) <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></li>
<li>中文文本标注规范（微软亚洲研究院）<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></li>
</ol>
<h3 id="命名实体识别">命名实体识别</h3>
<p>命名实体识别，又称作“专名识别”，是指识别文本中具有特定意义的实体，主要包括人名、地名、机构名、专有名词等。简单的讲，就是识别自然文本中的实体指称的边界和类别。</p>
<p>常用的标注标准有 IO，BIO，BIOES，BMEWO 和 BMEWO+ 等。（参考自：<a href="https://lingpipe-blog.com/2009/10/14/coding-chunkers-as-taggers-io-bio-bmewo-and-bmewo/">Coding Chunkers as Taggers: IO, BIO, BMEWO, and BMEWO+</a>）</p>
<ol>
<li>IO 标注标准是最简单的标注方式，对于命名实体类别 X 标注为 <code>I_X</code>，其他则标注为 <code>O</code>。由于没有标签界线表示，这种方式无法表示两个相邻的同类命名实体。</li>
<li>BIO 标注标准将命名实体的起始部分标记为 <code>B_X</code>，其余部分标记为 <code>I_X</code>。</li>
<li>BIOES 标注标准将命名实体的起始部分标记为 <code>B_X</code>，中间部分标记为 <code>I_X</code>，结尾部分标记为 <code>E_X</code>，对于单个字符成为命名实体的情况标记为 <code>S_X</code>。</li>
<li>BMEWO 标注标准将命名实体的起始部分标记为 <code>B_X</code>，中间部分标记为 <code>M_X</code>，结尾部分标记为 <code>E_X</code>，对于单个字符成为命名实体的情况标记为 <code>W_X</code>。</li>
<li>BMEWO+ 标注标准在 BMEWO 的基础上针对不同情况的非命名实体标签的标注进行了扩展，同时增加了一个句外（out-of-sentence）标签 <code>W_OOS</code>，句子起始标签 <code>BB_O_OOS</code> 和句子结束标签 <code>WW_O_OOS</code>，如 <a href="http://www.alias-i.com/lingpipe/docs/api/com/aliasi/chunk/HmmChunker.html">下表</a> 所示：</li>
</ol>
<table>
  <thead>
      <tr>
          <th>标签</th>
          <th>描述</th>
          <th>可能上接的标签</th>
          <th>可能下接的标签</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>B_X</code></td>
          <td>命名实体类型 X 的起始</td>
          <td><code>E_Y, W_Y, EE_O_X, WW_O_X</code></td>
          <td><code>M_X, W_X</code></td>
      </tr>
      <tr>
          <td><code>M_X</code></td>
          <td>命名实体类型 X 的中间</td>
          <td><code>B_X, M_X</code></td>
          <td><code>M_X, W_X</code></td>
      </tr>
      <tr>
          <td><code>E_X</code></td>
          <td>命名实体类型 X 的结尾</td>
          <td><code>B_X, M_X</code></td>
          <td><code>B_Y, W_Y, BB_O_X, WW_O_X</code></td>
      </tr>
      <tr>
          <td><code>W_X</code></td>
          <td>命名实体类型 X 的单个字符</td>
          <td><code>E_Y, W_Y, EE_O_X, WW_O_X</code></td>
          <td><code>B_Y, W_Y, BB_O_X, WW_O_X</code></td>
      </tr>
      <tr>
          <td><code>BB_O_X</code></td>
          <td>非命名实体的起始，上接命名实体类型 X</td>
          <td><code>E_X, W_X</code></td>
          <td><code>MM_O, EE_O_Y</code></td>
      </tr>
      <tr>
          <td><code>MM_O</code></td>
          <td>非命名实体的中间</td>
          <td><code>BB_O_Y, MM_O</code></td>
          <td><code>MM_O, EE_O_Y</code></td>
      </tr>
      <tr>
          <td><code>EE_O_X</code></td>
          <td>非命名实体的结尾，下接命名实体类型 X</td>
          <td><code>BB_O_Y, MM_O</code></td>
          <td><code>B_X, W_X</code></td>
      </tr>
      <tr>
          <td><code>WW_O_X</code></td>
          <td>非命名实体，上接命名实体，下接命名实体类型 X</td>
          <td><code>E_X, W_X</code></td>
          <td><code>B_Y, W_Y</code></td>
      </tr>
  </tbody>
</table>
<p>不同标注标准的差别示例如下：</p>
<table>
  <thead>
      <tr>
          <th>字符</th>
          <th>IO</th>
          <th>BIO</th>
          <th>BIOES</th>
          <th>BMEWO</th>
          <th>BMEWO+</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td><code>W_OOS</code></td>
      </tr>
      <tr>
          <td>Yesterday</td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>BB_O_OOS</code></td>
      </tr>
      <tr>
          <td>afternoon</td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>MM_O</code></td>
      </tr>
      <tr>
          <td>,</td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>EE_O_PER</code></td>
      </tr>
      <tr>
          <td>John</td>
          <td><code>I_PER</code></td>
          <td><code>B_PER</code></td>
          <td><code>B_PER</code></td>
          <td><code>B_PER</code></td>
          <td><code>B_PER</code></td>
      </tr>
      <tr>
          <td>J</td>
          <td><code>I_PER</code></td>
          <td><code>I_PER</code></td>
          <td><code>I_PER</code></td>
          <td><code>M_PER</code></td>
          <td><code>M_PER</code></td>
      </tr>
      <tr>
          <td>.</td>
          <td><code>I_PER</code></td>
          <td><code>I_PER</code></td>
          <td><code>I_PER</code></td>
          <td><code>M_PER</code></td>
          <td><code>M_PER</code></td>
      </tr>
      <tr>
          <td>Smith</td>
          <td><code>I_PER</code></td>
          <td><code>I_PER</code></td>
          <td><code>E_PER</code></td>
          <td><code>E_PER</code></td>
          <td><code>E_PER</code></td>
      </tr>
      <tr>
          <td>traveled</td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>BB_O_PER</code></td>
      </tr>
      <tr>
          <td>to</td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>EE_O_LOC</code></td>
      </tr>
      <tr>
          <td>Washington</td>
          <td><code>I_LOC</code></td>
          <td><code>B_LOC</code></td>
          <td><code>S_LOC</code></td>
          <td><code>W_LOC</code></td>
          <td><code>W_LOC</code></td>
      </tr>
      <tr>
          <td>.</td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>O</code></td>
          <td><code>WW_O_OOS</code></td>
      </tr>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td><code>W_OOS</code></td>
      </tr>
  </tbody>
</table>
<p>不同标准的标签数量如下表所示：</p>
<table>
  <thead>
      <tr>
          <th>标注标准</th>
          <th>标签数量</th>
          <th>N=1</th>
          <th>N=3</th>
          <th>N=20</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>IO</td>
          <td>N+1</td>
          <td>2</td>
          <td>4</td>
          <td>21</td>
      </tr>
      <tr>
          <td>BIO</td>
          <td>2N+1</td>
          <td>3</td>
          <td>7</td>
          <td>41</td>
      </tr>
      <tr>
          <td>BIOES</td>
          <td>4N+1</td>
          <td>5</td>
          <td>13</td>
          <td>81</td>
      </tr>
      <tr>
          <td>BMEWO</td>
          <td>4N+1</td>
          <td>5</td>
          <td>13</td>
          <td>81</td>
      </tr>
      <tr>
          <td>BMEWO+</td>
          <td>7N+3</td>
          <td>10</td>
          <td>24</td>
          <td>143</td>
      </tr>
  </tbody>
</table>
<p>其中，N 为命名实体类型的数量。</p>
<h4 id="bilstm-crf">BiLSTM CRF <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></h4>
<blockquote>
<p>本小节内容参考和修改自 <a href="https://github.com/createmomo/CRF-Layer-on-the-Top-of-BiLSTM">CRF-Layer-on-the-Top-of-BiLSTM</a>。</p>
</blockquote>
<p>Huang 等人提出了一种基于 BiLSTM 和 CRF 的神经网络模型用于序例标注。整个网络如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/bilstm-crf.png" class="lazyload"/>
  
</figure>
<p>关于模型中的 BiLSTM 部分在此不过多赘述，相关细节可以参见之前的博客：<a href="/cn/2018/09/rnn/">循环神经网络 (Recurrent Neural Network, RNN)</a> 和 <a href="/cn/2020/03/pre-trained-model-for-nlp/">预训练自然语言模型 (Pre-trained Models for NLP)</a>。BiLSTM-CRF 模型的输入是词嵌入向量，输出是对应的预测标注标签，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/bilstm-crf-1.png" class="lazyload"/>
  
</figure>
<p>BiLSTM 层的输出为每个标签的分数，对于 <code>$w_0$</code>，BiLSTM 的输出为 1.5 (<code>B_PER</code>)，0.9 (<code>I_PER</code>)，0.1 (<code>B_ORG</code>)，0.08 (<code>I_ORG</code>) 和 0.05 (<code>O</code>)，这些分数为 CRF 层的输入，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/bilstm-crf-2.png" class="lazyload"/>
  
</figure>
<p>经过 CRF 层后，具有最高分数的预测序列被选择为最优预测结果。如果没有 CRF 层，我们可以直接选择 BiLSTM 层输出分数的最大值对应的序列为预测结果。例如，对于 <code>$w_0$</code>，最高分数为 1.5，对应的预测标签则为 <code>B_PER</code>，类似的 <code>$w_1, w_2, w_3, w_4$</code> 对应的预测标签为 <code>I_PER, O, B_ORG, O</code>，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/bilstm-crf-3.png" class="lazyload"/>
  
</figure>
<p>虽然我们在上例中得到了正确的结果，但通常情况下并非如此。对于如下的示例，预测结果为 <code>I_ORG, I_PER, O, I_ORG, I_PER</code>，这显然是不正确的。</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/bilstm-crf-4.png" class="lazyload"/>
  
</figure>
<p>CRF 层在进行预测时可以添加一些约束，这些约束可以在训练时被 CRF 层学习得到。可能的约束有：</p>
<ul>
<li>句子的第一个词的标签可以是 <code>B_X</code> 或 <code>O</code>，而非 <code>I_X</code>。</li>
<li><code>B_X, I_X</code> 是有效的标签，而 <code>B_X, I_Y</code> 是无效的标签。</li>
<li>一个命名实体的起始标签应为 <code>B_X</code> 而非 <code>I_X</code>。</li>
</ul>
<p>CRF 层的损失包含两部分，这两部分构成了 CRF 层的关键：</p>
<ul>
<li>发射分数（Emission Score）</li>
</ul>
<p>发射分数即为 BiLSTM 层的输出分数，例如 <code>$w_0$</code> 对应的标签 <code>B_PER</code> 的分数为 1.5。为了方便起见，对于每类标签给定一个索引：</p>
<table>
  <thead>
      <tr>
          <th>标签</th>
          <th>索引</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>B_PER</code></td>
          <td>0</td>
      </tr>
      <tr>
          <td><code>I_PER</code></td>
          <td>1</td>
      </tr>
      <tr>
          <td><code>B_ORG</code></td>
          <td>2</td>
      </tr>
      <tr>
          <td><code>I_ORG</code></td>
          <td>3</td>
      </tr>
      <tr>
          <td><code>O</code></td>
          <td>4</td>
      </tr>
  </tbody>
</table>
<p>我们利用 <code>$x_{i y_{j}}$</code> 表示发射分数，<code>$i$</code> 为词的索引，<code>$y_i$</code> 为标注标签的索引。例如：<code>$x_{i=1, y_{j}=2} = x_{w_1, \text{B_ORG}} = 0.1$</code>，表示 <code>$w_1$</code> 为 <code>B_ORG</code> 的分数为 0.1。</p>
<ul>
<li>转移分数（Transition Score）</li>
</ul>
<p>我们利用 <code>$t_{y_i, y_j}$</code> 表示转移分数，例如 <code>$t_{\text{B_PER}, \text{I_PER}} = 0.9$</code> 表示由标签 <code>B_PER</code> 转移到 <code>I_PER</code> 的分数为 0.9。因此，需要一个转移分数矩阵用于存储所有标注标签之间的转移分数。为了使得转移分数矩阵更加鲁棒，需要添加两个标签 <code>START</code> 和 <code>END</code>，分别表示一个句子的开始和结束。下表为一个转移分数矩阵的示例：</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th><code>START</code></th>
          <th><code>B-PER</code></th>
          <th><code>I-PER</code></th>
          <th><code>B-ORG</code></th>
          <th><code>I-ORG</code></th>
          <th><code>O</code></th>
          <th><code>END</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>START</code></td>
          <td>0</td>
          <td>0.8</td>
          <td>0.007</td>
          <td>0.7</td>
          <td>0.0008</td>
          <td>0.9</td>
          <td>0.08</td>
      </tr>
      <tr>
          <td><code>B_PER</code></td>
          <td>0</td>
          <td>0.6</td>
          <td>0.9</td>
          <td>0.2</td>
          <td>0.0006</td>
          <td>0.6</td>
          <td>0.009</td>
      </tr>
      <tr>
          <td><code>I_PER</code></td>
          <td>-1</td>
          <td>0.5</td>
          <td>0.53</td>
          <td>0.55</td>
          <td>0.0003</td>
          <td>0.85</td>
          <td>0.008</td>
      </tr>
      <tr>
          <td><code>B_ORG</code></td>
          <td>0.9</td>
          <td>0.5</td>
          <td>0.0003</td>
          <td>0.25</td>
          <td>0.8</td>
          <td>0.77</td>
          <td>0.006</td>
      </tr>
      <tr>
          <td><code>I_ORG</code></td>
          <td>-0.9</td>
          <td>0.45</td>
          <td>0.007</td>
          <td>0.7</td>
          <td>0.65</td>
          <td>0.76</td>
          <td>0.2</td>
      </tr>
      <tr>
          <td><code>O</code></td>
          <td>0</td>
          <td>0.65</td>
          <td>0.0007</td>
          <td>0.7</td>
          <td>0.0008</td>
          <td>0.9</td>
          <td>0.08</td>
      </tr>
      <tr>
          <td><code>END</code></td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
      </tr>
  </tbody>
</table>
<p>转移分数矩阵作为 BiLSTM-CRF 模型的一个参数，随机初始化并通过模型的训练不断更新，最终学习得到约束条件。</p>
<p>CRF 层的损失函数包含两个部分：真实路径分数和所有可能路径的总分数。假设每个可能的路径有一个分数 <code>$P_i$</code>，共 <code>$N$</code> 种可能的路径，所有路径的总分数为：</p>
<p><code>$$ P_{\text {total}}=P_{1}+P_{2}+\ldots+P_{N}=e^{S_{1}}+e^{S_{2}}+\ldots+e^{S_{N}} $$</code></p>
<p>则损失函数定义为：</p>
<p><code>$$ \text{Loss} = \dfrac{P_{\text{RealPath}}}{\sum_{i=1}^{N} P_i} $$</code></p>
<p>对于 <code>$S_i$</code>，共包含两部分：发射分数和转移分数。以路径 <code>START -&gt; B_PER -&gt; I_PER -&gt; O -&gt; B_ORG -&gt; O -&gt; END</code> 为例，发射分数为：</p>
<p><code>$$ \begin{aligned} \text{EmissionScore} = \ &amp;x_{0, \text{START}} + x_{1, \text{B_PER}} + x_{2, \text{I_PER}} \\ &amp;+ x_{3, \text{O}} + x_{4, \text{B_ORG}} + x_{5, \text{O}} + x_{6, \text{END}} \end{aligned} $$</code></p>
<p>其中 <code>$x_{i, y_j}$</code> 表示第 <code>$i$</code> 个词标签为 <code>$y_j$</code> 的分数，为 BiLSTM 的输出，<code>$x_{0, \text{START}}$</code> 和 <code>$x_{6, \text{END}}$</code> 可以设置为 0。转换分数为：</p>
<p><code>$$ \begin{aligned} \text{TransitionScore} = \ &amp;t_{\text{START}, \text{B_PER}} + t_{\text{B_PER}, \text{I_PER}} + t_{\text{I_PER}, \text{O}} \\ &amp;+ t_{\text{O}, \text{B_ORG}} + t_{\text{B_ORG}, \text{O}} + t_{\text{O}, \text{END}} \end{aligned} $$</code></p>
<p>其中 <code>$t_{y_i, y_j}$</code> 表示标注标签由 <code>$y_i$</code> 转移至 <code>$y_j$</code> 的分数。</p>
<p>对于所有路径的总分数的计算过程采用了类似 <a href="/cn/2018/11/computational-complexity-and-dynamic-programming/">动态规划</a> 的思想，整个过程计算比较复杂，在此不再详细展开，详细请参见参考文章。</p>
<p>利用训练好的 BiLSTM-CRF 模型进行预测时，首先我们可以得到序列的发射分数和转移分数，其次用维特比算法可以得到最终的预测标注序列。</p>
<h4 id="lattice-lstm">Lattice LSTM <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></h4>
<p>Zhang 等人针对中文提出了一种基于 Lattice LSTM 的命名实体识别方法，Lattice LSTM 的结构如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-05-02-hmm-and-crf/lattice-lstm.png" class="lazyload"/>
  
</figure>
<p>模型的基本思想是将句子中的词汇（例如：南京，长江大桥等）信息融入到基于字符的 LSTM 模型中，从而可以显性地利用词汇信息。</p>
<p>模型的输入为一个字符序列 <code>$c_1, c_2, \cdots, c_m$</code> 和词汇表 <code>$\mathbb{D}$</code> 中所有匹配的字符子序列，其中词汇表 <code>$\mathbb{D}$</code> 利用大量的原始文本通过分词构建。令 <code>$w_{b, e}^d$</code> 表示有以第 <code>$b$</code> 个字符起始，以第 <code>$e$</code> 个字符结尾的子序列，例如：<code>$w_{1,2}^d$</code> 表示“南京
”，<code>$w_{7,8}^d$</code> 表示“大桥”。</p>
<p>不同于一般的字符级模型，LSTM 单元的状态考虑了句子中的子序列 <code>$w_{b,e}^d$</code>，每个子序列 <code>$w_{b,e}^d$</code> 表示为：</p>
<p><code>$$ \mathbf{x}_{b, e}^{w}=\mathbf{e}^{w}\left(w_{b, e}^{d}\right) $$</code></p>
<p>其中，<code>$\mathbf{e}^{w}$</code> 为词向量查询表。一个词单元 <code>$\mathbf{c}_{b,e}^w$</code> 用于表示 <code>$\mathbf{x}_{b,e}^w$</code> 的循环状态：</p>
<p><code>$$ \begin{aligned} \left[\begin{array}{c} \mathbf{i}_{b, e}^{w} \\ \mathbf{f}_{b, e}^{w} \\ \widetilde{c}_{b, e}^{w} \end{array}\right] &amp;=\left[\begin{array}{c} \sigma \\ \sigma \\ \tanh \end{array}\right]\left(\mathbf{W}^{w \top}\left[\begin{array}{c} \mathbf{x}_{b, e}^{w} \\ \mathbf{h}_{b}^{c} \end{array}\right]+\mathbf{b}^{w}\right) \\ \mathbf{c}_{b, e}^{w} &amp;=\mathbf{f}_{b, e}^{w} \odot \mathbf{c}_{b}^{c}+\mathbf{i}_{b, e}^{w} \odot \widetilde{c}_{b, e}^{w} \end{aligned} $$</code></p>
<p>其中，<code>$\mathbf{i}_{b, e}^{w}$</code> 和 <code>$\mathbf{f}_{b, e}^{w}$</code> 分别为输入门和遗忘门。由于仅在字符级别上进行标注，因此对于词单元来说没有输出门。</p>
<p>对于 <code>$\mathbf{c}_{j}^c$</code> 来说可能有多条信息流，例如 <code>$\mathbf{c}_7^c$</code> 的输入包括 <code>$\mathbf{x}_7^c$</code>（桥），<code>$\mathbf{c}_{6,7}^w$</code>（大桥）和 <code>$\mathbf{c}_{4,7}^w$</code>（长江大桥）。论文采用了一个新的门 <code>$\mathbf{i}_{b,e}^c$</code> 来控制所有子序列单元 <code>$\mathbf{c}_{b,e}^w$</code> 对 <code>$\mathbf{c}_{j}^c$</code> 的贡献：</p>
<p><code>$$ \mathbf{i}_{b, e}^{c}=\sigma\left(\mathbf{W}^{l \top}\left[\begin{array}{c} \mathbf{x}_{e}^{c} \\ \mathbf{c}_{b, e}^{w} \end{array}\right]+\mathbf{b}^{l}\right) $$</code></p>
<p>则单元状态 <code>$\mathbf{c}_j^c$</code> 的计算变为：</p>
<p><code>$$ \mathbf{c}_{j}^{c}=\sum_{b \in\left\{b^{\prime} | w_{b^{\prime}, j} \in \mathbb{D}\right\}} \boldsymbol{\alpha}_{b, j}^{c} \odot \boldsymbol{c}_{b, j}^{w}+\boldsymbol{\alpha}_{j}^{c} \odot \widetilde{\boldsymbol{c}}_{j}^{c} $$</code></p>
<p>在上式中，<code>$\mathbf{i}_{b,j}^c$</code> 和 <code>$\mathbf{i}_j^c$</code> 标准化为 <code>$\boldsymbol{\alpha}_{b, j}^{c}$</code> 和 <code>$\boldsymbol{\alpha}_{j}^{c}$</code>：</p>
<p><code>$$ \begin{aligned} \boldsymbol{\alpha}_{b, j}^{c} &amp;=\frac{\exp \left(\mathbf{i}_{b, j}^{c}\right)}{\exp \left(\mathbf{i}_{j}^{c}\right)+\sum_{b^{\prime} \in\left\{b^{\prime \prime} | w_{b^{\prime \prime}, j}^{d} \in \mathbb{D}\right\}} \exp \left(\mathbf{i}_{b^{\prime}, j}^{c}\right)} \\ \boldsymbol{\alpha}_{j}^{c} &amp;=\frac{\exp \left(\mathbf{i}_{j}^{c}\right)}{\exp \left(\mathbf{i}_{j}^{c}\right)+\sum_{b^{\prime} \in\left\{b^{\prime \prime} | w_{b^{\prime \prime}, j}^{d} \in \mathbb{D}\right\}} \exp \left(\mathbf{i}_{b^{\prime}, j}^{c}\right)} \end{aligned} $$</code></p>
<h2 id="开放资源">开放资源</h2>
<h3 id="标注工具">标注工具</h3>
<ol>
<li><a href="https://github.com/synyi/poplar">synyi/poplar</a></li>
<li><a href="https://github.com/nlplab/brat">nlplab/brat</a></li>
<li><a href="https://github.com/doccano/doccano">doccano/doccano</a></li>
<li><a href="https://github.com/heartexlabs/label-studio">heartexlabs/label-studio</a></li>
<li><a href="https://github.com/deepwel/Chinese-Annotator">deepwel/Chinese-Annotator</a></li>
<li><a href="https://github.com/jiesutd/YEDDA">jiesutd/YEDDA</a></li>
</ol>
<h3 id="开源模型-框架和代码">开源模型，框架和代码</h3>
<ol>
<li><a href="https://github.com/pytorch/text">pytorch/text</a></li>
<li><a href="https://github.com/flairNLP/flair">flairNLP/flair</a></li>
<li><a href="https://github.com/PetrochukM/PyTorch-NLP">PetrochukM/PyTorch-NLP</a></li>
<li><a href="https://github.com/allenai/allennlp">allenai/allennlp</a></li>
<li><a href="https://github.com/fastnlp/fastNLP">fastnlp/fastNLP</a></li>
<li><a href="https://stanfordnlp.github.io/CoreNLP/index.html">Stanford CoreNLP</a></li>
<li><a href="http://neuroner.com/">NeuroNER</a></li>
<li><a href="https://spacy.io/">spaCy</a></li>
<li><a href="https://www.nltk.org/">NLTK</a></li>
<li><a href="https://github.com/BrikerMan/Kashgari">BrikerMan/Kashgari</a></li>
<li><a href="https://github.com/Hironsan/anago">Hironsan/anago</a></li>
<li><a href="https://github.com/crownpku/Information-Extraction-Chinese">crownpku/Information-Extraction-Chinese</a></li>
<li><a href="https://github.com/thunlp/OpenNRE">thunlp/OpenNRE</a></li>
<li><a href="https://github.com/hankcs/HanLP">hankcs/HanLP</a></li>
<li><a href="https://github.com/jiesutd/NCRFpp">jiesutd/NCRFpp</a></li>
</ol>
<h3 id="其他资源">其他资源</h3>
<ol>
<li><a href="https://github.com/keon/awesome-nlp">keon/awesome-nlp</a></li>
<li><a href="https://github.com/crownpku/Awesome-Chinese-NLP">crownpku/Awesome-Chinese-NLP</a></li>
<li><a href="https://github.com/sebastianruder/NLP-progress">sebastianruder/NLP-progress</a></li>
<li><a href="https://github.com/thunlp/NREPapers">thunlp/NREPapers</a></li>
</ol>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>李航. (2019). <em>统计学习方法（第二版）</em>. 清华大学出版社.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>俞士汶, 段慧明, 朱学锋, &amp; 孙斌. (2002). 北京大学现代汉语语料库基本加工规范. <em>中文信息学报</em>, 16(5), 51-66.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>俞士汶, 段慧明, 朱学锋, 孙斌, &amp; 常宝宝. (2003). 北大语料库加工规范: 切分· 词性标注· 注音. <em>汉语语言与计算学报</em>, 13(2), 121-158.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="http://ictclas.nlpir.org/nlpir/html/readme.htm">http://ictclas.nlpir.org/nlpir/html/readme.htm</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Xia, F. (2000). The part-of-speech tagging guidelines for the Penn Chinese Treebank (3.0). <em>IRCS Technical Reports Series</em>, 38.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Huang, C. N., Li, Y., &amp; Zhu, X. (2006). Tokenization guidelines of Chinese text (v5.0, in Chinese). <em>Microsoft Research Asia</em>.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Huang, Z., Xu, W., &amp; Yu, K. (2015). Bidirectional LSTM-CRF models for sequence tagging. <em>arXiv preprint arXiv:1508.01991</em>.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Zhang, Y., &amp; Yang, J. (2018). Chinese NER Using Lattice LSTM. In <em>Proceedings of the 56th Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers)</em> (pp. 1554-1564).&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]></description></item><item><title>预训练自然语言模型 (Pre-trained Models for NLP)</title><link>https://zeqiang.fun/cn/2020/03/pre-trained-model-for-nlp/</link><pubDate>Sat, 28 Mar 2020 00:00:00 +0000</pubDate><guid>https://zeqiang.fun/cn/2020/03/pre-trained-model-for-nlp/</guid><description><![CDATA[
        <blockquote>
<p>本文为 Pre-trained Models for Natural Language Processing: A Survey 和相关模型的读书笔记 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
</blockquote>
<p>在当下的 NLP 研究领域，随着计算机算力的不断增强，越来越多的通用语言表征的预训练模型（Pre-trained Models，PTMs）逐渐涌现出来。这对下游的 NLP 任务非常有帮助，可以避免大量从零开始训练新的模型。PTM 大致可以分为两代：</p>
<ul>
<li>第一代 PTM 旨在学习词嵌入。由于下游任务不在需要这些模型，因此为了计算效率，这些模型往往采用浅层模型，例如 Skip-Gram <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>，GloVe <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> 等。尽管这些模型可以捕获词的语义，但由于未基于上下文环境，因此不能够捕捉到更深层次的概念，例如：句法结构，语义角色，指代等等。</li>
<li>第二代 PTM 专注于学习基于上下文的词嵌入，例如 CoVe <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>，ELMo <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>，OpenAI GPT <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> 和 BERT <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> 等。这些学习到的编码器在下游任务中仍会用于词在上下文中的语义表示。</li>
</ul>
<h2 id="预训练原理">预训练原理</h2>
<h3 id="语言表示学习">语言表示学习</h3>
<p>分布式表示的核心思想为用一个低维的实值向量表示一段文本，向量单独每个维度不具有任何实质含义，但整个向量表示了一个具体的概念。下图展示了一个 NLP 任务的一般神经网络架构：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/generic-neural-architecture-for-nlp.png" class="lazyload"/>
  <figcaption><p class="figcaption">NLP 任务的一般神经网络架构</p></figcaption>
</figure>
<p>词嵌入包含两种类型：<strong>上下文无关的词嵌入</strong>和<strong>基于上下文的词嵌入</strong>。两者的不同点在于一个词的嵌入是够会随着上下文的不同而随之改变。</p>
<ul>
<li>上下文无关的词嵌入</li>
</ul>
<p>为了表征语义，我们需要将离散的语言符号映射到一个分布式嵌入空间中。对于词典 <code>$\mathcal{V}$</code> 中的一个词 <code>$x$</code>，我们将其映射为查询表 <code>$\mathbf{E} \in \mathbb{R}^{D_e \times \|\mathcal{V}\|}$</code> 中的一个向量 <code>$\mathbf{e}_x \in \mathbb{R}^{D_e}$</code>，其中 <code>$D_e$</code> 为嵌入的维度。</p>
<p>这种类型的嵌入主要有两个缺陷：一是嵌入是静态的，词在不同的上下文中的嵌入表示是相同的，因此无法处理一词多义；二是未登录词（out-of-vocabulary，OOV）问题，通常可以采用字符级嵌入表示解决该问题。更多上下文无关的词嵌入模型，请参见之前的博客 <a href="/cn/2018/10/word-embeddings/">词向量</a>。</p>
<ul>
<li>基于上下文的词嵌入</li>
</ul>
<p>为了解决上述问题，我们需要区分在不同上下文下词的含义。给定一段文本 <code>$x_1, x_2, \dotsc, x_T$</code> 其中每段标记 <code>$x_t \in \mathcal{V}$</code> 为一个词或子词，<code>$x_t$</code> 基于上下文的表示依赖于整段文本。</p>
<p><code>$$ \left[\mathbf{h}_1, \mathbf{h}_2, \dotsc, \mathbf{h}_T\right] = f_{\text{enc}} \left(x_1, x_2, \dotsc, x_T\right) $$</code></p>
<p>其中，<code>$f_{\text{enc}} \left(\cdot\right)$</code> 为神经编码器，<code>$\mathbf{h}_t$</code> 为标记 <code>$x_t$</code> 的<strong>基于上下文的嵌入</strong>或<strong>动态嵌入</strong>。</p>
<h3 id="神经上下文编码器">神经上下文编码器</h3>
<p>神经上下文编码器大致可以分为 3 类：</p>
<ol>
<li><strong>基于卷积的模型</strong>：基于卷积的模型通过卷积操作从一个词的邻居中聚合局部信息来捕获这个词的含义 <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>。
<figure>
    <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/convolutional-model.png" class="lazyload"/>
    <figcaption><p class="figcaption">Convolutional model</p></figcaption>
  </figure></li>
<li><strong>基于序列的模型</strong>：基于序列的模型采用 RNNs（LSTM <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> 和 GRU <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>） 来捕获词的上下文信息。实际中，我们采用双向的 RNNs 从词的两端收集信息，不过整体效果容易收到长期依赖问题的影响。
<figure>
    <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/sequential-model.png" class="lazyload"/>
    <figcaption><p class="figcaption">Sequential model</p></figcaption>
  </figure></li>
<li><strong>基于图的模型</strong>：基于图的模型将字作为图中的一个节点来学习上下文表示，这个图通常是一个词之间预定义的语言结构，例如：语法结构 <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup> <sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup> 或语义关系 <sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup>。尽管基于语言学的图结构能提供有用的信息，但如何构建一个好的图结构则成为了难题。除此之外，基于语言学的图结构需要依赖专家知识和外部工具，例如：依存句法分析等。事实上，我们会采用一个更直接的方式去学习任意两个词之间的关系，通常连接的权重可以通过自注意力机制自动计算得出。Transformer <sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup> 是一个采用了全链接自注意力架构的实现，同时也采用了位置嵌入（positional embedding），层标准化（layer normalization）和残差连接（residual connections）等网络设计理念。
<figure>
    <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/fully-connected-graph-based-model.png" class="lazyload"/>
    <figcaption><p class="figcaption">Fully-connected graph-based model</p></figcaption>
  </figure></li>
</ol>
<h3 id="为什么预训练">为什么预训练</h3>
<p>对于大多数的 NLP 任务，构建一个大规模的有标签的数据集是一项很大的挑战。相反，大规模的无标签语料是相对容易构建的，为了充分利用这些无标签数据，我们可以先利用它们获取一个好的语言表示，再将这些表示用于其他任务。预训练的好处如下：</p>
<ol>
<li>预训练可以从大规模语料中学习得到通用的语言表示，并用于下游任务。</li>
<li>预训练提供了更优的模型初始化方法，有助于提高模型的泛化能力和加速模型收敛。</li>
<li>预训练可以当作是在小数据集上一种避免过拟合的正则化方法。</li>
</ol>
<h3 id="预训练任务">预训练任务</h3>
<p>预训练任务对于学习语言的通用表示来说至关重要。通常情况下，预训练任务具有挑战性，同时需要大量训练数据。我们将预训练任务划分为 3 类：</p>
<ol>
<li><strong>监督学习</strong>，即从包含输入输出对的训练数据中学习一个由输入到输出的映射函数。</li>
<li><strong>非监督学习</strong>，即从无标签数据获取一些固有的知识，例如：聚类，密度，潜在表征等。</li>
<li><strong>自监督学习</strong>，是监督学习和非监督学习的混合体，核心思想是对于输入的一部分利用其他部分进行预测。</li>
</ol>
<h4 id="语言模型-language-modeling-lm">语言模型（Language Modeling，LM）</h4>
<p>NLP 中最常见的非监督任务为概率语言建模，这是一个经典的概率密度估计问题。给定一个文本序列 <code>$x_{1:T} = \left[x_1, x_2, \dotsc, x_T\right]$</code>，他的联合概率 <code>$p \left(x_{1:T}\right)$</code> 可以分解为：</p>
<p><code>$$ p \left(x_{1:T}\right) = \prod_{t=1}^{y}{p \left(x_t \mid x_{0:t-1}\right)} $$</code></p>
<p>其中 <code>$x_0$</code> 为序列开始的特殊标记。条件概率 <code>$p \left(x_t \mid x_{0:t-1}\right)$</code> 可以通过给定的语言上下文 <code>$x_{0:t-1}$</code> 词的概率分布进行建模估计。上下文 <code>$x_{0:t-1}$</code> 可以通过神经编码器 <code>$f_{\text{enc}} \left(\cdot\right)$</code> 进行建模，则条件概率可以表示为：</p>
<p><code>$$ p \left(x_t | x_{0:t-1}\right) = g_{\text{LM}} \left(f_{\text{enc}} \left(x_{0:t-1}\right)\right) $$</code></p>
<p>其中，<code>$g_{\text{LM}}$</code> 为预测层。</p>
<h4 id="遮罩语言模型-masked-language-modeling-mlm">遮罩语言模型（Masked Language Modeling，MLM）</h4>
<p>大致上来说，MLM 首先将输入句子的一些词条进行遮挡处理，其次再训练模型利用剩余的部分预测遮挡的部分。这种预训练方法会导致在预训练（pre-training）阶段和微调（fine-tuning）阶段的不一致，因为在微调阶段遮挡标记并未出现，BERT <sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup> 通过一个特殊的符号 <code>[MASK]</code> 对其进行处理。</p>
<h5 id="sequence-to-sequence-mlm-seq2seq-mlm">Sequence-to-Sequence MLM (Seq2Seq MLM)</h5>
<p>MLM 通常以一个分类问题进行求解，我们将遮挡后的序列输入到一个神经编码器，再将输出向量传给一个 Softmax 分类器来预测遮挡的字符。我们可以采用 Encoder-Decoder（Seq2Seq）网络结构，将遮挡的序列输入到 Encoder，Decoder 则会循序的产生被遮挡的字符。MASS <sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup> 和 T5 <sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup> 均采用了这种序列到序列的 MLM 结构，这种结构对 Seq2Seq 风格的下游任务很有帮助，例如：问答，摘要和机器翻译。</p>
<h5 id="enhanced-masked-language-modeling-e-mlm">Enhanced Masked Language Modeling (E-MLM)</h5>
<p>同时，大量研究对于 BERT 所使用的遮罩处理进行了改进。RoBERTa <sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup> 采用了一种动态的遮罩处理。UniLM 将遮罩任务拓展到 3 种不同的类型：单向的，双向的和 Seq2Seq 类型的。</p>
<h4 id="排列语言模型-permuted-language-modeling-plm">排列语言模型（Permuted Language Modeling，PLM）</h4>
<p>在 MLM 中一些特殊字符（例如：<code>[MASK]</code>）在下游任务中是无用的，为了解决这个问题，XLNet <sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup> 提出了一种排列语言模型（Permuted Language Modeling，PLM）用于替代 MLM。简言之，PLM 是对输入序列的排列进行语言建模。给定一个序列，从所有可能的排列中随机抽样得到一个排列，将排列后的序列中的一些字符作为模型的预测目标，利用其他部分和目标的自然位置进行训练。需要注意的是这种排列并不会影响序列的自然位置，其仅用于定义字符预测的顺序。</p>
<h4 id="去噪自编码-denoising-autoencoder-dae">去噪自编码（Denoising Autoencoder，DAE）</h4>
<p>DAE 旨在利用部分有损的输入恢复原始无损的输入。对于语言模型，例如 Seq2Seq 模型，可以采用标准的 Transformer 来重构原始文本。有多种方式可以对文本进行破坏 <sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup>：</p>
<ol>
<li>字符遮罩：随机采样字符并将其替换为 <code>[MASK]</code>。</li>
<li>字符删除：随机的从输入中删除字符，不同于字符遮罩，模型需要确定丢失字符的位置。</li>
<li>文本填充：采样一段文本并将其替换为一个 <code>[MASK]</code>，每段文本的长度服从泊松分布（$\lambda = 3$），模型需要确定这段文本中缺失的字符个数。</li>
<li>句子重排：将文档以终止标点进行分割，再进行随机排序。</li>
<li>文档旋转：随机均匀地选择一个字符，对文档进行旋转使得这个字符作为文档的起始字符，模型需要确定文档真实的起始位置。</li>
</ol>
<h4 id="对比学习-contrastive-learning-ctl">对比学习（Contrastive Learning，CTL）</h4>
<p>对比学习 <sup id="fnref:21"><a href="#fn:21" class="footnote-ref" role="doc-noteref">21</a></sup> 假设一些观测到的文本对比随机采样的文本具有更相似的语义。对于文本对 <code>$\left(x, y\right)$</code> 通过最小化如下目标函数来学习评分函数 <code>$s \left(x, y\right)$</code>：</p>
<p><code>$$ \mathbb{E}_{x, y^+, y^-} \left[- \log \dfrac{\exp \left(s \left(x, y^+\right)\right)}{\exp \left(s \left(x, y^+\right)\right) + \exp \left(s \left(x, y^-\right)\right)}\right] $$</code></p>
<p>其中，<code>$\left(x, y^+\right)$</code> 为一个相似对，<code>$y^-$</code> 对于 <code>$x$</code> 而言假定为不相似，<code>$y^+$</code> 和 <code>$y^-$</code> 通常称之为正样本和负样本。评分函数 <code>$s \left(x, y\right)$</code> 通过一个神经编码器计算可得，<code>$s \left(x, y\right) = f^{\top}_{\text{enc}} \left(x\right) f_{\text{enc}} \left(y\right)$</code> 或 <code>$s \left(x, y\right) = f_{\text{enc}} \left(x \oplus y\right)$</code>。CTL 的核心思想是“通过对比进行学习”。</p>
<p>下图展示了预训练模型的分类和部分代表模型：</p>

<div class="box fancy-figure caption-position-bottom caption-effect-fade" >
  <figure class="photoswipe-figure" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
    <div class="img">
      <img itemprop="thumbnail" src="/images/cn/2020-03-28-pre-trained-model-for-nlp/ptms.png" alt="预训练模型分类及代表性模型"/>
    </div>
    <a href="/images/cn/2020-03-28-pre-trained-model-for-nlp/ptms.png" itemprop="contentUrl"></a>
      <figcaption>
          <p>预训练模型分类及代表性模型</p>
      </figcaption>
  </figure>
</div>

<h3 id="应用于下游任务">应用于下游任务</h3>
<h4 id="如何迁移">如何迁移</h4>
<h5 id="选择合适的预训练任务-模型架构和语料">选择合适的预训练任务，模型架构和语料</h5>
<p>不同的 PTMs 在相同的下游任务上有着不同的效果，这是因为 PTMs 有着不同的预训练任务，模型架构和语料。</p>
<ol>
<li>目前，语言模型是最流行的预训练任务，同时也可以有效地解决很多 NLP 问题。但是不同的预训练任务有着自己的侧重，在不同的任务上会有不同的效果。例如：NSP 任务使得 PTM 可以理解两句话之间的关系，因此 PTM 可以在例如问答（Question Answering，QA）和自然语言推理（Natural Language Inference，NLI）等下游任务上表现更好。</li>
<li>PTM 的网络架构对下游任务也至关重要。例如：尽管 BERT 可以处理大多数自然语言理解任务，对其很难生成语言。</li>
<li>下游任务的数据分布应该和 PTM 训练所用语料相似。目前，大量现成的 PTM 仅可以快速地用于特定领域或特定语言的下游任务上。</li>
</ol>
<h5 id="选择合适的网络层">选择合适的网络层</h5>
<p>给定一个预训练的模型，不同的网络层捕获了不同的信息，例如：词性标记（POS tagging），语法（parsing），长期依赖（long-term dependencies），语义角色（semantic roles），指代（coreference）等。Tenney <sup id="fnref:22"><a href="#fn:22" class="footnote-ref" role="doc-noteref">22</a></sup> 等人发现 BERT 表示方式类似传统的 NLP 流程：基础的句法信息出现在浅层的网络中，高级的语义信息出现在更高的层级中。</p>
<p>令 <code>$\mathbf{H}^{\left(l\right)} \left(1 \leq l \leq L\right)$</code> 表示共 <code>$L$</code> 层的预训练模型的第 <code>$l$</code> 层表示，<code>$g \left(\cdot\right)$</code> 表示用于特定任务的的模型。一般有 3 中情况选择表示：</p>
<ol>
<li>Embedding Only：一种情况是仅选用预训练模型的静态嵌入，模型的其他部分仍需作为一个任务从头训练。这种情况不能够获取到一些有用的深层信息，词嵌入仅能够捕获词的语义信息。</li>
<li>Top Layer：最简单有效的方式是将网络的顶层表示输入到模型中 <code>$g \left(\mathbf{H}^{\left(L\right)}\right)$</code>。</li>
<li>All Layers：另一种更灵活的方式是自动选择最合适的层，例如 ELMo：
<code>$$ \mathbf{r}_t = \gamma \sum_{l=1}^{L}{\alpha_l \mathbf{h}^{\left(l\right)}_t} $$</code>
其中 <code>$\alpha_l$</code> 是层 <code>$l$</code> 的 softmax 归一的权重，<code>$\gamma$</code> 是用于缩放预训练模型输出向量的一个标量值，再将不同层的混合输出输入到后续模型中 <code>$g \left(\mathbf{r}_t\right)$</code>。</li>
</ol>
<h5 id="是否微调">是否微调</h5>
<p>目前，主要有两种方式进行模型迁移：特征提取（预训练模型的参数是固定的）和模型微调（预训练模型的参数是经过微调的）。当采用特征提取时，预训练模型可以被看作是一个特征提取器。除此之外，我们应该采用内部层作为特征，因为他们通常是最适合迁移的特征。尽管两种不同方式都能对大多数 NLP 任务效果有显著提升，但以特征提取的方式需要更复杂的特定任务的架构。因此，微调是一种更加通用和方便的处理下游任务的方式。</p>
<h4 id="微调策略">微调策略</h4>
<p>随着 PTMs 网络层数的加深，其捕获的表示使得下游任务变得越来越简单，因此整个模型中用于特定任务的网络层一般比较简单，微调已经成为了采用 PTMs 的主要方式。但是微调的过程通常是比较不好预估的，即使采用相同的超参数，不同的随机数种子也可能导致差异较大的结果。除了标准的微调外，如下为一些有用的微调策略：</p>
<h5 id="两步骤微调">两步骤微调</h5>
<p>一种方式是两阶段的迁移，在预训练和微调之间引入了一个中间阶段。在第一个阶段，PTM 通过一个中间任务或语料转换为一个微调后的模型，在第二个阶段，再利用目标任务进行微调。</p>
<h5 id="多任务微调">多任务微调</h5>
<p>在多任务学习框架下对其进行微调。</p>
<h5 id="利用额外模块进行微调">利用额外模块进行微调</h5>
<p>微调的主要缺点就是其参数的低效性。每个下游模型都有其自己微调好的参数，因此一个更好的解决方案是将一些微调好的适配模块注入到 PTMs 中，同时固定原始参数。</p>
<h3 id="开放资源">开放资源</h3>
<h4 id="ptms-开源实现">PTMs 开源实现：</h4>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th>框架</th>
          <th>PTMs</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://github.com/tmikolov/word2vec">word2vec</a></td>
          <td>-</td>
          <td>CBOW, Skip-Gram</td>
      </tr>
      <tr>
          <td><a href="https://nlp.stanford.edu/projects/glove">GloVe</a></td>
          <td>-</td>
          <td>Pre-trained word vectors</td>
      </tr>
      <tr>
          <td><a href="https://github.com/facebookresearch/fastText">FastText</a></td>
          <td>-</td>
          <td>Pre-trained word vectors</td>
      </tr>
      <tr>
          <td><a href="https://github.com/huggingface/transformers">Transformers</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i> &amp; <i class="icon icon-tensorflow">TF</i></td>
          <td>BERT, GPT-2, RoBERTa, XLNet, etc.</td>
      </tr>
      <tr>
          <td><a href="https://github.com/pytorch/fairseq">Fairseq</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i></td>
          <td>English LM, German LM, RoBERTa, etc.</td>
      </tr>
      <tr>
          <td><a href="https://github.com/%EF%AC%82airNLP/%EF%AC%82air">Flair</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i></td>
          <td>BERT, ELMo, GPT, RoBERTa, XLNet, etc.</td>
      </tr>
      <tr>
          <td><a href="https://github.com/allenai/allennlp">AllenNLP</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i></td>
          <td>ELMo, BERT, GPT-2, etc.</td>
      </tr>
      <tr>
          <td><a href="https://github.com/fastnlp/fastNLP">FastNLP</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i></td>
          <td>BERT, RoBERTa, GPT, etc.</td>
      </tr>
      <tr>
          <td><a href="https://github.com/ymcui/Chinese-BERT-wwm">Chinese-BERT</a></td>
          <td>-</td>
          <td>BERT, RoBERTa, etc. (for Chinese)</td>
      </tr>
      <tr>
          <td><a href="https://github.com/google-research/bert">BERT</a></td>
          <td><i class="icon icon-tensorflow">TF</i></td>
          <td>BERT, BERT-wwm</td>
      </tr>
      <tr>
          <td><a href="https://github.com/pytorch/fairseq/tree/master/examples/roberta">RoBERTa</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i></td>
          <td></td>
      </tr>
      <tr>
          <td><a href="https://github.com/zihangdai/xlnet">XLNet</a></td>
          <td><i class="icon icon-tensorflow">TF</i></td>
          <td></td>
      </tr>
      <tr>
          <td><a href="https://github.com/google-research/ALBERT">ALBERT</a></td>
          <td><i class="icon icon-tensorflow">TF</i></td>
          <td></td>
      </tr>
      <tr>
          <td><a href="https://github.com/google-research/text-to-text-transfer-transformer">T5</a></td>
          <td><i class="icon icon-tensorflow">TF</i></td>
          <td></td>
      </tr>
      <tr>
          <td><a href="https://github.com/thunlp/ERNIE">ERNIE(THU)</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i></td>
          <td></td>
      </tr>
      <tr>
          <td><a href="https://github.com/PaddlePaddle/ERNIE">ERNIE(Baidu)</a></td>
          <td><i class="icon icon-paddlepaddle"></i> PaddlePaddle</td>
          <td></td>
      </tr>
      <tr>
          <td><a href="https://github.com/huggingface/transformers">Hugging Face</a></td>
          <td><i class="icon icon-pytorch">PyTorch</i> &amp; <i class="icon icon-tensorflow">TF</i></td>
          <td>很多&hellip;</td>
      </tr>
  </tbody>
</table>
<h4 id="论文列表和-ptms-相关资源">论文列表和 PTMs 相关资源：</h4>
<table>
  <thead>
      <tr>
          <th>资源</th>
          <th>URL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>论文列表</td>
          <td><a href="https://github.com/thunlp/PLMpapers">https://github.com/thunlp/PLMpapers</a></td>
      </tr>
      <tr>
          <td>论文列表</td>
          <td><a href="https://github.com/tomohideshibata/BERT-related-papers">https://github.com/tomohideshibata/BERT-related-papers</a></td>
      </tr>
      <tr>
          <td>论文列表</td>
          <td><a href="https://github.com/cedrickchee/awesome-bert-nlp">https://github.com/cedrickchee/awesome-bert-nlp</a></td>
      </tr>
      <tr>
          <td>Bert Lang Street</td>
          <td><a href="https://bertlang.unibocconi.it">https://bertlang.unibocconi.it</a></td>
      </tr>
      <tr>
          <td>BertViz</td>
          <td><a href="https://github.com/jessevig/bertviz">https://github.com/jessevig/bertviz</a></td>
      </tr>
  </tbody>
</table>
<h2 id="预训练模型">预训练模型</h2>
<h3 id="cove-2017">CoVe (2017) <sup id="fnref1:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></h3>
<p>首先，给定一个源语言序列 <code>$w^x = \left[w^x_1, \dotsc, w^x_n\right]$</code> 和一个翻译目标语言序列 <code>$w^z = \left[w^z_1, \dotsc, w^z_n\right]$</code>。令 <code>$\text{GloVe} \left(w^x\right)$</code> 为词 <code>$w^x$</code> 对应的 GloVe 向量，<code>$z$</code> 为 <code>$w^z$</code> 中的词随机初始化的词向量。将 <code>$\text{GloVe} \left(w^x\right)$</code> 输入到一个标准的两层 biLSTM 网络中，称之为 MT-LSTM，MT-LSTM 用于计算序列的隐含状态如下：</p>
<p><code>$$ h = \text{MT-LSTM} \left(\text{GloVe} \left(w^x\right)\right) $$</code></p>
<p>对于机器翻译，MT-LSTM 的注意力机制的解码器可以对于输出的词在每一步产生一个分布 <code>$p \left(\hat{w}^z_t \mid H, w^z_1, \dotsc, w^z_{t-1}\right)$</code>。在 <code>$t$</code> 步，解码器利用一个两层的单向 LSTM 基于之前目标词嵌入 <code>$z_{t-1}$</code> 和一个基于上下文调整的隐含状态 <code>$\tilde{h}_{t-1}$</code> 生成一个隐含状态 <code>$h^{\text{dec}}_t$</code>：</p>
<p><code>$$ h^{\text{dec}}_t = \text{LSTM} \left(\left[z_{t-1}; \tilde{h}_{t-1}\right], h^{\text{dec}}_{t-1}\right) $$</code></p>
<p>之后解码器计算每一步编码到当前解码状态的注意力权重 <code>$\alpha$</code>：</p>
<p><code>$$ \alpha_t = \text{softmax} \left(H \left(W_1 h^{\text{dec}}_t + b_1\right)\right) $$</code></p>
<p>其中 <code>$H$</code> 表示 <code>$h$</code> 按照时间维度的堆叠。之后解码器将这些权重作为相关性用于计算基于上下文调整的隐含状态 <code>$\tilde{h}$</code>：</p>
<p><code>$$ \tilde{h}_t = \text{tanh} \left(W_2 \left[H^{\top} \alpha_t; h^{\text{dec}}_t\right] + b_2\right) $$</code></p>
<p>最后，输出词的分布通过基于上下文调整的隐含状态计算可得：</p>
<p><code>$$ p \left(\hat{w}^z_t \mid H, w^z_1, \dotsc, w^z_{t-1}\right) = \text{softmax} \left(W_{\text{out}} \tilde{h}_t + b_{\text{out}}\right) $$</code></p>
<p>CoVe 将 MT-LSTM 学习到的表示迁移到下游任务中，令 <code>$w$</code> 表示文字序列，<code>$\text{GloVe} \left(w\right)$</code> 表示对应的 GloVe 向量，则：</p>
<p><code>$$ \text{CoVe} \left(w\right) = \text{MT-LSTM} \left(\text{GloVe} \left(w\right)\right) $$</code></p>
<p>表示由 MT-LSTM 产生的上下文向量，对于分类和问答任务，有一个输入序列 <code>$w$</code>，我们可以将 GloVe 和 CoVe 向量进行拼接作为其嵌入表示：</p>
<p><code>$$ \tilde{w} = \left[\text{GloVe} \left(w\right); \text{CoVe} \left(w\right)\right] $$</code></p>
<p>CoVe 网络架构示意图如下：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/cove.png" class="lazyload"/>
  
</figure>
<h3 id="elmo-2018">ELMo (2018) <sup id="fnref1:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></h3>
<p>在 ELMo 模型中，对于每个词条 <code>$t_k$</code>，一个 <code>$L$</code> 层的 biLM 可以计算得到 <code>$2L + 1$</code> 个表示：</p>
<p><code>$$ \begin{aligned} R_k &amp;= \left\{\mathbf{x}^{LM}_k, \overrightarrow{\mathbf{h}}^{LM}_{k, j}, \overleftarrow{\mathbf{h}}^{LM}_{k, j} \mid j = 1, \dotsc, L \right\} \\ &amp;= \left\{\mathbf{h}^{LM}_{k, j} \mid j = 0, \dotsc, L\right\} \end{aligned} $$</code></p>
<p>其中 <code>$\mathbf{h}^{LM}_{k, 0}$</code> 为词条的嵌入层，<code>$\mathbf{h}^{LM}_{k, j} = \left[\overrightarrow{\mathbf{h}}^{LM}_{k, j}; \overleftarrow{\mathbf{h}}^{LM}_{k, j}\right]$</code> 为每个 biLSTM 层。</p>
<p>对于下游任务，ELMo 将 <code>$R$</code> 中的所有层汇总成一个向量 <code>$\mathbf{ELMo}_k = E \left(R_k; \mathbf{\Theta}_e\right)$</code>。在一些简单的案例中，ELMo 仅选择顶层，即：<code>$E \left(R_k\right) = \mathbf{h}^{LM}_{k, L}$</code>。更通用的，对于一个特定的任务，我们可以计算一个所有 biLM 层的加权：</p>
<p><code>$$ \mathbf{ELMo}^{task}_k = E \left(R_k; \Theta^{task}\right) = \gamma^{task} \sum_{j=0}^{L}{s^{task}_j \mathbf{h}^{LM}_{k, j}} $$</code></p>
<p>其中，<code>$s^{task}$</code> 表示 softmax 归一化后的权重，<code>$\gamma^{task}$</code> 允许模型对整个 ELMo 向量进行缩放。<code>$\gamma$</code> 对整个优化过程具有重要意义，考虑每个 biLM 层的激活具有不同的分布，在一些情况下这相当于在进行加权之前对每一个 biLM 层增加了层标准化。</p>
<p>ELMo 网络架构示意图如下 <sup id="fnref:23"><a href="#fn:23" class="footnote-ref" role="doc-noteref">23</a></sup>：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/elmo.png" class="lazyload"/>
  
</figure>
<h3 id="gpt-2018">GPT (2018) <sup id="fnref1:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></h3>
<p>给定一个语料 <code>$\mathcal{U} = \left\{u_1, \dotsc, u_n\right\}$</code>，使用标准的语言建模目标来最大化如下似然：</p>
<p><code>$$ L_1 \left(\mathcal{U}\right) = \sum_{i} \log P \left(u_i \mid u_{i-k}, \dotsc, u_{i-1}; \Theta\right) $$</code></p>
<p>其中，<code>$k$</code> 为上下文窗口的大小，条件概率 <code>$P$</code> 通过参数为 <code>$\Theta$</code> 的神经网络进行建模。GPT 中使用了一个多层的 Transformer Decoder 作为语言模型。模型首先对输入上下文词条应用多头自注意力机制，再通过按位置的前馈层产生目标词条的输出分布：</p>
<p><code>$$ \begin{aligned} h_0 &amp;= UW_e + W_p \\ h_l &amp;= \text{transformer_black} \left(h_{l-1}\right), \forall i \in \left[1, n\right] \\ P \left(u\right) &amp;= \text{softmax} \left(h_n W^{\top}_e\right) \end{aligned} $$</code></p>
<p>其中，<code>$U = \left(u_{-k}, \dotsc, u_{-1}\right)$</code> 为词条的上下文向量，<code>$n$</code> 为网络层数，<code>$W_e$</code> 为词条的嵌入矩阵，<code>$W_p$</code> 为位置嵌入矩阵。</p>
<p>给定一个有标签的数据集 <code>$\mathcal{C}$</code>，其中包含了输入词条序列 <code>$x^1, \dotsc, x^m$</code> 和对应的标签 <code>$y$</code>。利用上述预训练的模型获得输入对应的最后一个 Transformer 的激活输出 <code>$h^m_l$</code>，之后再将其输入到一个参数为 <code>$W_y$</code> 的线性输入层中预测 <code>$y$</code>：</p>
<p><code>$$ P \left(y \mid x^1, \dotsc, x^m\right) = \text{softmax} \left(h^m_l W_y\right) $$</code></p>
<p>模型通过最小化如下损失进行优化：</p>
<p><code>$$ L_2 \left(\mathcal{C}\right) = \sum_{\left(x, y\right)} \log P \left(y \mid x^1, \dotsc, x^m\right) $$</code></p>
<p>研究还发现将语言建模作为微调的附加目标可以帮助提高模型的泛化能力，同时可以加速模型收敛。GPT 中采用如下的优化目标：</p>
<p><code>$$ L_3 \left(\mathcal{C}\right) = L_2 \left(\mathcal{C}\right) + \lambda L_1 \left(\mathcal{C}\right) $$</code></p>
<p>GPT 网络架构示意图如下：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/gpt.png" class="lazyload"/>
  
</figure>
<h3 id="bert-2018">BERT (2018) <sup id="fnref1:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></h3>
<p>BERT 采用了一中基于 Vaswani <sup id="fnref1:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup> 所提出模型的多层双向 Transformer 编码器。在 BERT 中，令 <code>$L$</code> 为 Transformer Block 的层数，<code>$H$</code> 为隐层大小，<code>$A$</code> 为自注意力头的数量。在所有情况中，设置前馈层的大小为 <code>$4H$</code>，BERT 提供了两种不同大小的预训练模型：</p>
<ul>
<li><code>$\text{BERT}_{\text{BASE}}$</code>：<code>$L=12, H=768, A=12$</code>，参数总量为 100 M。</li>
<li><code>$\text{BERT}_{\text{LARGE}}$</code>：<code>$L=24, H=1024, A=16$</code>，参数总量为 340 M。</li>
</ul>
<p><code>$\text{BERT}_{\text{BASE}}$</code> 采用了同 GPT 相同的模型大小用于比较，不同与 GPT，BERT 使用了双向的注意力机制。在文献中，双向 Transformer 通常称之为 Transformer 编码器，仅利用左边上下文信息的 Transformer 由于可以用于文本生成被称之为 Transformer 解码器。BERT，GPT 和 ELMo 之间的不同如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/bert-gpt-elmo-model-architectures.png" class="lazyload"/>
  
</figure>
<p>BERT 的输入表示既可以表示一个单独的文本序列，也可以表示一对文本序列（例如：问题和答案）。对于一个给定的词条，其输入表示由对应的词条嵌入，分割嵌入和位置嵌入三部分加和构成，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/bert-input-representation.png" class="lazyload"/>
  
</figure>
<p>具体的有：</p>
<ul>
<li>采用一个包含 30,000 个词条的 WordPiece 嵌入 <sup id="fnref:24"><a href="#fn:24" class="footnote-ref" role="doc-noteref">24</a></sup>。</li>
<li>位置嵌入最大支持 512 个词条。</li>
<li>序列的第一字符采用特殊的分类嵌入 <code>[CLS]</code>，其最终的隐含状态在分类任务中用于汇总整个序列的表示，对于非分类任务则忽视该向量。</li>
<li>句子对被整合成一个序列，首先利用一个特殊词条 <code>[SEP]</code> 对句子进行分割，其次对于第一个句子中的每个词条叠加一个学习到的 A 句子嵌入，对于第二个句子中的每个词条叠加一个学习到的 B 句子嵌入。</li>
<li>对于一个单独的句子，仅使用 A 句子嵌入。</li>
</ul>
<p>在预训练阶段，BERT 采用了两个无监督预测任务：</p>
<ol>
<li>遮罩的语言模型（Masked LM，MLM）<br>
不同于一般的仅利用 <code>[MASK]</code> 进行遮挡，BERT 选择采用 80% 的 <code>[MASK]</code>，10% 的随机词和 10% 保留原始词的方式对随机选择的 15% 的词条进行遮挡处理。由于编码器不知会预测哪个词或哪个词被随机替换了，这迫使其必须保留每个输入词条的分布式上下文表示。同时 1.5% 的随机替换也不会过多的损害模型的理解能力。</li>
<li>预测是否为下一个句子（Next Sentence Prediction）<br>
一些重要的下游任务，例如问答（Question Answering，QA）和自然语言推断（Natural Language Inference，NLI）是基于两个句子之间关系的理解，这是语言建模无法直接捕获的。BERT 通过训练一个预测是否为下一个句子的二分类任务来实现，对于一个句子对 A 和 B，50% 的 B 是句子 A 真实的下一句，剩余 50% 为随机抽取的。</li>
</ol>
<p>基于 BERT 的不同下游任务的实现形式如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/bert-task-specific-models.png" class="lazyload"/>
  
</figure>
<h3 id="unilm-2019">UniLM (2019) <sup id="fnref:25"><a href="#fn:25" class="footnote-ref" role="doc-noteref">25</a></sup></h3>
<p>给定一个输入序列 <code>$x = x_1 \cdots x_{|x|}$</code>，UniLM 通过下图的方式获取每个词条的基于上下文的向量表示。整个预训练过程利用单向的语言建模（unidirectional LM），双向的语言建模（bidirectional LM）和 Seq2Seq 语言建模（sequence-to-sequence LM）优化共享的 Transformer 网络。</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/unilm.png" class="lazyload"/>
  
</figure>
<p>输入序列 <code>$x$</code> 对于单向语言模型而言是一个分割的文本，对于双向语言模型和 Seq2Seq 语言模型而言是一对打包的分割文本。UniLM 在输入的起始位置添加特殊的 <code>[SOS]</code> （start-of-sequence），在结尾处添加 <code>[EOS]</code>（end-of-sequence）。<code>[EOS]</code> 对于自然语言理解（NLU）任务可以标记句子之间的界线，对于自然语言生成（NLG）任务可以确定解码过程停止的时间。输入的表示同 BERT 一样，文本利用 WordPiece 进行分割，对于每个输入词条，其向量表示为对应的词条嵌入，位置嵌入和分割嵌入的汇总。</p>
<p>对于输入向量 <code>$\left\{\mathbf{x}_i\right\}^{|x|}_{i=1}$</code> 首先将其输入到隐层 <code>$\mathbf{H}^0 = \left[\mathbf{x}_1, \dotsc, \mathbf{x}_{|x|}\right]$</code>，之后使用一个 <code>$L$</code> 层的 Transformer <code>$\mathbf{H}^l = \text{Transformer}_l \left(\mathbf{H}^{l-1}\right), l \in \left[1, L\right]$</code> 对每一层 <code>$\mathbf{H}^l = \left[\mathbf{h}^l_1, \dotsc, \mathbf{h}^l_{|x|}\right]$</code> 进行上下文表示编码。在每个 Tansformer 块中，使用多头自注意力机制对输出向量和上一层进行汇总，第 <code>$l$</code> 层 Transformer 自注意力头 <code>$\mathbf{A}_l$</code> 的输入通过如下方式计算：</p>
<p>`$$
\begin{aligned}
\mathbf{Q} &amp;= \mathbf{H}^{l-1} \mathbf{W}^Q_l, \mathbf{K} = \mathbf{H}^{l-1} \mathbf{W}^K_l, \mathbf{V} = \mathbf{H}^{l-1} \mathbf{W}^W_l \
\mathbf{M}_{ij} &amp;=
\begin{cases}
0, &amp; \text{allow to attend} \</p>
<ul>
<li>\infty, &amp; \text{prevent from attending}
\end{cases} \
\mathbf{A}_l &amp;= \text{softmax} \left(\dfrac{\mathbf{Q} \mathbf{K}^{\top}}{\sqrt{d_k}} + \mathbf{M}\right) \mathbf{V}_l
\end{aligned}
$$`</li>
</ul>
<p>其中，上一层的输出 <code>$\mathbf{H}^{l-1} \in \mathbb{R}^{|x| \times d_h}$</code> 通过参数矩阵 <code>$\mathbf{W}^Q_l, \mathbf{W}^K_l, \mathbf{W}^V_l \in \mathbb{R}^{d_h \times d_k}$</code> 线性地映射为相应的 Query，Key 和 Value，遮罩矩阵 <code>$\mathbf{M} \in \mathbb{R}^{|x| \times |x|}$</code> 用于确定一对词条是否可以被相互连接。</p>
<h3 id="transformer-xl-2019">Transformer-XL (2019) <sup id="fnref:26"><a href="#fn:26" class="footnote-ref" role="doc-noteref">26</a></sup></h3>
<p>将 Transformer 或注意力机制应用到语言建模中的核心问题是如何训练 Transformer 使其有效地将一个任意长文本编码为一个固定长度的表示。Transformer-XL 将整个语料拆分为较短的段落，仅利用每段进行训练并忽略之前段落的上下文信息。这种方式称之为 Vanilla Model <sup id="fnref:27"><a href="#fn:27" class="footnote-ref" role="doc-noteref">27</a></sup>，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/transformer-xl-vanilla-model.png" class="lazyload"/>
  
</figure>
<p>在这种训练模式下，无论是前向还是后向信息都不会跨越分割的段落进行传导。利用固定长度的上下文主要有两个弊端：</p>
<ol>
<li>这限制了最大依赖的长度，虽然自注意力机制不会像 RNN 一样受到梯度弥散的影响，但 Vanilla Model 也不能完全利用到这个优势。</li>
<li>虽然可以利用补全操作来实现句子或其他语义的分割，但实际上通常会简单的将一个长文本截断成一个固定长度的分割，这样会产生上下文分裂破碎的问题。</li>
</ol>
<p>为了解决这个问题，Transformer-XL 采用了一种循环机制的 Transformer。在训练阶段，在处理新的分割段落时，之前分割分部分的隐含状态序列将被**固定（fixed）<strong>和</strong>缓存（cached）**下来作为一个扩展的上下文被复用参与计算，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/transformer-xl-model.png" class="lazyload"/>
  
</figure>
<p>虽然梯度仍仅限于这个分割段落内部，但网络可以从历史中获取信息，从而实现对长期依赖的建模。令两个长度为 <code>$L$</code> 的连续分割段落为 <code>$\mathbf{s}_{\tau} = \left[x_{\tau, 1}, \dotsc, x_{\tau, L}\right]$</code> 和 <code>$\mathbf{s}_{\tau + 1} = \left[x_{\tau + 1, 1}, \dotsc, x_{\tau + 1, L}\right]$</code>，第 <code>$\tau$</code> 段分割 <code>$\mathbf{s}_{\tau}$</code> 的第 <code>$n$</code> 层隐含状态为 <code>$\mathbf{h}^n_{\tau} \in \mathbb{R}^{L \times d}$</code>，其中 <code>$d$</code> 为隐含维度。则对于分割段落 <code>$\mathbf{s}_{\tau + 1}$</code> 的第 <code>$n$</code> 层隐含状态通过如下方式进行计算：</p>
<p><code>$$ \begin{aligned} \tilde{\mathbf{h}}^{n-1}_{\tau + 1} &amp;= \left[\text{SG} \left(\mathbf{h}^{n-1}_{\tau}\right) \circ \mathbf{h}^{n-1}_{\tau + 1} \right] \\ \mathbf{q}^{n}_{\tau + 1}, \mathbf{k}^{n}_{\tau + 1}, \mathbf{v}^{n}_{\tau + 1} &amp;= \mathbf{h}^{n-1}_{\tau + 1} \mathbf{W}^{\top}_{q}, \tilde{\mathbf{h}}^{n-1}_{\tau + 1} \mathbf{W}^{\top}_{k}, \tilde{\mathbf{h}}^{n-1}_{\tau + 1} \mathbf{W}^{\top}_{v} \\ \mathbf{h}^{n}_{\tau + 1} &amp;= \text{Transformer-Layer} \left(\mathbf{q}^{n}_{\tau + 1}, \mathbf{k}^{n}_{\tau + 1}, \mathbf{v}^{n}_{\tau + 1}\right) \end{aligned} $$</code></p>
<p>其中，<code>$\text{SG} \left(\cdot\right)$</code> 表示停止梯度，<code>$\left[\mathbf{h}_u \circ \mathbf{h}_v\right]$</code> 表示将两个隐含序列按照长度维度进行拼接，<code>$\mathbf{W}$</code> 为模型的参数。与一般的 Transformer 相比，最大的不同在于 <code>$\mathbf{k}^n_{\tau + 1}$</code> 和 <code>$\mathbf{v}^n_{\tau + 1}$</code> 不仅依赖于 <code>$\tilde{\mathbf{h}}^{n-1}_{\tau - 1}$</code> 还依赖于之前分割段落的 <code>$\mathbf{h}^{n-1}_{\tau}$</code> 缓存。</p>
<p>在标准的 Transformer 中，序列的顺序信息通过位置嵌入 <code>$\mathbf{U} \in \mathbb{R}^{L_{\max} \times d}$</code> 提供，其中第 <code>$i$</code> 行 <code>$\mathbf{U}_i$</code> 对应一个分割文本内部的第 <code>$i$</code> 个<strong>绝对</strong>位置，<code>$L_{\max}$</code> 为最大可能长度。在 Transformer-XL 中则是通过一种<strong>相对</strong>位置信息对其进行编码，构建一个相对位置嵌入 <code>$\mathbf{R} \in \mathbb{R} ^{L_{\max} \times d}$</code>，其中第 <code>$i$</code> 行 <code>$\mathbf{R}_i$</code> 表示两个位置之间相对距离为 <code>$i$</code> 的嵌入表示。</p>
<p>对于一般的 Transformer，一个分割段落内部的 <code>$q_i$</code> 和 <code>$k_j$</code> 之间的注意力分数可以分解为：</p>
<p><code>$$ \begin{aligned} \mathbf{A}_{i, j}^{\mathrm{abs}} &amp;=\underbrace{\mathbf{E}_{x_{i}}^{\top} \mathbf{W}_{q}^{\top} \mathbf{W}_{k} \mathbf{E}_{x_{j}}}_{(a)}+\underbrace{\mathbf{E}_{x_{i}}^{\top} \mathbf{W}_{q}^{\top} \mathbf{W}_{k} \mathbf{U}_{j}}_{(b)} \\ &amp;+\underbrace{\mathbf{U}_{i}^{\top} \mathbf{W}_{q}^{\top} \mathbf{W}_{k} \mathbf{E}_{x_{j}}}_{(c)}+\underbrace{\mathbf{U}_{i}^{\top} \mathbf{W}_{q}^{\top} \mathbf{W}_{k} \mathbf{U}_{j}}_{(d)} \end{aligned} $$</code></p>
<p>利用相对位置思想，变化如下：</p>
<p><code>$$ \begin{aligned} \mathbf{A}_{i, j}^{\mathrm{rel}} &amp;=\underbrace{\mathbf{E}_{x_{i}}^{\top} \mathbf{W}_{q}^{\top} \mathbf{W}_{k, E} \mathbf{E}_{x_{j}}}_{(a)}+\underbrace{\mathbf{E}_{x_{i}}^{\top} \mathbf{W}_{q}^{\top} \mathbf{W}_{k, R} \textcolor{blue}{\mathbf{R}_{i-j}}}_{(b)} \\ &amp;+\underbrace{\textcolor{red}{u^{\top}} \mathbf{W}_{k, E} \mathbf{E}_{x_{j}}}_{(c)}+\underbrace{\textcolor{red}{v^{\top}} \mathbf{W}_{k, R} \textcolor{blue}{\mathbf{R}_{i-j}}}_{(d)} \end{aligned} $$</code></p>
<ol>
<li>首先，利用相对位置 <code>$\textcolor{blue}{\mathbf{R}_{i-j}}$</code> 替代绝对位置嵌入 <code>$\mathbf{U}_j$</code>，这里 <code>$\mathbf{R}$</code> 采用的是无需学习的 sinusoid 编码矩阵 <sup id="fnref2:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup>。</li>
<li>其次，引入了一个可训练的参数 <code>$\textcolor{red}{u} \in \mathbb{R}^d$</code> 用于替换 <code>$\mathbf{U}^{\top}_i \mathbf{W}^{\top}_q$</code>。类似的，对于 <code>$\mathbf{U}^{\top} \mathbf{W}^{\top}_q$</code> 使用一个可训练的 <code>$\textcolor{red}{v} \in \mathbb{R}^d$</code> 替换。</li>
<li>最后，有意地划分了两个权重矩阵 <code>$\mathbf{W}_{k, E}$</code> 和 <code>$\mathbf{W}_{k, R}$</code> 用于生成基于内容的 Key 向量和基于位置的 Key 向量。</li>
</ol>
<p>这样，<code>$\left(a\right)$</code> 代表了基于内容的位置信息，<code>$\left(b\right)$</code> 捕获了内容无关的位置偏置，<code>$\left(c\right)$</code> 表示了一个全局的内容偏置，<code>$\left(d\right)$</code> 捕获了一个全局的位置偏置。</p>
<p>利用一个自注意力头计算 <code>$N$</code> 层的 Transformer-XL 的过程如下，对于 <code>$n = 1, \dotsc, N$</code> 有：</p>
<p><code>$$ \begin{aligned} \widetilde{\mathbf{h}}_{\tau}^{n-1}=&amp;\left[\mathrm{SG}\left(\mathbf{m}_{\tau}^{n-1}\right) \circ \mathbf{h}_{\tau}^{n-1}\right] \\ \mathbf{q}_{\tau}^{n}, \mathbf{k}_{\tau}^{n}, \mathbf{v}_{\tau}^{n}=&amp; \mathbf{h}_{\tau}^{n-1} {\mathbf{W}_{q}^{n}}^{\top}, \widetilde{\mathbf{h}}_{\tau}^{n-1} {\mathbf{W}_{k, E}^{n}}^{\top}, \widetilde{\mathbf{h}}_{\tau}^{n-1} {\mathbf{W}_{v}^{n}}^{\top} \\ \mathbf{A}_{\tau, i, j}^{n}=&amp; {\mathbf{q}_{\tau, i}^{n}}^{\top} \mathbf{k}_{\tau, j}^{n} + {\mathbf{q}_{\tau, i}^{n}}^{\top} \mathbf{W}_{k, R}^{n} \mathbf{R}_{i-j} \\ &amp;+u^{\top} \mathbf{k}_{\tau, j}+v^{\top} \mathbf{W}_{k, R}^{n} \mathbf{R}_{i-j} \\ \mathbf{a}_{\tau}^{n}=&amp; \text { Masked-Softmax }\left(\mathbf{A}_{\tau}^{n}\right) \mathbf{v}_{\tau}^{n} \\ \mathbf{o}_{\tau}^{n}=&amp; \text { LayerNorm } \left(\text{Linear}\left(\mathbf{a}_{\tau}^{n}\right)+\mathbf{h}_{\tau}^{n-1}\right) \\ \mathbf{h}_{\tau}^{n}=&amp; \text { Positionwise-Feed-Forward }\left(\mathbf{o}_{\tau}^{n}\right) \end{aligned} $$</code></p>
<h3 id="xlnet-2019">XLNet (2019) <sup id="fnref1:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup></h3>
<p>给定一个序列 <code>$\mathbf{X} = \left[x_1, \dotsc, x_T\right]$</code>，AR 语言模型通过最大化如下似然进行预训练：</p>
<p><code>$$ \max_{\theta} \quad \log p_{\theta}(\mathbf{x})=\sum_{t=1}^{T} \log p_{\theta}\left(x_{t} | \mathbf{x}_{&lt;t}\right)=\sum_{t=1}^{T} \log \frac{\exp \left(h_{\theta}\left(\mathbf{x}_{1: t-1}\right)^{\top} e\left(x_{t}\right)\right)}{\sum_{x^{\prime}} \exp \left(h_{\theta}\left(\mathbf{x}_{1: t-1}\right)^{\top} e\left(x^{\prime}\right)\right)} $$</code></p>
<p>其中，<code>$h_{\theta}\left(\mathbf{x}_{1: t-1}\right)$</code> 是由 RNNs 或 Transformer 等神经网络网络模型生成的上下文表示，<code>$e \left(x\right)$</code> 为 <code>$x$</code> 的嵌入。对于一个文本序列 <code>$\mathbf{x}$</code>，BERT 首先构建了一个遮罩的数据集 <code>$\hat{\mathbf{x}}$</code>，令被遮挡的词条为 <code>$\overline{\mathbf{x}}$</code>，通过训练如下目标来利用 <code>$\hat{\mathbf{x}}$</code> 重构 <code>$\overline{\mathbf{x}}$</code>：</p>
<p><code>$$ \max_{\theta} \quad \log p_{\theta}(\overline{\mathbf{x}} | \hat{\mathbf{x}}) \approx \sum_{t=1}^{T} m_{t} \log p_{\theta}\left(x_{t} | \hat{\mathbf{x}}\right)=\sum_{t=1}^{T} m_{t} \log \frac{\exp \left(H_{\theta}(\hat{\mathbf{x}})_{t}^{\top} e\left(x_{t}\right)\right)}{\sum_{x^{\prime}} \exp \left(H_{\theta}(\hat{\mathbf{x}})_{t}^{\top} e\left(x^{\prime}\right)\right)} $$</code></p>
<p>其中 <code>$m_t = 1$</code> 表示 <code>$x_t$</code> 是被遮挡的，<code>$H_{\theta}$</code> 是一个 Transformer 将一个长度为 <code>$T$</code> 的文本序列映射到一个隐含向量序列 <code>$H_{\theta}(\mathbf{x})=\left[H_{\theta}(\mathbf{x})_{1}, H_{\theta}(\mathbf{x})_{2}, \cdots, H_{\theta}(\mathbf{x})_{T}\right]$</code>。两种不同的预训练目标的优劣势如下</p>
<ol>
<li><strong>独立假设</strong>：BERT 中联合条件概率 <code>$p(\overline{\mathbf{x}} | \hat{\mathbf{x}})$</code> 假设在给定的 <code>$\hat{\mathbf{x}}$</code> 下，遮挡的词条 <code>$\overline{\mathbf{x}}$</code> 是相关独立的，而 AR 语言模型则没有这样的假设。</li>
<li><strong>输入噪声</strong>：BERT 在预训练是使用了特殊标记 <code>[MASK]</code>，在下游任务微调时不会出现，而 AR 语言模型则不会存在这个问题。</li>
<li><strong>上下文依赖</strong>：AR 语言模型仅考虑了词条左侧的上下文，而 BERT 则可以捕获两个方向的上下文。</li>
</ol>
<p>为了利用 AR 语言模型和 BERT 的优点，XLNet 提出了排序语言模型。对于一个长度为 <code>$T$</code> 序列 <code>$\mathbf{x}$</code>，共有 <code>$T!$</code> 种不同的方式进行 AR 分解，如果模型共享不同分解顺序的参数，那么模型就能学习到两侧所有位置的信息。令 <code>$\mathcal{Z}_T$</code> 为长度为 <code>$T$</code> 的索引序列 <code>$\left[1, 2, \dotsc, T\right]$</code> 的所有可能排列，<code>$z_t$</code> 和 <code>$\mathbf{z}_{&lt;t}$</code> 分别表示一个排列 <code>$\mathbf{z} \in \mathcal{Z}_T$</code> 第 <code>$t$</code> 个和前 <code>$t-1$</code> 个元素。则排列语言模型的优化目标为：</p>
<p><code>$$ \max_{\theta} \quad \mathbb{E}_{\mathbf{z} \sim \mathcal{Z}_{T}}\left[\sum_{t=1}^{T} \log p_{\theta}\left(x_{z_{t}} | \mathbf{x}_{\mathbf{z}_{&lt;t}}\right)\right] $$</code></p>
<p>根据标准的 Transformer，下一个词条的分布 <code>$p_{\theta}\left(X_{z_{t}} | \mathbf{x}_{\mathbf{z}&lt;t}\right)$</code> 为：</p>
<p><code>$$ p_{\theta}\left(X_{z_{t}} = x | \mathbf{x}_{\mathbf{z}&lt;t}\right)=\frac{\exp \left(e(x)^{\top} h_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}\right)\right)}{\sum_{x^{\prime}} \exp \left(e\left(x^{\prime}\right)^{\top} h_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}\right)\right)} $$</code></p>
<p>其中，<code>$h_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}\right)$</code> 表示通过共享的 Transformer 产生的 <code>$\mathbf{X}_{\mathbf{Z}&lt;t}$</code> 的隐含表示。该表示并不依赖于所预测的位置，为了避免这个问题，我们将位置 <code>$z_t$</code> 加入到模型中：</p>
<p><code>$$ p_{\theta}\left(X_{z_{t}}=x | \mathbf{x}_{z_{&lt;t}}\right)=\frac{\exp \left(e(x)^{\top} g_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}, z_{t}\right)\right)}{\sum_{x^{\prime}} \exp \left(e\left(x^{\prime}\right)^{\top} g_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}, z_{t}\right)\right)} $$</code></p>
<p>对于 <code>$g_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}, z_{t}\right)$</code> 进行建模需要满足如下两个要求：</p>
<ol>
<li>预测 <code>$x_{z_t}$</code> 时，<code>$g_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}, z_{t}\right)$</code> 只能使用位置信息 <code>$z_t$</code> 而不能使用内容信息 <code>$x_{z_t}$</code>。</li>
<li>在预测 <code>$x_{z_t}$</code> 之后的词条时，<code>$g_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}, z_{t}\right)$</code> 又必须包含 <code>$x_{z_t}$</code> 的语义信息。</li>
</ol>
<p>为了解决这个问题，XLNet 提供了两种隐含表示：</p>
<ol>
<li>内容隐含表示 <code>$h_{\theta}\left(\mathbf{x}_{\mathbf{z} \leq t}\right)$</code>，简写为 <code>$h_{z_t}$</code>，它和标准的 Transformer 一样，既编码上下文也编码 <code>$x_{z_t}$</code> 的内容。</li>
<li>查询隐含表示 <code>$g_{\theta}\left(\mathbf{x}_{\mathbf{z}&lt;t}, z_{t}\right)$</code>，简写为 <code>$g_{z_t}$</code>，它仅编码上下文信息 <code>$\mathbf{X}_{\mathbf{Z}&lt;t}$</code> 和位置信息 <code>$z_t$</code>，不编码内容 <code>$x_{z_t}$</code>。</li>
</ol>
<p>模型的整个计算过程如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/xlnet.png" class="lazyload"/>
  
</figure>
<p>虽然排列语言模型有很多优点，但是由于计算量很大，模型很难进行优化，因此我们通过仅预测一个句子后面的一些词条解决这个问题。将 <code>$\mathbf{z}$</code> 分为两部分：非目标子序列 <code>$\mathbf{z}_{\leq c}$</code> 和目标子序列 <code>$\mathbf{z}_{&gt;c}$</code>，其中 <code>$c$</code> 为切分点。同时会设置一个超参数 <code>$K$</code>，表示仅 <code>$1 / K$</code> 的词条会被预测，有 <code>$|\mathbf{z}| /(|\mathbf{z}|-c) \approx K$</code>。对于未被选择的词条，其查询隐状态无需被计算，从而节省计算时间和资源。</p>
<h3 id="mass-2019">MASS (2019) <sup id="fnref1:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></h3>
<p>MASS 是一个专门针对序列到序列的自然语言任务设计的预训练方法，对于一个给定的原始句子 <code>$x \in \mathcal{X}$</code>，令 <code>$x^{\setminus u:v}$</code> 表示将 <code>$x$</code> 从 <code>$u$</code> 到 <code>$v$</code> 位置进行遮挡处理，<code>$k = v - u + 1$</code> 为被遮挡词条的个数，<code>$x^{u:v}$</code> 为从 <code>$u$</code> 到 <code>$v$</code> 位置被遮挡的部分。MASS 利用被遮挡的序列 <code>$x^{\setminus u:v}$</code> 预测被遮挡的部分 <code>$x^{u:v}$</code>，目标函数的对数似然如下：</p>
<p><code>$$ \begin{aligned} L(\theta ; \mathcal{X}) &amp;=\frac{1}{|\mathcal{X}|} \Sigma_{x \in \mathcal{X}} \log P\left(x^{u: v} | x^{\setminus u: v} ; \theta\right) \\ &amp;=\frac{1}{|\mathcal{X}|} \Sigma_{x \in \mathcal{X}} \log \prod_{t=u}^{v} P\left(x_{t}^{u: v} | x_{&lt;t}^{u: v}, x^{\setminus u: v} ; \theta\right) \end{aligned} $$</code></p>
<p>对于一个具有 8 个词条的序列，<code>$x_3 x_4 x_5 x_6$</code> 被遮挡的示例如下：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/mass.png" class="lazyload"/>
  
</figure>
<p>模型仅预测遮挡的部分 <code>$x_3 x_4 x_5 x_6$</code>，对于解码器中位置 <code>$4-6$</code> 利用 <code>$x_3 x_4 x_5$</code> 作为输入，利用特殊遮挡符号 <code>$\left[\mathbb{M}\right]$</code> 作为其他位置的输入。对于不同长度 <code>$k$</code>，MASS 包含了上文中提到的两种预训练模型：</p>
<table>
  <thead>
      <tr>
          <th>长度</th>
          <th>概率</th>
          <th>模型</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>$k=1$</code></td>
          <td><code>$P\left(x^{u} \mid x^{\setminus u} ; \theta\right)$</code></td>
          <td>masked LM in BERT</td>
      </tr>
      <tr>
          <td><code>$k=m$</code></td>
          <td><code>$P\left(x^{1:m} \mid x^{\setminus 1:m} ; \theta\right)$</code></td>
          <td>masked LM in GPT</td>
      </tr>
      <tr>
          <td><code>$k \in \left(1, m\right)$</code></td>
          <td><code>$P\left(x^{u:v} \mid x^{\setminus u:v} ; \theta\right)$</code></td>
          <td>两种之间</td>
      </tr>
  </tbody>
</table>
<p>对于不同 <code>$k$</code> 值，实验发现当 <code>$k$</code> 处于 <code>$m$</code> 的 <code>$50\%$</code> 至 <code>$70\%$</code> 之间时下游任务性能最优。</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/mass-k.png" class="lazyload"/>
  
</figure>
<p>当 <code>$k = 0.5 m$</code> 时，MASS 可以很好地平衡编码器和解码器的预训练。过度地偏向编码器（<code>$k=1$</code>，masked LM in BERT）和过度地偏向解码器（<code>$k=m$</code>，masked LM in GPT）均不能在下游的自然语言生成任务中取得很好的效果。</p>
<h3 id="roberta-2019">RoBERTa (2019) <sup id="fnref1:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup></h3>
<p>RoBERTa 主要围绕 BERT 进行了如下改进：</p>
<ol>
<li>模型采用了动态遮罩，不同于原始 BERT 中对语料预先进行遮罩处理，RoBERTa 在 40 轮训练过程中采用了 10 种不同的遮罩。</li>
<li>模型去掉了 NSP 任务，发现可以略微提升下游任务的性能。</li>
<li>模型采用了更大的训练数据和更大的 Batch 大小。</li>
<li>原始 BERT 采用一个 30K 的 BPE 词表，RoBERTa 采用了一个更大的 50K 的词表 <sup id="fnref:28"><a href="#fn:28" class="footnote-ref" role="doc-noteref">28</a></sup>。</li>
</ol>
<h3 id="bart-2019">BART (2019) <sup id="fnref1:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup></h3>
<p>BART 采用了一个标准的 Seq2Seq Transformer 结构，类似 GPT 将 ReLU 激活函数替换为 GeLUs。对于基线模型，采用了一个 6 层的编码和解码器，对于更大模型采用了 12 层的结构。相比于 BERT 的架构主要有以下两点不同：</p>
<ol>
<li>解码器的每一层叠加了对编码器最后一个隐含层的注意力。</li>
<li>BERT 在预测之前采用了一个前馈的网络，而 BART 没有。</li>
</ol>
<p>BART 采用了最小化破坏后的文档和原始文档之间的重构误差的方式进行预训练。不同于其他的一些去噪自编码器，BART 可以使用任意类型的文档破坏方式。极端情况下，当源文档的所有信息均丢失时，BART 就等价与一个语言模型。BART 中采用的文本破坏方式有：字符遮罩，字符删除，文本填充，句子重排，文档旋转，如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/bart-transformations.png" class="lazyload"/>
  
</figure>
<h3 id="t5-2019">T5 (2019) <sup id="fnref1:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></h3>
<p>T5（Text-to-Text Transfer Transformer） 提出了一种 text-to-text 的框架，旨在利用相同的模型，损失函数和超参数等对机器翻译，文档摘要，问答和分类（例如：情感分析）等任务进行统一建模。我们甚至可以利用 T5 通过预测一个数字的文本表示而不是数字本身来建模一个回归任务。模型及其输入输出如下图所示：</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/t5-text-to-text-framework.gif" class="lazyload"/>
  
</figure>
<p>Google 的这项研究并不是提出一种新的方法，而是从全面的视角来概述当前 NLP 领域迁移学习的发展现状。T5 还公开了一个名为 C4（Colossal Clean Crawled Corpus）的数据集，该数据集是一个比 Wikipedia 大两个数量级的 Common Crawl 的清洗后版本的数据。更多模型的细节请参见源论文和 Google 的 <a href="https://ai.googleblog.com/2020/02/exploring-transfer-learning-with-t5.html">官方博客</a>。</p>
<h3 id="ernie-baidu-2019">ERNIE (Baidu, 2019) <sup id="fnref:29"><a href="#fn:29" class="footnote-ref" role="doc-noteref">29</a></sup> <sup id="fnref:30"><a href="#fn:30" class="footnote-ref" role="doc-noteref">30</a></sup></h3>
<p>ERNIE 1.0 <sup id="fnref1:29"><a href="#fn:29" class="footnote-ref" role="doc-noteref">29</a></sup> 通过建模海量数据中的词、实体及实体关系，学习真实世界的语义知识。相较于 BERT 学习原始语言信号，ERNIE 直接对先验语义知识单元进行建模，增强了模型语义表示能力。例如：</p>
<p><code>BERT ：哈 [mask] 滨是 [mask] 龙江的省会，[mask] 际冰 [mask] 文化名城。</code><br>
<code>ERNIE：[mask] [mask] [mask] 是黑龙江的省会，国际 [mask] [mask] 文化名城。</code></p>
<p>在 BERT 模型中，我们通过『哈』与『滨』的局部共现，即可判断出『尔』字，模型没有学习与『哈尔滨』相关的任何知识。而 ERNIE 通过学习词与实体的表达，使模型能够建模出『哈尔滨』与『黑龙江』的关系，学到『哈尔滨』是 『黑龙江』的省会以及『哈尔滨』是个冰雪城市。</p>
<p>训练数据方面，除百科类、资讯类中文语料外，ERNIE 还引入了论坛对话类数据，利用 DLM（Dialogue Language Model）建模 Query-Response 对话结构，将对话 Pair 对作为输入，引入 Dialogue Embedding 标识对话的角色，利用 Dialogue Response Loss 学习对话的隐式关系，进一步提升模型的语义表示能力。</p>
<p>ERNIE 2.0 <sup id="fnref1:30"><a href="#fn:30" class="footnote-ref" role="doc-noteref">30</a></sup> 是基于持续学习的语义理解预训练框架，使用多任务学习增量式构建预训练任务。ERNIE 2.0 中，新构建的预训练任务类型可以无缝的加入训练框架，持续的进行语义理解学习。 通过新增的实体预测、句子因果关系判断、文章句子结构重建等语义任务，ERNIE 2.0 语义理解预训练模型从训练数据中获取了词法、句法、语义等多个维度的自然语言信息，极大地增强了通用语义表示能力。</p>
<figure>
  <img data-src="/images/cn/2020-03-28-pre-trained-model-for-nlp/ernie-2-framework.png" class="lazyload"/>
  
</figure>
<h3 id="state-of-art">State-of-Art</h3>
<p>NLP 任务的 State-of-Art 模型详见：</p>
<ul>
<li><a href="https://gluebenchmark.com/leaderboard">GLUE Leaderboard</a></li>
<li><a href="https://super.gluebenchmark.com/leaderboard">SuperGLUE Leaderboard</a></li>
<li><a href="https://rajpurkar.github.io/SQuAD-explorer/">SQuAD</a></li>
<li><a href="https://nlpprogress.com/">NLP-progress</a></li>
<li><a href="https://www.cluebenchmarks.com/">中文任务基准测评</a></li>
</ul>


<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Qiu, X., Sun, T., Xu, Y., Shao, Y., Dai, N., &amp; Huang, X. (2020). Pre-trained Models for Natural Language Processing: A Survey. <em>ArXiv:2003.08271 [Cs]</em>. <a href="http://arxiv.org/abs/2003.08271">http://arxiv.org/abs/2003.08271</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Mikolov, T., Sutskever, I., Chen, K., Corrado, G. S., &amp; Dean, J. (2013). Distributed representations of words and phrases and their compositionality. In <em>Advances in neural information processing systems</em> (pp. 3111-3119).&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Pennington, J., Socher, R., &amp; Manning, C. D. (2014, October). Glove: Global vectors for word representation. In <em>Proceedings of the 2014 conference on empirical methods in natural language processing (EMNLP)</em> (pp. 1532-1543).&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>McCann, B., Bradbury, J., Xiong, C., &amp; Socher, R. (2017). Learned in translation: Contextualized word vectors. In <em>Advances in Neural Information Processing Systems</em> (pp. 6294-6305).&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Peters, M. E., Neumann, M., Iyyer, M., Gardner, M., Clark, C., Lee, K., &amp; Zettlemoyer, L. (2018). Deep contextualized word representations. <em>arXiv preprint arXiv:1802.05365.</em>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Radford, A., Narasimhan, K., Salimans, T., &amp; Sutskever, I. (2018). Improving language understanding by generative pre-training. <em>URL <a href="https://openai.com/blog/language-unsupervised/">https://openai.com/blog/language-unsupervised/</a></em>.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Devlin, J., Chang, M. W., Lee, K., &amp; Toutanova, K. (2018). Bert: Pre-training of deep bidirectional transformers for language understanding. <em>arXiv preprint arXiv:1810.04805.</em>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Kim, Y. (2014). Convolutional Neural Networks for Sentence Classification. In <em>Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing (EMNLP)</em> (pp. 1746-1751).&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Hochreiter, S., &amp; Schmidhuber, J. (1997). Long short-term memory. <em>Neural computation</em>, 9(8), 1735-1780.&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Chung, J., Gulcehre, C., Cho, K., &amp; Bengio, Y. (2014). Empirical evaluation of gated recurrent neural networks on sequence modeling. <em>arXiv preprint arXiv:1412.3555.</em>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Socher, R., Perelygin, A., Wu, J., Chuang, J., Manning, C. D., Ng, A. Y., &amp; Potts, C. (2013). Recursive deep models for semantic compositionality over a sentiment treebank. In <em>Proceedings of the 2013 conference on empirical methods in natural language processing</em> (pp. 1631-1642).&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Tai, K. S., Socher, R., &amp; Manning, C. D. (2015). Improved Semantic Representations From Tree-Structured Long Short-Term Memory Networks. In <em>Proceedings of the 53rd Annual Meeting of the Association for Computational Linguistics and the 7th International Joint Conference on Natural Language Processing (Volume 1: Long Papers)</em> (pp. 1556-1566).&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Marcheggiani, D., Bastings, J., &amp; Titov, I. (2018). Exploiting Semantics in Neural Machine Translation with Graph Convolutional Networks. In <em>Proceedings of the 2018 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 2 (Short Papers)</em> (pp. 486-492).&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., &hellip; &amp; Polosukhin, I. (2017). Attention is all you need. In <em>Advances in neural information processing systems</em> (pp. 5998-6008).&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>Devlin, J., Chang, M. W., Lee, K., &amp; Toutanova, K. (2019). BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. In <em>Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long and Short Papers)</em> (pp. 4171-4186).&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>Song, K., Tan, X., Qin, T., Lu, J., &amp; Liu, T. Y. (2019). MASS: Masked Sequence to Sequence Pre-training for Language Generation. In <em>International Conference on Machine Learning</em> (pp. 5926-5936).&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Raffel, C., Shazeer, N., Roberts, A., Lee, K., Narang, S., Matena, M., &hellip; &amp; Liu, P. J. (2019). Exploring the limits of transfer learning with a unified text-to-text transformer. <em>arXiv preprint arXiv:1910.1068</em>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>Liu, Y., Ott, M., Goyal, N., Du, J., Joshi, M., Chen, D., &hellip; &amp; Stoyanov, V. (2019). Roberta: A robustly optimized bert pretraining approach. <em>arXiv preprint arXiv:1907.11692.</em>&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p>Yang, Z., Dai, Z., Yang, Y., Carbonell, J., Salakhutdinov, R. R., &amp; Le, Q. V. (2019). Xlnet: Generalized autoregressive pretraining for language understanding. In <em>Advances in neural information processing systems</em> (pp. 5754-5764).&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>Lewis, M., Liu, Y., Goyal, N., Ghazvininejad, M., Mohamed, A., Levy, O., &hellip; &amp; Zettlemoyer, L. (2019). Bart: Denoising sequence-to-sequence pre-training for natural language generation, translation, and comprehension. <em>arXiv preprint arXiv:1910.13461.</em>&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:21">
<p>Saunshi, N., Plevrakis, O., Arora, S., Khodak, M., &amp; Khandeparkar, H. (2019). A Theoretical Analysis of Contrastive Unsupervised Representation Learning. In <em>International Conference on Machine Learning</em> (pp. 5628-5637).&#160;<a href="#fnref:21" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:22">
<p>Tenney, I., Das, D., &amp; Pavlick, E. (2019). BERT Rediscovers the Classical NLP Pipeline. In <em>Proceedings of the 57th Annual Meeting of the Association for Computational Linguistics</em> (pp. 4593-4601).&#160;<a href="#fnref:22" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:23">
<p>图片来源：http://www.realworldnlpbook.com/blog/improving-sentiment-analyzer-using-elmo.html&#160;<a href="#fnref:23" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:24">
<p>Wu, Y., Schuster, M., Chen, Z., Le, Q. V., Norouzi, M., Macherey, W., &hellip; &amp; Klingner, J. (2016). Google&rsquo;s neural machine translation system: Bridging the gap between human and machine translation. <em>arXiv preprint arXiv:1609.08144.</em>&#160;<a href="#fnref:24" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:25">
<p>Dong, L., Yang, N., Wang, W., Wei, F., Liu, X., Wang, Y., &hellip; &amp; Hon, H. W. (2019). Unified language model pre-training for natural language understanding and generation. In <em>Advances in Neural Information Processing Systems</em> (pp. 13042-13054).&#160;<a href="#fnref:25" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:26">
<p>Dai, Z., Yang, Z., Yang, Y., Carbonell, J. G., Le, Q., &amp; Salakhutdinov, R. (2019, July). Transformer-XL: Attentive Language Models beyond a Fixed-Length Context. In <em>Proceedings of the 57th Annual Meeting of the Association for Computational Linguistics</em> (pp. 2978-2988).&#160;<a href="#fnref:26" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:27">
<p>Al-Rfou, R., Choe, D., Constant, N., Guo, M., &amp; Jones, L. (2019). Character-level language modeling with deeper self-attention. In <em>Proceedings of the AAAI Conference on Artificial Intelligence</em> (Vol. 33, pp. 3159-3166).&#160;<a href="#fnref:27" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:28">
<p>Radford, A., Wu, J., Child, R., Luan, D., Amodei, D., &amp; Sutskever, I. (2019). Language models are unsupervised multitask learners. <em>URL <a href="https://openai.com/blog/better-language-models/">https://openai.com/blog/better-language-models/</a></em>.&#160;<a href="#fnref:28" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:29">
<p>Sun, Y., Wang, S., Li, Y., Feng, S., Chen, X., Zhang, H., &hellip; &amp; Wu, H. (2019). Ernie: Enhanced representation through knowledge integration. <em>arXiv preprint arXiv:1904.09223.</em>&#160;<a href="#fnref:29" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:29" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:30">
<p>Sun, Y., Wang, S., Li, Y., Feng, S., Tian, H., Wu, H., &amp; Wang, H. (2019). Ernie 2.0: A continual pre-training framework for language understanding. <em>arXiv preprint arXiv:1907.12412.</em>&#160;<a href="#fnref:30" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:30" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]></description></item><item><title>序列到序列 (Seq2Seq) 和注意力机制 (Attention Machanism)</title><link>https://zeqiang.fun/cn/2018/10/seq2seq-and-attention-machanism/</link><pubDate>Fri, 12 Oct 2018 00:00:00 +0000</pubDate><guid>https://zeqiang.fun/cn/2018/10/seq2seq-and-attention-machanism/</guid><description><![CDATA[
        <h2 id="encoder-decoder-seq2seq">Encoder-Decoder &amp; Seq2Seq</h2>
<p>Encoder-Decoder 是一种包含两个神经网络的模型，两个网络分别扮演编码器和解码器的角色。Cho 等人 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> 提出了一个基于 RNN 的 Encoder-Decoder 神经网络用于机器翻译。网络结构如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/rnn-encoder-decoder.png" alt="RNN-Encoder-Decoder"></p>
<p>整个模型包含编码器 (Encoder) 和解码器 (Decoder) 两部分：Encoder 将一个可变长度的序列转换成为一个固定长度的向量表示，Decoder 再将这个固定长度的向量表示转换为一个可变长度的序列。这使得模型可以处理从一个可变长度序列到另一个可变长度序例的转换，即学习到对应的条件概率 <code>$p \left(y_1, \dotsc, y_{T'} | x_1, \dotsc, x_T\right)$</code>，其中 <code>$T$</code> 和 <code>$T'$</code> 可以为不同的值，也就是说输入和输出的序列的长度不一定相同。</p>
<p>在模型中，Encoder 为一个 RNN，逐次读入输入序列 <code>$\mathbf{x}$</code> 中的每个元素，其中 RNN 隐状态的更新方式如下：</p>
<p><code>$$ \mathbf{h}_{\langle t \rangle} = f \left(\mathbf{h}_{\langle t-1 \rangle}, x_t\right) $$</code></p>
<p>在读入序列的最后一个元素后 (通常为一个结束标记)，RNN 的隐状态则为整个输入序列的概括信息 <code>$\mathbf{c}$</code>。Decoder 为另一个 RNN，用于根据隐状态 <code>$\mathbf{h}'_{\langle t \rangle}$</code> 预测下一个元素 <code>$y_t$</code>，从而生成整个输出序列。不同于 Encoder 中的 RNN，Decoder 中 RNN 的隐状态 <code>$\mathbf{h}'_{\langle t \rangle}$</code> 除了依赖上一个隐含层的状态和之前的输出外，还依赖整个输入序列的概括信息 <code>$\mathbf{c}$</code>，即：</p>
<p><code>$$ \mathbf{h}'_{\langle t \rangle} = f \left(\mathbf{h}'_{\langle t-1 \rangle}, y_{t-1}, \mathbf{c}\right) $$</code></p>
<p>类似的，下一个输出元素的条件分布为：</p>
<p><code>$$ P \left(y_t | y_{t-1}, y_{t-2}, \dotsc, y_1, \mathbf{c}\right) = g \left(\mathbf{h}_{\langle t \rangle}, y_{t-1}, \mathbf{c}\right) $$</code></p>
<p>RNN Encoder-Decoder 的两部分通过最大化如下的对数似然函数的联合训练进行优化：</p>
<p><code>$$ \max_{\theta} \dfrac{1}{N} \sum_{n=1}^{N}{\log p_{\theta} \left(\mathbf{y}_n | \mathbf{x}_n\right)} $$</code></p>
<p>其中，<code>$\theta$</code> 为模型的参数，<code>$\mathbf{x}_n$</code> 和 <code>$\mathbf{y}_n$</code> 分别为输入和输出序列的成对样本。当模型训练完毕后，我们可以利用模型根据给定的输入序列生成相应的输出序列，或是根据给定的输入和输出序列对计算概率得分 <code>$p_{\theta} \left(\mathbf{y} | \mathbf{x}\right)$</code>。同时，作者还提出了一种新的 RNN 单元 GRU (Gated Recurrent Unit)，有关 GRU 的更多介绍请参见 <a href="/cn/2018/09/rnn">之前的博客</a>。</p>
<p>序列到序列 (Sequence to Sequence, Seq2Seq) 模型从名称中不难看出来是一种用于处理序列数据到序列数据转换问题 (例如：机器翻译等) 的方法。Sutskever 等人 <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> 提出了一种基于 Encoder-Decoder 网络结构的 Seq2Seq 模型用于机器翻译，网络结构细节同 RNN Encoder-Decoder 略有不同，如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/seq2seq.png" alt="Seq2Seq"></p>
<p>模型的相关细节如下：</p>
<ol>
<li>对数据进行预处理，在每个句子的结尾添加特殊字符 <code>&lt;EOS&gt;</code>，如上图所示。首先计算 <code>A, B, C, &lt;EOS&gt;</code> 的表示，再利用该表示计算 <code>W, X, Y, Z, &lt;EOS&gt;</code> 的条件概率。</li>
<li>利用两个不同的 LSTM，一个用于输入序列，另一个用于输出序列。</li>
<li>选用一个较深的 LSTM 模型 (4 层) 提升模型效果。</li>
<li>对输入序列进行倒置处理，例如对于输入序列 <code>$a, b, c$</code> 和对应的输出序列 <code>$\alpha, \beta, \gamma$</code>，LSTM 需要学习的映射关系为 <code>$c, b, a \to \alpha, \beta, \gamma$</code>。</li>
</ol>
<p>在模型的解码阶段，模型采用简单的从左到右的 Beam Search，该方法维护一个大小为 <code>$B$</code> 的集合保存最好的结果。下图展示了 <code>$B = 2$</code> 情况下 Beam Search 的具体工作方式：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/beam-search.png" alt="Beam-Search"></p>
<p>其中，红色的虚线箭头表示每一步可能的搜索方向，绿色的实线箭头表示每一步概率为 Top <code>$B$</code> 的方向。例如，从 S 开始搜索：</p>
<ol>
<li>第一步搜索的可能结果为 SA 和 SB，保留 Top 2，结果为 SA 和 SB。</li>
<li>第二步搜索的可能结果为 SAC，SAD，SBE 和 SBF，保留 Top 2，结果为 SAC 和 SBE。</li>
<li>第三步搜索的可能结果为 SACG，SACH，SBEK 和 SBEL，保留 Top 2，结果为 SACH 和 SBEK。至此，整个搜索结束。</li>
</ol>
<p>Bahdanau 等人 <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> 提出了一种基于双向 RNN (Bidirectional RNN, BiRNN) 结合注意力机制 (Attention Mechanism) 的网络结构用于机器翻译。网络结构如下：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/seq2seq-birnn-attention.png" alt="Seq2Seq-BiRNN-Attention"></p>
<p>模型的编码器使用了一个双向的 RNN，前向的 RNN <code>$\overrightarrow{f}$</code> 以从 <code>$x_1$</code> 到 <code>$x_T$</code> 的顺序读取输入序列并计算前向隐状态 <code>$\left(\overrightarrow{h}_1, \dotsc, \overrightarrow{h}_T\right)$</code>，后向的 RNN <code>$\overleftarrow{f}$</code> 以从 <code>$x_T$</code> 到 <code>$x_1$</code> 的顺序读取输入序列并计算后向隐状态 <code>$\left(\overleftarrow{h}_1, \dotsc, \overleftarrow{h}_T\right)$</code>。对于一个词 <code>$x_j$</code>，通过将对应的前向隐状态 <code>$\overrightarrow{h}_j$</code> 和后向隐状态 <code>$\overleftarrow{h}_j$</code> 进行拼接得到最终的隐状态 <code>$h_j = \left[\overrightarrow{h}_j^{\top}; \overleftarrow{h}_j^{\top}\right]^{\top}$</code>。这样的操作使得隐状态 <code>$h_j$</code> 既包含了前面词的信息也包含了后面词的信息。</p>
<p>在模型的解码器中，对于一个给定的序例 <code>$\mathbf{x}$</code>，每一个输出的条件概率为：</p>
<p><code>$$ p \left(y_i | y_1, \dotsc, y_{i-1}, \mathbf{x}\right) = g \left(y_{i-1}, s_i, c_i\right) $$</code></p>
<p>其中，<code>$s_i$</code> 为 <code>$i$</code> 时刻 RNN 隐含层的状态，即：</p>
<p><code>$$ s_i = f \left(s_{i-1}, y_{i-1}, c_i\right) $$</code></p>
<p>这里需要注意的是不同于之前的 Encoder-Decoder 模型，此处每一个输出词 <code>$y_i$</code> 的条件概率均依赖于一个单独的上下文向量 <code>$c_i$</code>。该部分的改进即结合了注意力机制，有关注意力机制的详细内容将在下个小节中展开说明。</p>
<h2 id="注意力机制-attention-mechanism">注意力机制 (Attention Mechanism)</h2>
<p>Bahdanau 等人在文中 <sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> 提出传统的 Encoder-Decoder 模型将输入序列压缩成一个固定长度的向量 <code>$c$</code>，但当输入的序例很长时，尤其是当比训练集中的语料还长时，模型的的效果会显著下降。针对这个问题，如上文所述，上下文向量 <code>$c_i$</code> 依赖于 <code>$\left(h_1, \dotsc, h_T\right)$</code>。其中，每个 <code>$h_i$</code> 都包含了整个序列的信息，同时又会更多地关注第 <code>$i$</code> 个词附近的信息。对于 <code>$c_i$</code>，计算方式如下：</p>
<p><code>$$ c_i = \sum_{j=1}^{T}{\alpha_{ij} h_j} $$</code></p>
<p>对于每个 <code>$h_j$</code> 的权重 <code>$\alpha_{ij}$</code>，计算方式如下：</p>
<p><code>$$ \alpha_{ij} = \dfrac{\exp \left(e_{ij}\right)}{\sum_{k=1}^{T}{\exp \left(e_{ik}\right)}} $$</code></p>
<p>其中，<code>$e_{ij} = a \left(s_{i-1}, h_j\right)$</code> 为一个 Alignment 模型，用于评价对于输入的位置 <code>$j$</code> 附近的信息与输出的位置 <code>$i$</code> 附近的信息的匹配程度。Alignment 模型 <code>$a$</code> 为一个用于评分的前馈神经网络，与整个模型进行联合训练，计算方式如下：</p>
<p><code>$$ a \left(s_{i-1}, h_j\right) = v_a^{\top} \tanh \left(W_a s_{i-1} + U_a h_j\right) $$</code></p>
<p>其中，<code>$W_a \in \mathbb{R}^{n \times n}, U_a \in \mathbb{R}^{n \times 2n}，v_a \in \mathbb{R}^n$</code> 为网络的参数。</p>
<h3 id="hard-soft-attention">Hard &amp; Soft Attention</h3>
<p>Xu 等人 <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> 在图像标题生成 (Image Caption Generation) 任务中引入了注意力机制。在文中作者提出了 Hard Attenttion 和 Soft Attention 两种不同的注意力机制。</p>
<p>对于 Hard Attention 而言，令 <code>$s_t$</code> 表示在生成第 <code>$t$</code> 个词时所关注的位置变量，<code>$s_{t, i} = 1$</code> 表示当第 <code>$i$</code> 个位置用于提取视觉特征。将注意力位置视为一个中间潜变量，可以以一个参数为 <code>$\left\{\alpha_i\right\}$</code> 的多项式分布表示，同时将上下文向量 <code>$\hat{\mathbf{z}}_t$</code> 视为一个随机变量：</p>
<p><code>$$ \begin{equation} \begin{split} &amp; p \left(s_{t, i} = 1 | s_{j &lt; t}, \mathbf{a}\right) = \alpha_{t, i} \\ &amp; \hat{\mathbf{z}}_t = \sum_{i}{s_{t, i} \mathbf{a}_i} \end{split} \end{equation} $$</code></p>
<p>因此 Hard Attention 可以依据概率值从隐状态中进行采样计算得到上下文向量，同时为了实现梯度的反向传播，需要利用蒙特卡罗采样的方法来估计梯度。</p>
<p>对于 Soft Attention 而言，则直接计算上下文向量 <code>$\hat{\mathbf{z}}_t$</code> 的期望，计算方式如下：</p>
<p><code>$$ \mathbb{E}_{p \left(s_t | a\right)} \left[\hat{\mathbf{z}}_t\right] = \sum_{i=1}^{L}{\alpha_{t, i} \mathbf{a}_i} $$</code></p>
<p>其余部分的计算方式同 Bahdanau 等人 <sup id="fnref2:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> 的论文类似。Soft Attention 模型可以利用标准的反向传播算法进行求解，直接嵌入到整个模型中一同训练，相对更加简单。</p>
<p>下图展示了一些图片标题生成结果的可视化示例，其中图片内 <span style="background-color:#000; color:#FFF; font-style:bold;">白色</span> 为关注的区域，<span style="border-bottom:2px solid;">画线的文本</span> 即为生成的标题中对应的词。</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/image-caption-generation-visual-attention.png" alt="Image-Caption-Generation-Visual-Attention"></p>
<h3 id="global-local-attention">Global &amp; Local Attention</h3>
<p>Luong 等人 <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> 提出了 Global Attention 和 Local Attention 两种不同的注意力机制用于机器翻译。Global Attention 的思想是在计算上下文向量 <code>$c_t$</code> 时将编码器的所有隐状态均考虑在内。对于对齐向量 <code>$\boldsymbol{a}_t$</code>，通过比较当前目标的隐状态 <code>$\boldsymbol{h}_t$</code> 与每一个输入的隐状态 <code>$\bar{\boldsymbol{h}}_s$</code> 得到，即：</p>
<p><code>$$ \begin{equation} \begin{split} \boldsymbol{a}_t &amp;= \text{align} \left(\boldsymbol{h}_t, \bar{\boldsymbol{h}}_s\right) \\ &amp;= \dfrac{\exp \left(\text{score} \left(\boldsymbol{h}_t, \bar{\boldsymbol{h}}_s\right)\right)}{\sum_{s'}{\exp \left(\text{score} \left(\boldsymbol{h}_t, \bar{\boldsymbol{h}}_{s'}\right)\right)}} \end{split} \end{equation} $$</code></p>
<p>其中 <code>$\text{score}$</code> 为一个基于内容 (content-based) 的函数，可选的考虑如下三种形式：</p>
<p><code>$$ \text{score} \left(\boldsymbol{h}_t, \bar{\boldsymbol{h}}_s\right) = \begin{cases} \boldsymbol{h}_t^{\top} \bar{\boldsymbol{h}}_s &amp; dot \\ \boldsymbol{h}_t^{\top} \boldsymbol{W}_a \bar{\boldsymbol{h}}_s &amp; general \\ \boldsymbol{W}_a \left[\boldsymbol{h}_t; \bar{\boldsymbol{h}}_s\right] &amp; concat \end{cases} $$</code></p>
<p>我们利用一个基于位置 (location-based) 的函数构建注意力模型，其中对齐分数通过目标的隐状态计算得到：</p>
<p><code>$$ \boldsymbol{a}_t = \text{softmax} \left(\boldsymbol{W}_a \boldsymbol{h}_t\right) $$</code></p>
<p>Global Attention 模型的网络结构如下所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/global-attention.png" alt="Global-Attention"></p>
<p>Global Attention 的一个问题在于任意一个输出都需要考虑输入端的所有隐状态，这对于很长的文本 (例如：一个段落或一篇文章) 计算量太大。Local Attention 为了解决这个问题，首先在 <code>$t$</code> 时刻对于每个目标词生成一个对齐位置 <code>$p_t$</code>，其次上下文向量 <code>$\boldsymbol{c}_t$</code> 则由以 <code>$p_t$</code> 为中心前后各 <code>$D$</code> 大小的窗口 <code>$\left[p_t - D, p_t + D\right]$</code> 内的输入的隐状态计算得到。不同于 Global Attention，Local Attention 的对齐向量 <code>$\boldsymbol{a}_t \in \mathbb{R}^{2D + 1}$</code> 为固定维度。</p>
<p>一个比较简单的做法是令 <code>$p_t = t$</code>，也就是假设输入和输出序列是差不多是单调对齐的，我们称这种做法为 <em>Monotonic</em> Alignment (<strong>local-m</strong>)。另一种做法是预测 <code>$p_t$</code>，即：</p>
<p><code>$$ p_t = S \cdot \text{sigmoid} \left(\boldsymbol{v}_p^{\top} \tanh \left(\boldsymbol{W}_p \boldsymbol{h}_t\right)\right) $$</code></p>
<p>其中，<code>$\boldsymbol{W}_p$</code> 和 <code>$\boldsymbol{h}_t$</code> 为预测位置模型的参数，<code>$S$</code> 为输入句子的长度。我们称这种做法为 <em>Predictive</em> Alignment (<strong>local-p</strong>)。作为 <code>$\text{sigmoid}$</code> 函数的结果，<code>$p_t \in \left[0, S\right]$</code>，则通过一个以 <code>$p_t$</code> 为中心的高斯分布定义对齐权重：</p>
<p><code>$$ \boldsymbol{a}_t \left(s\right) = \text{align} \left(\boldsymbol{h}_t, \bar{\boldsymbol{h}}_s\right) \exp \left(- \dfrac{\left(s - p_t\right)^2}{2 \sigma^2}\right) $$</code></p>
<p>其中，根据经验设置 <code>$\sigma = \dfrac{D}{2}$</code>，<code>$s$</code> 为在窗口大小内的一个整数。</p>
<p>Local Attention 模型的网络结构如下所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/local-attention.png" alt="Local-Attention"></p>
<h3 id="self-attention">Self Attention</h3>
<p>Vaswani 等人 <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> 提出了一种新的网络结构，称之为 Transformer，其中采用了自注意力 (Self-attention) 机制。自注意力是一种将同一个序列的不同位置进行自我关联从而计算一个句子表示的机制。Transformer 利用堆叠的 Self Attention 和全链接网络构建编码器 (下图左) 和解码器 (下图右)，整个网络架构如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/self-attention.png" alt="Self-Attention"></p>
<h4 id="编码器和解码器">编码器和解码器</h4>
<p><strong>编码器</strong> 是由 <code>$N = 6$</code> 个相同的网络层构成，每层中包含两个子层。第一层为一个 Multi-Head Self-Attention 层，第二层为一个 Position-Wise 全链接的前馈神经网络。每一层再应用一个残差连接 (Residual Connection) <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> 和一个层标准化 (Layer Normalization) <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>。则每一层的输出为 <code>$\text{LayerNorm} \left(x + \text{Sublayer} \left(x\right)\right)$</code>，其中 <code>$\text{Sublayer} \left(x\right)$</code> 为子层本身的函数实现。为了实现残差连接，模型中所有的子层包括 Embedding 层的输出维度均为 <code>$d_{\text{model}} = 512$</code>。</p>
<p><strong>解码器</strong> 也是由 <code>$N = 6$</code> 个相同的网络层构成，但每层中包含三个子层，增加的第三层用于处理编码器的输出。同编码器一样，每一层应用一个残差连接和一个层标准化。除此之外，解码器对 Self-Attention 层进行了修改，确保对于位置 <code>$i$</code> 的预测仅依赖于位置在 <code>$i$</code> 之前的输出。</p>
<h4 id="scaled-dot-product-multi-head-attention">Scaled Dot-Product &amp; Multi-Head Attention</h4>
<p>一个 Attention 函数可以理解为从一个序列 (Query) 和一个键值对集合 (Key-Value Pairs Set) 到一个输出的映射。文中提出了一种名为 <strong>Scaled Dot-Product Attention</strong> (如下图所示)，其中输入包括 queries，维度为 <code>$d_k$</code> 的 keys 和维度为 <code>$d_v$</code> 的 values。通过计算 queries 和所有 keys 的点积，除以 <code>$\sqrt{d_k}$</code>，再应用一个 softmax 函数获取 values 的权重。</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/scaled-dot-product-attention.png" alt="Scaled-Dot-Product-Attention"></p>
<p>实际中，我们会同时计算一个 Queries 集合中的 Attention，并将其整合成一个矩阵 <code>$Q$</code>。Keys 和 Values 也相应的整合成矩阵 <code>$K$</code> 和 <code>$V$</code>，则有：</p>
<p><code>$$ \text{Attention} \left(Q, K, V\right) = \text{softmax} \left(\dfrac{Q K^{\top}}{\sqrt{d_k}}\right) V $$</code></p>
<p>其中，<code>$Q \in \mathbb{R}^{n \times d_k}$</code>，<code>$Q$</code> 中的每一行为一个 query，<code>$K \in \mathbb{R}^{n \times d_k}, V \in \mathbb{R}^{n \times d_v}$</code>。<code>$\dfrac{1}{\sqrt{d_k}}$</code> 为一个归一化因子，避免点积的值过大导致 softmax 之后的梯度过小。</p>
<p><strong>Multi-Head Attention</strong> 的做法并不直接对原始的 keys，values 和 queries 应用注意力函数，而是学习一个三者各自的映射再应用 Atteneion，同时将这个过程重复 <code>$h$</code> 次。Multi-Head Attention 的网路结构如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/multi-head-attention.png" alt="Multi-Head-Attention"></p>
<p>Multi-Head Attention 的计算过程如下所示：</p>
<p><code>$$ \begin{equation} \begin{split} \text{MultiHead} \left(Q, K, V\right) &amp;= \text{Concat} \left(\text{head}_1, \dotsc, \text{head}_h\right) W^O \\ \textbf{where } \text{head}_i &amp;= \text{Attention} \left(QW_i^Q, KW_i^K, VW_i^V\right) \end{split} \end{equation} $$</code></p>
<p>其中，<code>$W_i^Q \in \mathbb{R}^{d_{\text{model}} \times d_k}, W_i^K \in \mathbb{R}^{d_{\text{model}} \times d_k}, W_i^V \in \mathbb{R}^{d_{\text{model}} \times d_v}, W_i^O \in \mathbb{R}^{h d_v \times d_{\text{model}}}, $</code> 为映射的参数，<code>$h = 8$</code> 为重复的次数，则有 <code>$d_k = d_v = d_{\text{model}} / h = 64$</code>。</p>
<p>整个 Transformer 模型在三处使用了 Multi-Head Attention，分别是：</p>
<ol>
<li>Encoder-Decoder Attention Layers，其中 queries 来自于之前的 Decoder 层，keys 和 values 来自于 Encoder 的输出，该部分同其他 Seq2Seq 模型的 Attention 机制类似。</li>
<li>Encoder Self-Attention Layers，其中 queries，keys 和 values 均来自之前的 Encoder 层的输出，同时 Encoder 层中的每个位置都能够从之前层的所有位置获取到信息。</li>
<li>Decoder Self-Attention Layers，其中 queries，keys 和 values 均来自之前的 Decoder 层的输出，但 Decoder 层中的每个位置仅可以从之前网络层的包含当前位置之前的位置获取信息。</li>
</ol>
<h4 id="position-wise-feed-forward-networks">Position-wise Feed-Forward Networks</h4>
<p>在 Encoder 和 Decoder 中的每一层均包含一个全链接的前馈神经网络，其使用两层线性变换和一个 ReLU 激活函数实现：</p>
<p><code>$$ \text{FFN} \left(x\right) = \max \left(0, x W_1 + b_1\right) W_2 + b_2 $$</code></p>
<p>全链接层的输入和输出的维度 <code>$d_{\text{model}} = 512$</code>，内层的维度 <code>$d_{ff} = 2048$</code>。</p>
<h4 id="positional-encoding">Positional Encoding</h4>
<p>Transformer 模型由于未使用任何循环和卷积组件，因此为了利用序列的位置信息则在模型的 Embedding 输入中添加了 <strong>Position Encoding</strong>。Position Encoding 的维度同 Embedding 的维度相同，从而可以与 Embedding 进行加和，文中使用了如下两种形式：</p>
<p><code>$$ \begin{equation} \begin{split} PE_{\left(pos, 2i\right)} &amp;= \sin \left(pos / 10000^{2i / d_{\text{model}}}\right) \\ PE_{\left(pos, 2i+1\right)} &amp;= \cos \left(pos / 10000^{2i / d_{\text{model}}}\right) \end{split} \end{equation} $$</code></p>
<p>其中，<code>$pos$</code> 为位置，<code>$i$</code> 为对应的维度，选用这种表示形式的原因是对于一个固定的偏移 <code>$k$</code>，<code>$PE_{pos + k}$</code> 都可以利用 <code>$PE_{pos}$</code> 线性表示。这是因为对于正弦和余弦函数有：</p>
<p><code>$$ \begin{equation} \begin{split} \sin \left(\alpha + \beta\right) &amp;= \sin \alpha \cos \beta + \cos \alpha \sin \beta \\ \cos \left(\alpha + \beta\right) &amp;= \cos \alpha \sin \beta - \sin \alpha \sin \beta \end{split} \end{equation} $$</code></p>
<h4 id="why-self-attention">Why Self-Attention</h4>
<p>相比于循环和卷积层，Transformer 模型利用 Self-Attention 层用于一个序列 <code>$\left(x_1, \dotsc, x_n\right)$</code> 到另一个等长序例 <code>$\left(z_1, \dotsc, z_n\right)$</code> 的映射，其中 <code>$x_i, z_i \in \mathbb{R}^d$</code>。Self-Attention 与循环和卷积的对比如下表所示：</p>
<table>
  <thead>
      <tr>
          <th>层类型</th>
          <th>每层的复杂度</th>
          <th>序列操作数</th>
          <th>长距离依赖路径长度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Self-Attention</td>
          <td><code>$O \left(n^2 \cdot d\right)$</code></td>
          <td><code>$O \left(1\right)$</code></td>
          <td><code>$O \left(1\right)$</code></td>
      </tr>
      <tr>
          <td>Recurrent</td>
          <td><code>$O \left(n \cdot d^2\right)$</code></td>
          <td><code>$O \left(n\right)$</code></td>
          <td><code>$O \left(n\right)$</code></td>
      </tr>
      <tr>
          <td>Convolutional</td>
          <td><code>$O \left(k \cdot n \cdot d^2\right)$</code></td>
          <td><code>$O \left(1\right)$</code></td>
          <td><code>$O \left(\log_k \left(n\right)\right)$</code></td>
      </tr>
      <tr>
          <td>Self-Attention (restricted)</td>
          <td><code>$O \left(r \cdot n \cdot d\right)$</code></td>
          <td><code>$O \left(1\right)$</code></td>
          <td><code>$O \left(n/r\right)$</code></td>
      </tr>
  </tbody>
</table>
<ol>
<li>对于每层的复杂度，当序例的长度 <code>$n$</code> 比表示的维度 <code>$d$</code> 小时，Self-Attention 要比循环结构计算复杂度小。为了改进在长序列上 Self-Attention 的计算性能，Self-Attention 可以被限制成仅考虑与输出位置对应的输入序列位置附近 <code>$r$</code> 窗口大小内的信息。</li>
<li>Recurrent 层的最小序列操作数为 <code>$O \left(n\right)$</code>，其他情况为 <code>$O \left(1\right)$</code>，这使得 Recurrent 的并行能力较差，即上表中的 Self-Attention (restricted)。</li>
<li>学习到长距离依赖是很多序列任务的关键，影响该能力的一个重要因素就是前向和后向信号穿越整个网络的路径长度，这个路径长度越短，越容易学习到长距离依赖。</li>
</ol>
<h4 id="attention-visualizations">Attention Visualizations</h4>
<p>第一张图展示了 Self-Attention 学到的句子内部的一个长距离依赖 <strong>“making &hellip; more diffcult”</strong>，图中不同的颜色表示不同 Head 的 Attention，颜色越深表示 Attention 的值越大。</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/self-attention-long-distance-dependencies.png" alt="Self-Attention-Long-Distance-Dependencies"></p>
<p>第二张图展示了 Self-Attention 学到的一个指代消解关系 (Anaphora Resolution)，its 指代的为上文中的 law。下图 (上) 为 Head 5 的所有 Attention，下图 (下) 为 Head 5 和 6 关于词 its 的 Attention，不难看出模型学习到了 its 和 law 之间的依赖关系 (指代消解关系)。</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/self-attention-anaphora-resolution.png" alt="Self-Attention-Long-Anaphora-Resolution"></p>
<h3 id="hierarchical-attention">Hierarchical Attention</h3>
<p>Yang 等人 <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> 提出了一种层级的注意力 (Hierarchical Attention) 网络用于文档分类。Hierarchical Attention 共包含 4 层：一个词编码器 (Word Encoder)，一个词级别的注意力层 (Word Attention)，一个句子编码器 (Sentence Encoder) 和一个句子级别的注意力层 (Sentence Attention)。网络架构如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/hierarchical-attention.png" alt="Hierarchical-Attention"></p>
<h4 id="word-encoder">Word Encoder</h4>
<p>对于一个给定的句子 <code>$w_{it}, t \in \left[0, T\right]$</code>，通过一个 Embedding 矩阵 <code>$W_e$</code> 得到每个词的向量表示，再应用一个双向的 GRU，即：</p>
<p><code>$$ \begin{equation} \begin{split} x_{it} &amp;= W_e w_{it}, t \in \left[1, T\right] \\ \overrightarrow{h}_{it} &amp;= \overrightarrow{\text{GRU}} \left(x_{it}\right), t \in \left[1, T\right] \\ \overleftarrow{h}_{it} &amp;= \overleftarrow{\text{GRU}} \left(x_{it}\right), t \in \left[T, 1\right] \end{split} \end{equation} $$</code></p>
<p>最后将前向的隐状态 <code>$\overrightarrow{h}_{it}$</code> 和后向的隐状态 <code>$\overleftarrow{h}_{it}$</code> 进行拼接，得到 <code>$h_{ij} = \left[\overrightarrow{h}_{it}, \overleftarrow{h}_{it}\right]$</code> 为整个句子在词 <code>$w_{ij}$</code> 附近的汇总信息。</p>
<h4 id="word-attention">Word Attention</h4>
<p>Word Attention 同一般的 Attention 机制类似，计算方式如下：</p>
<p><code>$$ \begin{equation} \begin{split} u_{it} &amp;= \tanh \left(W_w h_{it} + b_w\right) \\ a_{it} &amp;= \dfrac{\exp \left(u_{it}^{\top} u_w\right)}{\sum_{t}{\exp \left(u_{it}^{\top} u_w\right)}} \\ s_i &amp;= \sum_{t}{a_{it} h_{it}} \end{split} \end{equation} $$</code></p>
<h4 id="sentence-encoder">Sentence Encoder</h4>
<p>在 Word Attention 之后，我们得到了一个句子的表示 <code>$s_i$</code>，类似的我们利用一个双向的 GRU 编码文档中的 <code>$L$</code> 个句子：</p>
<p><code>$$ \begin{equation} \begin{split} \overrightarrow{h}_i &amp;= \overrightarrow{\text{GRU}} \left(s_i\right), i \in \left[1, L\right] \\ \overleftarrow{h}_i &amp;= \overleftarrow{\text{GRU}} \left(s_i\right), i \in \left[L, 1\right] \end{split} \end{equation} $$</code></p>
<p>最后将前向的隐状态 <code>$\overrightarrow{h}_i$</code> 和后向的隐状态 <code>$\overleftarrow{h}_i$</code> 进行拼接，得到 <code>$h_i = \left[\overrightarrow{h}_i, \overleftarrow{h}_i\right]$</code> 为整个文档关于句子 <code>$s_i$</code> 的注意力汇总信息。</p>
<h4 id="sentence-attention">Sentence Attention</h4>
<p>同理可得 Sentence Attention 的计算方式如下：</p>
<p><code>$$ \begin{equation} \begin{split} u_i &amp;= \tanh \left(W_s h_i + b_s\right) \\ a_i &amp;= \dfrac{\exp \left(u_i^{\top} u_s\right)}{\sum_{i}{\exp \left(u_i^{\top} u_s\right)}} \\ v &amp;= \sum_{i}{a_i h_i} \end{split} \end{equation} $$</code></p>
<p>最终得到整个文档的向量表示 <code>$v$</code>。</p>
<h3 id="attention-over-attention">Attention-over-Attention</h3>
<p>Cui 等人 <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup> 提出了 Attention-over-Attention 的模型用于阅读理解 (Reading Comprehension)。网络结构如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/attention-over-attention.png" alt="Attention-over-Attention"></p>
<p>对于一个给定的训练集 <code>$\langle \mathcal{D}, \mathcal{Q}, \mathcal{A} \rangle$</code>，模型包含两个输入，一个文档 (Document) 和一个问题序列 (Query)。网络的工作流程如下：</p>
<ol>
<li>先获取 Document 和 Query 的 Embedding 结果，再应用一个双向的 GRU 得到对应的隐状态 <code>$h_{doc}$</code> 和 <code>$h_{query}$</code>。</li>
<li>计算一个 Document 和 Query 的匹配程度矩阵 <code>$M \in \mathbb{R}^{\lvert \mathcal{D} \rvert \times \lvert \mathcal{Q} \rvert}$</code>，其中第 <code>$i$</code> 行第 <code>$j$</code> 列的值计算方式如下：
<code>$$ M \left(i, j\right) = h_{doc} \left(i\right)^{\top} \cdot h_{query} \left(j\right) $$</code></li>
<li>按照 <strong>列</strong> 的方向对矩阵 <code>$M$</code> 应用 softmax 函数，矩阵中的每一列为考虑一个 Query 中的词的 Document 级别的 Attention，因此定义 <code>$\alpha \left(t\right) \in \mathbb{R}^{\lvert \mathcal{D} \rvert}$</code> 为 <code>$t$</code> 时刻的 Document 级别 Attention (<strong><em>query-to-document</em> attention</strong>)。计算方式如下：
<code>$$ \begin{equation} \begin{split} \alpha \left(t\right) &amp;= \text{softmax} \left(M \left(1, t\right), \dotsc, M \left(\lvert \mathcal{D} \rvert, t\right)\right) \\ \alpha &amp;= \left[\alpha \left(1\right), \alpha \left(2\right), \dotsc, \alpha \left(\lvert \mathcal{Q} \rvert\right)\right] \end{split} \end{equation} $$</code></li>
<li>同理按照 <strong>行</strong> 的方向对矩阵 <code>$M$</code> 应用 softmax 函数，可以得到 <code>$\beta \left(t\right) \in \mathbb{R}^{\lvert \mathcal{Q} \rvert}$</code> 为 <code>$t$</code> 时刻的 Query 级别的 Attention (<strong><em>document-to-query</em> attention</strong>)。计算方式如下：
<code>$$ \beta \left(t\right) = \text{softmax} \left(M \left(t, 1\right), \dotsc, M \left(t, \lvert \mathcal{Q} \rvert\right)\right) $$</code></li>
<li>对于 document-to-query attention，我们对结果进行平均得到：
<code>$$ \beta = \dfrac{1}{n} \sum_{t=1}^{\lvert \mathcal{D} \rvert}{\beta \left(t\right)} $$</code></li>
<li>最终利用 <code>$\alpha$</code> 和 <code>$\beta$</code> 的点积 <code>$s = \alpha^{\top} \beta \in \mathbb{R}^{\lvert \mathcal{D} \rvert}$</code> 得到 attended document-level attention (即 <strong><em>attention-over-attention</em></strong>)。</li>
</ol>
<h3 id="multi-step-attention">Multi-step Attention</h3>
<p>Gehring 等人 <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup> 提出了基于 CNN 和 Multi-step Attention 的模型用于机器翻译。网络结构如下图所示：</p>
<p><img src="/images/cn/2018-10-12-seq2seq-and-attention-machanism/multi-step-attention.png" alt="Multi-step-Attention"></p>
<h4 id="position-embeddings">Position Embeddings</h4>
<p>模型首先得到序列 <code>$\mathbf{x} = \left(x_1, \dotsc, x_m\right)$</code> 的 Embedding <code>$\mathbf{w} = \left(w_1, \dotsc , w_m\right), w_j \in \mathbb{R}^f$</code>。除此之外还将输入序列的位置信息映射为 <code>$\mathbf{p} = \left(p_1, \dotsc, p_m\right), p_j \in \mathbb{R}^f$</code>，最终将两者进行合并得到最终的输入 <code>$\mathbf{e} = \left(w_1 + p_1, \dotsc, w_m + p_m\right)$</code>。同时在解码器部分也采用类似的操作，将其与解码器网络的输出表示合并之后再喂入解码器网络 <code>$\mathbf{g} = \left(g_1, \dotsc, g_n\right)$</code> 中。</p>
<h4 id="convolutional-block-structure">Convolutional Block Structure</h4>
<p>编码器和解码器均由多个 Convolutional Block 构成，每个 Block 包含一个卷积计算和一个非线性计算。令 <code>$\mathbf{h}^l = \left(h_1^l, \dotsc, h_n^l\right)$</code> 表示解码器第 <code>$l$</code> 个 Block 的输出，<code>$\mathbf{z}^l = \left(z_1^l, \dotsc, z_m^l\right)$</code> 表示编码器第 <code>$l$</code> 个 Block 的输出。对于一个大小 <code>$k = 5$</code> 的卷积核，其结果的隐状态包含了这 5 个输入，则对于一个 6 层的堆叠结构，结果的隐状态则包含了输入中的 25 个元素。</p>
<p>在每一个 Convolutional Block 中，卷积核的参数为 <code>$W \in \mathbb{R}^{2d \times kd}, b_w \in \mathbb{R}^{2d}$</code>，其中 <code>$k$</code> 为卷积核的大小，经过卷积后的输出为 <code>$Y \in \mathbb{R}^{2d}$</code>。之后的非线性层采用了 Dauphin 等人 <sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup> 提出的 Gated Linear Units (GLU)，对于卷积后的输出 <code>$Y = \left[A, B\right]$</code> 有：</p>
<p><code>$$ v \left(\left[A, B\right]\right) = A \otimes \sigma \left(B\right) $$</code></p>
<p>其中，<code>$A, B \in \mathbb{R}^d$</code> 为非线性单元的输入，<code>$\otimes$</code> 为逐元素相乘，<code>$\sigma \left(B\right)$</code> 为用于控制输入 <code>$A$</code> 与当前上下文相关度的门结构。</p>
<p>模型中还加入了残差连接，即：</p>
<p><code>$$ h_i^l = v \left(W^l \left[h_{i-k/2}^{l-1}, \dotsc, h_{i+k/2}^{l-1}\right] + b_w^l\right) + h_i^{l-1} $$</code></p>
<p>为了确保网络卷积层的输出同输入的长度相匹配，模型对输入数据的前后填补 <code>$k - 1$</code> 个零值，同时为了避免解码器使用当前预测位置之后的信息，模型删除了卷积输出尾部的 <code>$k$</code> 个元素。在将 Embedding 喂给编码器网络之前，在解码器输出应用 softmax 之前以及所有解码器层计算 Attention 分数之前，建立了一个从 Embedding 维度 <code>$f$</code> 到卷积输出大小 <code>$2d$</code> 的线性映射。最终，预测下一个词的概率计算方式如下：</p>
<p><code>$$ p \left(y_{i+1} | y_1, \dotsc, y_i, \mathbf{x}\right) = \text{softmax} \left(W_o h_i^L + b_o\right) \in \mathbb{R}^T $$</code></p>
<h4 id="multi-step-attention-1">Multi-step Attention</h4>
<p>模型的解码器网络中引入了一个分离的注意力机制，在计算 Attention 时，将解码器当前的隐状态 <code>$h_i^l$</code> 同之前输出元素的 Embedding 进行合并：</p>
<p><code>$$ d_i^l = W_d^l h_i^l + b_d^l + g_i $$</code></p>
<p>对于解码器网络层 <code>$l$</code> 中状态 <code>$i$</code> 和输入元素 <code>$j$</code> 之间的的 Attention <code>$a_{ij}^l$</code> 通过解码器汇总状态 <code>$d_i^l$</code> 和最后一个解码器 Block <code>$u$</code> 的输出 <code>$z_j^u$</code> 进行点积运算得到：</p>
<p><code>$$ a_{ij}^l = \dfrac{\exp \left(d_i^l \cdot z_j^u\right)}{\sum_{t=1}^{m}{\exp \left(d_i^l \cdot z_t^u\right)}} $$</code></p>
<p>条件输入 <code>$c_i^l$</code> 的计算方式如下：</p>
<p><code>$$ c_i^l = \sum_{j=1}^{m}{a_{ij}^l \left(z_j^u + e_j\right)} $$</code></p>
<p>其中，<code>$e_j$</code> 为输入元素的 Embedding。与传统的 Attention 不同，<code>$e_j$</code> 的加入提供了一个有助于预测的具体输入元素信息。</p>
<p>最终将 <code>$c_i^l$</code> 加到对应的解码器层的输出 <code>$h_i^l$</code>。这个过程与传统的单步 Attention 不同，被称之为 Multiple Hops <sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup>。这种方式使得模型在计算 Attention 时会考虑之前已经注意过的输入信息。</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Cho, K., van Merrienboer, B., Gulcehre, C., Bahdanau, D., Bougares, F., Schwenk, H., &amp; Bengio, Y. (2014). Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation. In <em>Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing (EMNLP)</em> (pp. 1724–1734).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Sutskever, I., Vinyals, O., &amp; Le, Q. V. (2014). Sequence to Sequence Learning with Neural Networks. In Z. Ghahramani, M. Welling, C. Cortes, N. D. Lawrence, &amp; K. Q. Weinberger (Eds.), <em>Advances in Neural Information Processing Systems 27</em> (pp. 3104–3112).&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Bahdanau, D., Cho, K., &amp; Bengio, Y. (2014). Neural Machine Translation by Jointly Learning to Align and Translate. <em>arXiv preprint arXiv:1409.0473</em>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Xu, K., Ba, J., Kiros, R., Cho, K., Courville, A., Salakhudinov, R., … Bengio, Y. (2015). Show, Attend and Tell: Neural Image Caption Generation with Visual Attention. In <em>International Conference on Machine Learning</em> (pp. 2048–2057).&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Luong, T., Pham, H., &amp; Manning, C. D. (2015). Effective Approaches to Attention-based Neural Machine Translation. In <em>Proceedings of the 2015 Conference on Empirical Methods in Natural Language Processing</em> (pp. 1412–1421).&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., … Polosukhin, I. (2017). Attention is All you Need. In I. Guyon, U. V. Luxburg, S. Bengio, H. Wallach, R. Fergus, S. Vishwanathan, &amp; R. Garnett (Eds.), <em>Advances in Neural Information Processing Systems 30</em> (pp. 5998–6008).&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>He, K., Zhang, X., Ren, S., &amp; Sun, J. (2016). Deep Residual Learning for Image Recognition. In <em>2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR)</em> (pp. 770–778).&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Ba, J. L., Kiros, J. R., &amp; Hinton, G. E. (2016). Layer Normalization. <em>arXiv preprint arXiv:1607.06450</em>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Yang, Z., Yang, D., Dyer, C., He, X., Smola, A., &amp; Hovy, E. (2016). Hierarchical Attention Networks for Document Classification. In <em>Proceedings of the 2016 Conference of the North American Chapter of the Association for Computational Linguistics</em>: Human Language Technologies (pp. 1480–1489).&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Cui, Y., Chen, Z., Wei, S., Wang, S., Liu, T., &amp; Hu, G. (2017). Attention-over-Attention Neural Networks for Reading Comprehension. In <em>Proceedings of the 55th Annual Meeting of the Association for Computational Linguistics</em> (Volume 1: Long Papers) (pp. 593–602).&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Gehring, J., Auli, M., Grangier, D., Yarats, D., &amp; Dauphin, Y. N. (2017). Convolutional Sequence to Sequence Learning. In <em>International Conference on Machine Learning</em> (pp. 1243–1252).&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Dauphin, Y. N., Fan, A., Auli, M., &amp; Grangier, D. (2016). Language Modeling with Gated Convolutional Networks. <em>arXiv preprint arXiv:1612.08083</em>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Sukhbaatar, S., szlam,  arthur, Weston, J., &amp; Fergus, R. (2015). End-To-End Memory Networks. In C. Cortes, N. D. Lawrence, D. D. Lee, M. Sugiyama, &amp; R. Garnett (Eds.), <em>Advances in Neural Information Processing Systems 28</em> (pp. 2440–2448).&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]></description></item><item><title>词向量 (Word Embeddings)</title><link>https://zeqiang.fun/cn/2018/10/word-embeddings/</link><pubDate>Mon, 01 Oct 2018 00:00:00 +0000</pubDate><guid>https://zeqiang.fun/cn/2018/10/word-embeddings/</guid><description><![CDATA[
        <h2 id="文本表示">文本表示</h2>
<p>文本表示是计算机处理自然语言的核心，我们希望计算机能够同人类一样对自然语言能够实现语义层面的理解，但这并非易事。在中文和拉丁语系中，文本的直观表示就存在一定的差异，拉丁语系中词与词之间存在天然的分隔符，而中文则没有。</p>
<blockquote>
<p>I can eat glass, it doesn&rsquo;t hurt me.<br>
我能吞下玻璃而不伤身体。</p>
</blockquote>
<p>所以，在处理中文之前我们往往需要对原始文本进行分词，在此我们不谈这部分工作，假设我们已经得到了分词完的文本，即我们后续需要处理的“<strong>词</strong>”。早期的词表示方法多采用独热编码 (One-Hot Encoding)，对于每一个不同的词都使用一个单独的向量进行表示。对于一个包含 <code>$n$</code> 个词的语料而言，一个词的向量表示 <code>$\text{word}_i \in \left\{0, 1\right\}^n$</code> 仅在第 <code>$i$</code> 的位置值为 1，其他位置的值均为 0。例如，我们可以将“父亲”表示为：</p>
<p><code>$$ \left[1, 0, 0, 0, 0, 0, ...\right] \nonumber $$</code></p>
<p>One-Hot Encoding 的表示方法十分简洁，但也存在着一些问题。</p>
<h3 id="维数灾难-the-curse-of-dimensionality">维数灾难 (The Curse of Dimensionality)</h3>
<p>在很多现实问题中，我们仅用少数的特征是很难利用一个线性模型将数据区分开来的，也就是线性不可分问题。一个有效的方法是利用核函数实现一个非线性变换，将非线性问题转化成线性问题，通过求解变换后的线性问题进而求解原来的非线性问题。</p>
<p>假设 <code>$\mathcal{X}$</code> 是输入空间（欧式空间 <code>$\mathbb{R}^n$</code> 的子集或离散结合），<code>$\mathcal{H}$</code> 为特征空间（希尔伯特空间），若存在一个从 <code>$\mathcal{X}$</code> 到 <code>$ \mathcal{H}$</code> 的映射：</p>
<p><code>$$\phi \left(x\right): \mathcal{X} \rightarrow \mathcal{H}$$</code></p>
<p>使得对所有 <code>$x, z \in \mathcal{X}$</code> ，函数 <code>$K\left(x, z\right)$</code> 满足条件：</p>
<p><code>$$K\left(x, z\right) = \phi \left(x\right) \cdot \phi \left(z\right)$$</code></p>
<p>则 <code>$K\left(x, z\right)$</code> 为核函数， <code>$\phi \left(x\right)$</code> 为映射函数，其中 <code>$\phi \left(x\right) \cdot \phi \left(z\right)$</code> 为 <code>$\phi \left(x\right)$</code> 和 <code>$\phi \left(z\right)$</code> 的内积。</p>
<p>例如，对于一个下图所示的二维数据，显然是线性不可分的。</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/2d-points.png" alt="2d-Points"></p>
<p>构建一个映射 <code>$\phi: \mathbb{R}^2 \rightarrow \mathbb{R}^3$</code> 经 <code>$X$</code> 映射为： <code>$x = x^2, y = y^2, z = y$</code> ，则通过变换后的数据通过可视化可以明显地看出，数据是可以通过一个超平面来分开的。</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/3d-points.png" alt="3d-Points"></p>
<p>可以说随着维度的增加，我们更有可能找到一个超平面（线性模型）将数据划分开来。尽管看起来，随着维度的增加似乎有助于我们构建模型，但是同时数据在高维空间的分布变得越来越<strong>稀疏</strong>。因此，在构建机器学习模型时，当我们需要更好的覆盖数据的分布时，我们需要的数据量就更大，这也就会导致需要更多的时间去训练模型。例如，假设所有特征均为0到1之间连续分布的数据，针对1维的情况，当覆盖50%的数据时，仅需全体50%的样本即可；针对2维的情况，当覆盖50%的数据时，则需全体71% ( <code>$0.71^2 \approx 0.5$</code> ) 的样本；针对3维的情况，当覆盖50%的数据时，则需全体79% ( <code>$0.79^3 \approx 0.5$</code> )，这就是我们所说的维数灾难。</p>
<h3 id="分散式表示-distributed-representations">分散式表示 (Distributed Representations)</h3>
<p>分散式表示（Distributed Representations）<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> 最早由 Hiton 提出，对比于传统的 One-Hot Representation ，Distributed Representations 可以将数据表示为低维，稠密，连续的向量，也就是说将原始空间中的潜在信息分散的表示在低维空间的不同维度上。</p>
<p>传统的 One-Hot Representation 会将数据表示成一个很长的向量，例如，在 NLP 中，利用 One-Hot Representation 表示一个单词：</p>
<pre><code>父亲: [1, 0, 0, 0, 0, 0, ...]
爸爸: [0, 1, 0, 0, 0, 0, ...]
母亲: [0, 0, 1, 0, 0, 0, ...]
妈妈: [0, 0, 0, 1, 0, 0, ...]
</code></pre>
<p>这种表示形式很简介，但也很稀疏，相当于语料库中有多少个词，则表示空间的维度就需要多少。那么，对于传统的聚类算法，高斯混合模型，最邻近算法，决策树或高斯 SVM 需要 <code>$O\left(N\right)$</code> 个参数 (或 <code>$O\left(N\right)$</code> 个样本) 将能够将 <code>$O\left(N\right)$</code> 的输入区分开来。而像 RBMs ，稀疏编码，Auto-Encoder 或多层神经网络则可以利用 <code>$O\left(N\right)$</code> 个参数表示 <code>$O\left(2^k\right)$</code> 的输入，其中 <code>$k \leq N$</code> 为稀疏表示中非零元素的个数 <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。</p>
<p>采用 Distributed Representation，则可以将单词表示为：</p>
<pre><code>父亲: [0.12, 0.34, 0.65, ...]
爸爸: [0.11, 0.33, 0.58, ...]
母亲: [0.34, 0.98, 0.67, ...]
妈妈: [0.29, 0.92, 0.66, ...]
</code></pre>
<p>利用这种表示，我们不仅可以将稀疏的高维空间转换为稠密的低维空间，同时我们还能学习出文本间的语义相似性来，例如实例中的 <code>父亲</code> 和 <code>爸爸</code>，从语义上看其均表示 <code>父亲</code> 的含义，但是如果利用 One-Hot Representation 编码则 <code>父亲</code> 与 <code>爸爸</code> 的距离同其与 <code>母亲</code> 或 <code>妈妈</code> 的距离时相同的，而利用 Distributed Representation 编码，则 <code>父亲</code> 同 <code>爸爸</code> 之间的距离要远小于其同 <code>母亲</code> 或 <code>妈妈</code> 之间的距离。</p>
<h2 id="word-embedding-之路">Word Embedding 之路</h2>
<h3 id="n-gram-模型">N-gram 模型</h3>
<p>N-gram (N 元语法) 是一种文本表示方法，指文中连续出现的 <code>$n$</code> 个词语。N-gram 模型是基于 <code>$n-1$</code> 阶马尔科夫链的一种概率语言模型，可以通过前 <code>$n-1$</code> 个词对第 <code>$n$</code> 个词进行预测。Bengio 等人 <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> 提出了一个三层的神经网络的概率语言模型，其网络结构如下图所示：</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/nplm-network.png" alt="NPLM-Network"></p>
<p>模型的最下面为前 <code>$n-1$</code> 个词 <code>$w_{t-n+1}, ..., w_{t-2}, w_{t-1}$</code>，每个词 <code>$w_i$</code> 通过查表的方式同输入层对应的词向量 <code>$C \left(w_i\right)$</code> 相连。词表 <code>$C$</code> 为一个 <code>$\lvert V\rvert \times m$</code> 大小的矩阵，其中 <code>$\lvert V\rvert$</code> 表示语料中词的数量，<code>$m$</code> 表示词向量的维度。输入层则为前 <code>$n-1$</code> 个词向量拼接成的向量 <code>$x$</code>，其维度为 <code>$m \left(n-1\right) \times 1$</code>。隐含层直接利用 <code>$d + Hx$</code> 计算得到，其中 <code>$H$</code> 为隐含层的权重，<code>$d$</code> 为隐含层的偏置。输出层共包含 <code>$\lvert V\rvert$</code> 个神经元，每个神经元 <code>$y_i$</code> 表示下一个词为第 <code>$i$</code> 个词的未归一化的 log 概率，即：</p>
<p><code>$$ y = b + Wx + U \tanh \left(d + Hx\right) $$</code></p>
<p>对于该问题，我们的优化目标为最大化如下的 log 似然函数：</p>
<p><code>$$ L = \dfrac{1}{T} \sum_{t}{f \left(w_t, w_{t-1}, ..., w_{t-n+1}\right) + R \left(\theta\right)} $$</code></p>
<p>其中，<code>$f \left(w_t, w_{t-1}, ..., w_{t-n+1}\right)$</code> 为利用前 <code>$n-1$</code> 个词预测当前词 <code>$w_t$</code> 的条件概率，<code>$R \left(\theta\right)$</code> 为参数的正则项，<code>$\theta = \left(b, d, W, U, H, C\right)$</code>。<code>$C$</code> 作为模型的参数之一，随着模型的训练不断优化，在模型训练完毕后，<code>$C$</code> 中保存的即为词向量。</p>
<h3 id="continuous-bag-of-words-cbow-和-skip-gram-模型">Continuous Bag-of-Words (CBOW) 和 Skip-gram 模型</h3>
<p>CBOW 和 Skip-gram 均考虑一个词的上下文信息，两种模型的结构如下图所示：</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/cbow-skipgram.png" alt="CBOW-Skipgram"></p>
<p>两者在给定的上下文信息中 (即前后各 <code>$m$</code> 个词) 忽略了上下文环境的序列信息，CBOW (上图左) 是利用上下文环境中的词预测当前的词，而 Skip-gram (上图右) 则是用当前词预测上下文中的词。</p>
<p>对于 CBOW，<code>$x_{1k}, x_{2k}, ..., x_{Ck}$</code> 为上下文词的 One-Hot 表示，<code>$\mathbf{W}_{V \times N}$</code> 为所有词向量构成的矩阵 (词汇表)，<code>$y_j$</code> 为利用上下文信息预测得到的当前词的 One-Hot 表示输出，其中 <code>$C$</code> 为上下文词汇的数量，<code>$V$</code> 为词汇表中词的总数量，<code>$N$</code> 为词向量的维度。从输入层到隐含层，我们对输入层词对应的词向量进行简单的加和，即：</p>
<p><code>$$ h_i = \sum_{c=1}^{C}{x_{ck} \mathbf{W}_{V \times N}} $$</code></p>
<p>对于 Skip-gram，<code>$x_k$</code> 为当前词的 One-Hot 表示，<code>$\mathbf{W}_{V \times N}$</code> 为所有词向量构成的矩阵 (词汇表)，<code>$y_{1j}, y_{2j}, ..., y_{Cj}$</code> 为预测的上次文词汇的 One-Hot 表示输出。从输入层到隐含层，直接将 One-Hot 的输入向量转换为词向量表示即可。</p>
<p>除此之外两者还有一些其他的区别：</p>
<ol>
<li>CBOW 要比 Skip-gram 模型训练快。从模型中我们不难发现：从隐含层到输出层，CBOW 仅需要计算一个损失，而 Skip-gram 则需要计算 <code>$C$</code> 个损失再进行平均进行参数优化。</li>
<li>Skip-gram 在小数量的数据集上效果更好，同时对于生僻词的表示效果更好。CBOW 在从输入层到隐含层时，对输入的词向量进行了平均 (可以理解为进行了平滑处理)，因此对于生僻词，平滑后则容易被模型所忽视。</li>
</ol>
<h3 id="word2vec">Word2Vec</h3>
<p>Mikolov 等人 <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> 利用上面介绍的 CBOW 和 Skip-gram 两种模型提出了经典的 Word2Vec 算法。Word2Vec 中针对 CBOW 和 Skip-gram 又提出了两种具体的实现方案 Hierarchical Softmax (层次 Softmax) 和 Negative Sampling (负采样)，因此共有 4 种不同的模型。</p>
<ul>
<li><strong>基于 Hierarchical Softmax 的模型</strong></li>
</ul>
<p><strong>基于 Hierarchical Softmax 的 CBOW 模型如下</strong>：</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/hierarchical-softmax-cbow.png" alt="Hierarchical-Softmax-CBOW"></p>
<p>其中：</p>
<ol>
<li><strong>输入层</strong>：包含了 <code>$C$</code> 个词的词向量，<code>$\mathbf{v} \left(w_1\right), \mathbf{v} \left(w_2\right), ..., \mathbf{v} \left(w_C\right) \in \mathbb{R}^N$</code>，<code>$N$</code> 为词向量的维度。</li>
<li><strong>投影层</strong>：将输入层的向量进行加和，即：<code>$\mathbf{x}_w = \sum_{i=1}^{C}{\mathbf{v} \left(w_i\right)} \in \mathbb{R}^N$</code>。</li>
<li><strong>输出层</strong>：输出为一颗二叉树，是根据语料构建出来的 Huffman 树 <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>，其中每个叶子节点为词汇表中的一个词。</li>
</ol>
<p>Hierarchical Softmax 是解决概率语言模型中计算效率的关键，CBOW 模型去掉了隐含层，同时将输出层改为了 Huffman 树。对于该模型的优化求解，我们首先引入一些符号，对于 Huffman 树的一个叶子节点 (即词汇表中的词 <code>$w$</code>)，记：</p>
<ul>
<li><code>$p^w$</code>：从根节点出发到达 <code>$w$</code> 对应的叶子节点的路径。</li>
<li><code>$l^w$</code>：路径 <code>$p^w$</code> 包含的节点的个数。</li>
<li><code>$p_1^w, p_1^w, ..., p_{l^w}^w$</code>：路径 <code>$p^w$</code> 中的 <code>$l^w$</code> 个节点，其中 <code>$p_1^w$</code> 表示根节点，<code>$p_{l^w}^w$</code> 表示词 <code>$w$</code> 对应的叶子节点。</li>
<li><code>$d_2^w, d_3^w, ..., d_{l^w}^w \in \{0, 1\}$</code>：词 <code>$w$</code> 的 Huffman 编码，由 <code>$l^w - 1$</code> 位编码构成，<code>$d_j^w$</code> 表示路径 <code>$p^w$</code> 中第 <code>$j$</code> 个结点对应的编码。</li>
<li><code>$\theta_1^w, \theta_1^w, ..., \theta_{l^w - 1}^w \in \mathbb{R}^N$</code>：路径 <code>$p^w$</code> 中非叶子节点对应的向量，<code>$\theta_j^w$</code> 表示路径 <code>$p^w$</code> 中第 <code>$j$</code> 个非叶子节点对应的向量。</li>
</ul>
<p>首先我们需要根据向量 <code>$\mathbf{x}_w$</code> 和 Huffman 树定义条件概率 <code>$p \left(w | Context\left(w\right)\right)$</code>。我们可以将其视为一系列的二分类问题，在到达对应的叶子节点的过程中，经过的每一个非叶子节点均为对应一个取值为 0 或 1 的 Huffman 编码。因此，我们可以将编码为 1 的节点定义为负类，将编码为 0 的节点定义为正类 (即分到左边为负类，分到右边为正类)，则这条路径上对应的标签为：</p>
<p><code>$$ Label \left(p_i^w\right) = 1 - d_i^w, i = 2, 3, ..., l^w $$</code></p>
<p>则对于一个节点被分为正类的概率为 <code>$\sigma \left(\mathbf{x}_w^{\top} \theta\right)$</code>，被分为负类的概率为 <code>$1 - \sigma \left(\mathbf{x}_w^{\top} \theta\right)$</code>。则条件概率可以表示为：</p>
<p><code>$$ p \left(w | Context\left(w\right)\right) = \prod_{j=2}^{l^w}{p \left(d_j^w | \mathbf{x}_w, \theta_{j-1}^w\right)} $$</code></p>
<p>其中</p>
<p><code>$$ p \left(d_j^w | \mathbf{x}_w, \theta_{j-1}^w\right) = \begin{cases} \sigma \left(\mathbf{x}_w^{\top} \theta\right) &amp; d_j^w = 0 \\ 1 - \sigma \left(\mathbf{x}_w^{\top} \theta\right) &amp; d_j^w = 1 \end{cases} $$</code></p>
<p>或表示为：</p>
<p><code>$$ p \left(d_j^w | \mathbf{x}_w, \theta_{j-1}^w\right) = \left[\sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}\right)\right]^{1 - d_j^w} \cdot \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}\right)\right]^{d_j^w} $$</code></p>
<p>则对数似然函数为：</p>
<p><code>$$ \begin{equation} \begin{split} \mathcal{L} &amp;= \sum_{w \in \mathcal{C}}{\log \prod_{j=2}^{l^w}{\left\{\left[\sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}\right)\right]^{1 - d_j^w} \cdot \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}\right)\right]^{d_j^w}\right\}}} \\ &amp;= \sum_{w \in \mathcal{C}}{\sum_{j=2}^{l^w}{\left\{\left(1 - d_j^w\right) \cdot \log \left[\sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] + d_j^w \cdot \log \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right]\right\}}} \end{split} \end{equation} $$</code></p>
<p>记上式花括号中的内容为 <code>$\mathcal{L} \left(w, j\right)$</code>，则 <code>$\mathcal{L} \left(w, j\right)$</code> 关于 <code>$\theta_{j-1}^w$</code> 的梯度为：</p>
<p><code>$$ \begin{equation} \begin{split} \dfrac{\partial \mathcal{L} \left(w, j\right)}{\partial \theta_{j-1}^w} &amp;= \dfrac{\partial}{\partial \theta_{j-1}^w} \left\{\left(1 - d_j^w\right) \cdot \log \left[\sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] + d_j^w \cdot \log \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right]\right\} \\ &amp;= \left(1 - d_j^w\right) \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] \mathbf{x}_w - d_j^w \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right) \mathbf{x}_w \\ &amp;= \left\{\left(1 - d_j^w\right) \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] - d_j^w \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right\} \mathbf{x}_w \\ &amp;= \left[1 - d_j^w - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] \mathbf{x}_w \end{split} \end{equation} $$</code></p>
<p>则 <code>$\theta_{j-1}^w$</code> 的更新方式为：</p>
<p><code>$$ \theta_{j-1}^w \gets \theta_{j-1}^w + \eta \left[1 - d_j^w - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] \mathbf{x}_w $$</code></p>
<p>同理可得，<code>$\mathcal{L} \left(w, j\right)$</code> 关于 <code>$\mathbf{x}_w$</code> 的梯度为：</p>
<p><code>$$ \dfrac{\partial \mathcal{L} \left(w, j\right)}{\partial \mathbf{x}_w} = \left[1 - d_j^w - \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)\right] \theta_{j-1}^w $$</code></p>
<p>但 <code>$\mathbf{x}_w$</code> 为上下文词汇向量的加和，Word2Vec 的做法是将梯度贡献到上下文中的每个词向量上，即：</p>
<p><code>$$ \mathbf{v} \left(u\right) \gets \mathbf{v} \left(u\right) + \eta \sum_{j=2}^{l^w}{\dfrac{\partial \mathcal{L} \left(w, j\right)}{\partial \mathbf{x}_w}}, u \in Context \left(w\right) $$</code></p>
<p>基于 Hierarchical Softmax 的 CBOW 模型的随机梯度上升算法伪代码如下：</p>


<div><pre class="pseudocode">
\begin{algorithm}
\caption{基于 Hierarchical Softmax 的 CBOW 随机梯度上升算法}
\begin{algorithmic}
\STATE $\mathbf{e} = 0$
\STATE $\mathbf{x}_w = \sum_{u \in Context \left(w\right)}{\mathbf{v} \left(u\right)}$
\FOR{$j = 2, 3, ..., l^w$}
    \STATE $q = \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^w\right)$
    \STATE $g = \eta \left(1 - d_j^w - q\right)$
    \STATE $\mathbf{e} \gets \mathbf{e} + g \theta_{j-1}^w$
    \STATE $\theta_{j-1}^w \gets \theta_{j-1}^w + g \mathbf{x}_w$
\ENDFOR
\FOR{$u \in Context \left(w\right)$}
    \STATE $\mathbf{v} \left(u\right) \gets \mathbf{v} \left(u\right) + \mathbf{e}$
\ENDFOR
\end{algorithmic}
\end{algorithm}
</pre></div>

<p><strong>基于 Hierarchical Softmax 的 Skip-gram 模型如下</strong>：</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/hierarchical-softmax-skipgram.png" alt="Hierarchical-Softmax-Skipgram"></p>
<p>对于 Skip-gram 模型，是利用当前词 <code>$w$</code> 对上下文 <code>$Context \left(w\right)$</code> 中的词进行预测，则条件概率为：</p>
<p><code>$$ p \left(Context \left(w\right) | w\right) = \prod_{u \in Context \left(w\right)}{p \left(u | w\right)} $$</code></p>
<p>类似于 CBOW 模型的思想，有：</p>
<p><code>$$ p \left(u | w\right) = \prod_{j=2}^{l^u}{p \left(d_j^u | \mathbf{v} \left(w\right), \theta_{j-1}^u\right)} $$</code></p>
<p>其中</p>
<p><code>$$ p \left(d_j^u | \mathbf{v} \left(w\right), \theta_{j-1}^u\right) = \left[\sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^u\right)\right]^{1 - d_j^u} \cdot \left[1 - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^u\right)\right]^{d_j^u} $$</code></p>
<p>可得对数似然函数为：</p>
<p><code>$$ \begin{equation} \begin{split} \mathcal{L} &amp;= \sum_{w \in \mathcal{C}}{\log \prod_{u \in Context \left(w\right)}{\prod_{j=2}^{l^u}{\left\{\left[\sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right]^{1 - d_j^u} \cdot \left[1 - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^u\right)\right]^{d_j^u}\right\}}}} \\ &amp;= \sum_{w \in \mathcal{C}}{\sum_{u \in Context \left(w\right)}{\sum_{j=2}^{l^u}{\left\{\left(1 - d_j^u\right) \cdot \log \left[\sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] + d_j^u \cdot \log \left[1 - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right]\right\}}}} \end{split} \end{equation} $$</code></p>
<p>记上式花括号中的内容为 <code>$\mathcal{L} \left(w, u, j\right)$</code>，在 <code>$\mathcal{L} \left(w, u, j\right)$</code> 关于 <code>$\theta_{j-1}^u$</code> 的梯度为：</p>
<p><code>$$ \begin{equation} \begin{split} \dfrac{\partial \mathcal{L} \left(w, u, j\right)}{\partial \theta_{j-1}^{u}} &amp;= \dfrac{\partial}{\partial \theta_{j-1}^{u}} \left\{\left(1 - d_j^u\right) \cdot \log \left[\sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] + d_j^u \cdot \log \left[1 - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right]\right\} \\ &amp;= \left(1 - d_j^u\right) \cdot \left[1 - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] \mathbf{v} \left(w\right) - d_j^u \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right) \mathbf{v} \left(w\right) \\ &amp;= \left\{\left(1 - d_j^u\right) \cdot \left[1 - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] - d_j^u \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right\} \mathbf{v} \left(w\right) \\ &amp;= \left[1 - d_j^u - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] \mathbf{v} \left(w\right) \end{split} \end{equation} $$</code></p>
<p>则 <code>$\theta_{j-1}^u$</code> 的更新方式为：</p>
<p><code>$$ \theta_{j-1}^u \gets \theta_{j-1}^u + \eta \left[1 - d_j^u - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] \mathbf{v} \left(w\right) $$</code></p>
<p>同理可得，<code>$\mathcal{L} \left(w, u, j\right)$</code> 关于 <code>$\mathbf{v} \left(w\right)$</code> 的梯度为：</p>
<p><code>$$ \dfrac{\partial \mathcal{L} \left(w, u, j\right)}{\partial \mathbf{v} \left(w\right)} = \left[1 - d_j^u - \sigma \left(\mathbf{v} \left(w\right)^{\top} \theta_{j-1}^{u}\right)\right] \theta_{j-1}^u $$</code></p>
<p>则 <code>$\mathbf{v} \left(w\right)$</code> 的更新方式为：</p>
<p><code>$$ \mathbf{v} \left(w\right) \gets \mathbf{v} \left(w\right) + \eta \sum_{u \in Context \left(w\right)}{\sum_{j=2}^{l^u}{\dfrac{\partial \mathcal{L} \left(w, u, j\right)}{\partial \mathbf{v} \left(w\right)}}} $$</code></p>
<p>基于 Hierarchical Softmax 的 Skip-gram 模型的随机梯度上升算法伪代码如下：</p>


<div><pre class="pseudocode">
\begin{algorithm}
\caption{基于 Hierarchical Softmax 的 Skig-gram 随机梯度上升算法}
\begin{algorithmic}
\STATE $\mathbf{e} = 0$
\FOR{$u \in Context \left(w\right)$}
    \FOR{$j = 2, 3, ..., l^u$}
        \STATE $q = \sigma \left(\mathbf{x}_w^{\top} \theta_{j-1}^u\right)$
        \STATE $g = \eta \left(1 - d_j^u - q\right)$
        \STATE $\mathbf{e} \gets \mathbf{e} + g \theta_{j-1}^u$
        \STATE $\theta_{j-1}^u \gets \theta_{j-1}^u + g \mathbf{v} \left(w\right)$
    \ENDFOR
\ENDFOR
\STATE $\mathbf{v} \left(w\right) \gets \mathbf{v} \left(w\right) + \mathbf{e}$
\end{algorithmic}
\end{algorithm}
</pre></div>

<ul>
<li><strong>基于 Negative Sampling 的模型</strong></li>
</ul>
<p>基于 Negative Sampling (NEG) 的模型相比于基于 Hierarchical Softmax 的模型不再使用复杂的 Huffman 树，而是使用简单的<strong>随机负采样</strong>，从而大幅的提高了模型的性能。</p>
<p><strong>基于 Negative Sampling 的 CBOW 模型如下</strong>：</p>
<p>对于基于 Negative Sampling  CBOW 模型，已知词 <code>$w$</code> 的上下文 <code>$Context \left(w\right)$</code>，预测词 <code>$w$</code>，则词 <code>$w$</code> 即为一个<strong>正样本</strong>，其他词则为<strong>负样本</strong>。对于一个给定 <code>$Context \left(w\right)$</code> 的负样本集合 <code>$NEG \left(w\right) \neq \varnothing$</code>，词典中的任意词 <code>$\forall \tilde{w} \in \mathcal{D}$</code>，其样本的标签定义为：</p>
<p><code>$$ L^w \left(\tilde{w}\right) =  \begin{cases} 1, &amp; \tilde{w} = w \\ 0, &amp; \tilde{w} \neq w \end{cases} $$</code></p>
<p>则对于一个正样本 <code>$\left(Context, \left(w\right)\right)$</code>，我们希望最大化：</p>
<p><code>$$ g \left(w\right) = \prod_{u \in \left\{w\right\} \cup NEG \left(w\right)}{p \left(u | Context \left(w\right)\right)} $$</code></p>
<p>或表示为：</p>
<p><code>$$ p \left(u | Context \left(w\right)\right) = \left[\sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right]^{L^w \left(w\right)} \cdot \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right]^{1 - L^w \left(w\right)} $$</code></p>
<p>即增大正样本概率的同时减少负样本的概率。对于一个给定的语料库 <code>$\mathcal{C}$</code>，对数似然函数为：</p>
<p><code>$$ \begin{equation} \begin{split} \mathcal{L} &amp;= \sum_{w \in \mathcal{C}}{\log g \left(w\right)} \\ &amp;= \sum_{w \in \mathcal{C}}{\log \prod_{u \in \left\{w\right\} \cup NEG \left(w\right)}{\left\{\left[\sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right]^{L^w \left(u\right)} \cdot \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right]^{1 - L^w \left(u\right)}\right\}}} \\ &amp;= \sum_{w \in \mathcal{C}}{\sum_{u \in \left\{w\right\} \cup NEG \left(w\right)}{\left\{L^w \left(u\right) \cdot \log \left[\sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right] + \left[1 - L^w \left(u\right)\right] \cdot \log \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right]\right\}}} \end{split} \end{equation} $$</code></p>
<p>记上式花括号中的内容为 <code>$\mathcal{L} \left(w, u\right)$</code>，则 <code>$\mathcal{L} \left(w, u\right)$</code> 关于 <code>$\theta^u$</code> 的梯度为：</p>
<p><code>$$ \begin{equation} \begin{split} \dfrac{\partial \mathcal{L} \left(w, u\right)}{\partial \theta^u} &amp;= \dfrac{\partial}{\partial \theta^u} \left\{L^w \left(u\right) \cdot \log \left[\sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right] + \left[1 - L^w \left(u\right)\right] \cdot \log \left[1 - \sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right]\right\} \\ &amp;= L^w \left(u\right) \left[1 - \sigma \left(\mathbf{w}_w^{\top} \theta^u\right)\right] \mathbf{x}_w - \left[1 - L^w \left(u\right)\right] \sigma \left(\mathbf{x}_w^{\top} \theta^u\right) \mathbf{x}_w \\ &amp;= \left\{L^w \left(u\right) \left[1 - \sigma \left(\mathbf{w}_w^{\top} \theta^u\right)\right] - \left[1 - L^w \left(u\right)\right] \sigma \left(\mathbf{x}_w^{\top} \theta^u\right)\right\} \mathbf{x}_w \\ &amp;= \left[L^w \left(u\right) - \sigma \left(\mathbf{w}_w^{\top} \theta^u\right)\right] \mathbf{x}_w \end{split} \end{equation} $$</code></p>
<p>则 <code>$\theta^u$</code> 的更新方式为：</p>
<p><code>$$ \theta^u \gets \theta^u + \eta \left[L^w \left(u\right) - \sigma \left(\mathbf{w}_w^{\top} \theta^u\right)\right] \mathbf{x}_w $$</code></p>
<p>同理可得，<code>$\mathcal{L} \left(w, u\right)$</code> 关于 <code>$\mathbf{x}_w$</code> 的梯度为：</p>
<p><code>$$ \dfrac{\partial \mathcal{L} \left(w, u\right)}{\partial \mathbf{x}_w} = \left[L^w \left(u\right) - \sigma \left(\mathbf{w}_w^{\top} \theta^u\right)\right] \theta^u $$</code></p>
<p>则 <code>$\mathbf{v} \left(\tilde{w}\right), \tilde{w} \in Context \left(w\right)$</code> 的更新方式为：</p>
<p><code>$$ \mathbf{v} \left(\tilde{w}\right) \gets \mathbf{v} \left(\tilde{w}\right) + \eta \sum_{u \in \left\{w\right\} \cup NEG \left(w\right)}{\dfrac{\partial \mathcal{L} \left(w, u\right)}{\partial \mathbf{x}_w}}, \tilde{w} \in Context \left(w\right) $$</code></p>
<p>基于 Negative Sampling 的 CBOW 模型的随机梯度上升算法伪代码如下：</p>


<div><pre class="pseudocode">
\begin{algorithm}
\caption{基于 Negative Sampling 的 CBOW 随机梯度上升算法}
\begin{algorithmic}
\STATE $\mathbf{e} = 0$
\STATE $\mathbf{x}_w = \sum_{u \in Context \left(w\right)}{\mathbf{v} \left(u\right)}$
\FOR{$u \in Context \left\{w\right\} \cup NEG \left(w\right)$}
    \STATE $q = \sigma \left(\mathbf{x}_w^{\top} \theta^u\right)$
    \STATE $g = \eta \left(L^w \left(u\right) - q\right)$
    \STATE $\mathbf{e} \gets \mathbf{e} + g \theta^u$
    \STATE $\theta^u \gets \theta^u + g \mathbf{x}_w$
\ENDFOR
\FOR{$u \in Context \left(w\right)$}
    \STATE $\mathbf{v} \left(u\right) \gets \mathbf{v} \left(u\right) + \mathbf{e}$
\ENDFOR
\end{algorithmic}
\end{algorithm}
</pre></div>

<p><strong>基于 Negative Sampling 的 Skip-gram 模型如下</strong>：</p>
<p>对于 Skip-gram 模型，利用当前词 <code>$w$</code> 对上下文 <code>$Context \left(w\right)$</code> 中的词进行预测，则对于一个正样本 <code>$\left(Context, \left(w\right)\right)$</code>，我们希望最大化：</p>
<p><code>$$ g \left(w\right) = \prod_{\tilde{w} \in Context \left(w\right)}{\prod_{u \in \left\{w\right\} \cup NEG^{\tilde{w}} \left(w\right)}{p \left(u | \tilde{w}\right)}} $$</code></p>
<p>其中，<code>$NEG^{\tilde{w}} \left(w\right)$</code> 为处理词 <code>$\tilde{w}$</code> 时生成的负样本集合，且：</p>
<p><code>$$ p \left(u | \tilde{w}\right) =  \begin{cases} \sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right) &amp; L^w \left(u\right) = 1 \\ 1 - \sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right) &amp; L^w \left(u\right) = 0 \end{cases} $$</code></p>
<p>或表示为：</p>
<p><code>$$ p \left(u | \tilde{w}\right) = \left[\sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right]^{L^w \left(u\right)} \cdot \left[1 - \sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right]^{1 - L^w \left(u\right)} $$</code></p>
<p>对于一个给定的语料库 <code>$\mathcal{C}$</code>，对数似然函数为：</p>
<p><code>$$ \begin{equation} \begin{split} \mathcal{L} &amp;= \sum_{w \in \mathcal{C}}{\log g \left(w\right)} \\ &amp;= \sum_{w \in \mathcal{C}}{\log \prod_{\tilde{w} \in Context \left(w\right)}{\prod_{u \in \left\{w\right\} \cup NEG^{\tilde{w}} \left(w\right)}{\left\{\left[\sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right]^{L^w \left(u\right)} \cdot \left[1 - \sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right]^{1 - L^w \left(u\right)}\right\}}}} \\ &amp;= \sum_{w \in \mathcal{C}}{\sum_{\tilde{w} \in Context \left(w\right)}{\sum_{u \in \left\{w\right\} \cup NEG^{\tilde{w}} \left(w\right)}{\left\{L^w \left(u\right) \cdot \log \left[\sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right] + \left[1 - L^w \left(u\right)\right] \cdot \log \left[1 - \sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right]\right\}}}} \end{split} \end{equation} $$</code></p>
<p>记上式花括号中的内容为 <code>$\mathcal{L} \left(w, \tilde{w}, u\right)$</code>，则 <code>$\mathcal{L} \left(w, \tilde{w}, u\right)$</code> 关于 <code>$\theta^u$</code> 的梯度为：</p>
<p><code>$$ \begin{equation} \begin{split} \dfrac{\partial \mathcal{L} \left(w, \tilde{w}, u\right)}{\partial \theta^u} &amp;= \dfrac{\partial}{\partial \theta^u} \left\{L^w \left(u\right) \cdot \log \left[\sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right] + \left[1 - L^w \left(u\right)\right] \cdot \log \left[1 - \sigma \left(\mathbf{v}\left(\tilde{w}\right)^{\top} \theta^u\right)\right]\right\} \\ &amp;= L^w \left(u\right) \left[1 - \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)\right] \mathbf{v} \left(\tilde{w}\right) - \left[1 - L^w \left(u\right)\right] \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right) \mathbf{v} \left(\tilde{w}\right) \\ &amp;= \left\{L^w \left(u\right) \left[1 - \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)\right] - \left[1 - L^w \left(u\right)\right] \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)\right\} \mathbf{v} \left(\tilde{w}\right) \\ &amp;= \left[L^w \left(u\right) - \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)\right] \mathbf{v} \left(\tilde{w}\right) \end{split} \end{equation} $$</code></p>
<p>则 <code>$\theta^u$</code> 的更新方式为：</p>
<p><code>$$ \theta^u \gets \theta^u + \eta \left[L^w \left(u\right) - \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)\right] \mathbf{v} \left(\tilde{w}\right) $$</code></p>
<p>同理可得，<code>$\mathcal{L} \left(w, \tilde{w}, u\right)$</code> 关于 <code>$\mathbf{v} \left(\tilde{w}\right)$</code> 的梯度为：</p>
<p><code>$$ \dfrac{\partial \mathcal{L} \left(w, \tilde{w}, u\right)}{\partial \mathbf{v} \left(\tilde{w}\right)} = \left[L^w \left(u\right) - \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)\right] \theta^u $$</code></p>
<p>则 <code>$\mathbf{v} \left(\tilde{w}\right)$</code> 的更新方式为：</p>
<p><code>$$ \mathbf{v} \left(\tilde{w}\right) \gets \mathbf{v} \left(\tilde{w}\right) + \eta \sum_{u \in \left\{w\right\} \cup NEG^{\tilde{w}} \left(w\right)}{\dfrac{\partial \mathcal{L} \left(w, \tilde{w}, u\right)}{\partial \mathbf{v} \left(\tilde{w}\right)}} $$</code></p>
<p>基于 Negative Sampling 的 Skig-gram 模型的随机梯度上升算法伪代码如下：</p>


<div><pre class="pseudocode">
\begin{algorithm}
\caption{基于 Negative Sampling 的 Skig-gram 随机梯度上升算法}
\begin{algorithmic}
\STATE $\mathbf{e} = 0$
\FOR{$\tilde{w} \in Context \left(w\right)$}
    \FOR{$u \in \left\{w\right\} \cup NEG^{\tilde{w}} \left(w\right)$}
        \STATE $q = \sigma \left(\mathbf{v} \left(\tilde{w}\right)^{\top} \theta^u\right)$
        \STATE $g = \eta \left(L^w \left(u\right) - q\right)$
        \STATE $\mathbf{e} \gets \mathbf{e} + g \theta^u$
        \STATE $\theta^u \gets \theta^u + g \mathbf{v} \left(\tilde{w}\right)$
    \ENDFOR
\ENDFOR
\STATE $\mathbf{v} \left(\tilde{w}\right) \gets \mathbf{v} \left(\tilde{w}\right) + \mathbf{e}$
\end{algorithmic}
\end{algorithm}
</pre></div>

<p>无论是基于 Negative Sampling 的 CBOW 模型还是 Skip-gram 模型，我们都需要对于给定的词 <code>$w$</code> 生成 <code>$NEG \left(w\right)$</code>，对于一个词典 <code>$\mathcal{D}$</code> 和给定的语料 <code>$\mathcal{C}$</code>，一个词被选择中的概率为：</p>
<p><code>$$ p_{NEG} \left(w\right) = \dfrac{\#w}{\sum_{u \in \mathcal{D}}{\#u}} $$</code></p>
<p>其中 <code>$\#w$</code> 和 <code>$\#u$</code> 表示词 <code>$w$</code> 和 <code>$u$</code> 在语料 <code>$\mathcal{C}$</code> 中出现的频次。在 Word2Vec 的 C 代码中 <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>，并没有使用词的原始频次，而是对其做了 0.75 次幂，即：</p>
<p><code>$$ p_{NEG} \left(w\right) = \dfrac{\left(\#w\right)^{0.75}}{\sum_{u \in \mathcal{D}}{\left(\#u\right)^{0.75}}} $$</code></p>
<div class="blockquote" style='border-left: 4px solid #369BE5;'>本节内容参考了 licstar 的 <a href="http://licstar.net/archives/328">博客</a> 和 peghoty 的 <a href="https://www.cnblogs.com/peghoty/p/3857839.html">博客</a>。</div>
<h2 id="其他-embedding-方法">其他 Embedding 方法</h2>
<h3 id="glove">GloVe</h3>
<p>GloVe (Global Vector 的简写) 是由 Pennington 等人 <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> 提出了一种词向量生成方法，该方法利用了语料的全局统计信息。</p>
<p>令 <code>$X$</code> 表示词与词之间的共现矩阵，<code>$X_{ij}$</code> 表示词 <code>$j$</code> 在词 <code>$i$</code> 为上下文的情况下出现的频次。则 <code>$X_i = \sum_{k}{X_{ik}}$</code> 表示在词<code>$i$</code> 为上下文的情况任意词出现的总次数。令 <code>$P_{ij} = P \left(j | i\right) = X_{ij} / X_i$</code> 表示词 <code>$j$</code> 在词 <code>$i$</code> 出现前提下出现的条件概率。</p>
<p>例如，我们令 <code>$i = ice, j = steam$</code>，则这两个词之间的关系可以利用同其他词 <code>$k$</code> 共现概率的比率学习得出。则有：</p>
<ol>
<li>与词 <code>ice</code> 相关，但与词 <code>steam</code> 不太相关，例如 <code>$k = solid$</code>，则比率 <code>$P_{ik} / P_{jk}$</code> 应该较大；类似的当词 <code>$k$</code> 与 <code>steam</code> 相关，但与词 <code>ice</code> 不太相关，则比率 <code>$P_{ik} / P_{jk}$</code> 应该较小。</li>
<li>当与词 <code>ice</code> 和词 <code>steam</code> 均相关或者均不太相关时，例如 <code>$k = water$</code> 或 <code>$k = fashion$</code>，则比率 <code>$P_{ik} / P_{jk}$</code> 应该和 1 接近。</li>
</ol>
<p>下表展示了在一个大量语料上的概率及其比率：</p>
<table>
  <thead>
      <tr>
          <th>概率和比例</th>
          <th><code>$k = solid$</code></th>
          <th><code>$k = gas$</code></th>
          <th><code>$k = water$</code></th>
          <th><code>$k = fashion$</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>$P \left(k \vert ice\right)$</code></td>
          <td><code>$1.9 \times 10^{-4}$</code></td>
          <td><code>$6.6 \times 10^{-5}$</code></td>
          <td><code>$3.0 \times 10^{-3}$</code></td>
          <td><code>$1.7 \times 10^{-5}$</code></td>
      </tr>
      <tr>
          <td><code>$P \left(k \vert steam\right)$</code></td>
          <td><code>$2.2 \times 10^{-5}$</code></td>
          <td><code>$7.8 \times 10^{-4}$</code></td>
          <td><code>$2.2 \times 10^{-3}$</code></td>
          <td><code>$1.8 \times 10^{-5}$</code></td>
      </tr>
      <tr>
          <td><code>$P \left(k \vert ice\right) / P \left(k \vert steam\right)$</code></td>
          <td><code>$8.9$</code></td>
          <td><code>$8.5 \times 10^{-2}$</code></td>
          <td><code>$1.36$</code></td>
          <td><code>$0.96$</code></td>
      </tr>
  </tbody>
</table>
<p>根据如上的假设，我们可以得到一个最基础的模型：</p>
<p><code>$$ F \left(w_i, w_j, \tilde{w}_k\right) = \dfrac{P_{ik}}{P_{jk}} $$</code></p>
<p>其中 <code>$w \in \mathbb{R}^d$</code> 为词向量，<code>$\tilde{w}_k \in \mathbb{R}^d$</code> 为单独的上下文词的词向量。假设向量空间是一个线性结构，因此 <code>$F$</code> 仅依赖于两个向量之间的差异，则模型可以改写为：</p>
<p><code>$$ F \left(w_i - w_j, \tilde{w}_k\right) = \dfrac{P_{ik}}{P_{jk}} $$</code></p>
<p>上式中右面是一个标量，如果左面的参数利用一个复杂的模型进行计算，例如神经网络，则会破坏我们希望保留的线性结构。因此，我们对参数采用点积运算，即：</p>
<p><code>$$ F \left(\left(w_i - w_j\right)^{\top} \tilde{w}_k\right) = \dfrac{P_{ik}}{P_{jk}} $$</code></p>
<p>在词之间的共现矩阵中，一个词和其上下文中的一个词之间应该是可以互换角色的。首先我们要保证 <code>$F$</code> 在 <code>$\left(\mathbb{R}, +\right)$</code> 和 <code>$\left(\mathbb{R}_{&gt;0}, \times\right)$</code> 上是同态的 (homomorphism)，例如：</p>
<p><code>$$ F \left(\left(w_i - w_j\right)^{\top} \tilde{w}_k\right) = \dfrac{F \left(w_i^{\top} \tilde{w}_k\right)}{F \left(w_j^{\top} \tilde{w}_k\right)} $$</code></p>
<p>其中 <code>$F \left(w_i^{\top} \tilde{w}_k\right) = P_{ik} = \dfrac{X_{ik}}{X_i}$</code>，则上式的一个解为 <code>$F = \exp$</code>，或：</p>
<p><code>$$ w_i^{\top} \tilde{w}_k = \log \left(P_{ik}\right) = \log \left(X_{ik}\right) - \log \left(X_i\right) $$</code></p>
<p>其中 <code>$\log \left(X_i\right)$</code> 与 <code>$k$</code> 无关记为 <code>$b_i$</code>，同时为了对称性添加 <code>$\tilde{b}_k$</code>，则上式改写为：</p>
<p><code>$$ w_i^{\top} \tilde{w}_k + b_i + \tilde{b}_k = \log \left(X_{ik}\right) $$</code></p>
<p>上式中，左侧为词向量的相关运算，右侧为共现矩阵的常量信息，则给出模型的损失函数如下：</p>
<p><code>$$ J = \sum_{i,j=1}^{V}{f \left(X_{ij}\right) \left(w_i^{\top} \tilde{w}_k + b_i + \tilde{b}_k - \log X_{ij}\right)^2} $$</code></p>
<p>其中，<code>$V$</code> 为词典中词的个数，<code>$f$</code> 为一个权重函数，其应具有如下特点：</p>
<ol>
<li><code>$f \left(0\right) = 0$</code>。如果 <code>$f$</code> 为一个连续函数，则当 <code>$x \to 0$</code> 时 <code>$\lim_{x \to 0}{f \left(x\right) \log^2 x}$</code> 应足够快地趋近于无穷。</li>
<li><code>$f \left(x\right)$</code> 应为非减函数，以确保稀少的共现不会权重过大。</li>
<li><code>$f \left(x\right)$</code> 对于较大的 <code>$x$</code> 应该相对较小，以确保过大的共现不会权重过大。</li>
</ol>
<p>文中给出了一个符合要求的函数如下：</p>
<p><code>$$ f \left(x\right) =  \begin{cases} \left(x / x_{\max}\right)^{\alpha} &amp; \text{if} \  x &lt; x_{\max} \\ 1 &amp; \text{otherwise} \end{cases} $$</code></p>
<p>其中两个超参数的值建议为 <code>$x_{\max} = 100, \alpha = 0.75$</code>。</p>
<h3 id="fasttext">fastText</h3>
<p>fastText 是由 Bojanowski 和 Grave 等人 <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> 提出的一种词向量表示方法。原始的 Skip-gram 模型忽略了词语内部的结构信息，fastText 利用 N-gram 方法将其考虑在内。</p>
<p>对于一个词 <code>$w$</code>，利用一系列的 N-gram 进行表示，同时在词的前后添加 <code>&lt;</code> 和 <code>&gt;</code> 边界符号以同其他文本序列进行区分。同时还将词语本身也包含在这个 N-gram 集合中，从而学习到词语的向量表示。例如，对于词 <code>$where$</code> 和 <code>$n = 3$</code>，则 N-gram 集合为：<code>&lt;wh, whe, her, ere, re&gt;</code>，同时包含词本身 <code>&lt;where&gt;</code>。需要注意的是，序列 <code>&lt;her&gt;</code> 与词 <code>$where$</code> 中的 tri-gram <code>her</code> 是两个不同的概念。模型提取所有 <code>$3 \leq n \leq 6$</code> 的 N-gram 序列。</p>
<p>假设 N-gram 词典的大小为 <code>$G$</code>，对于一个词 <code>$w$</code>，<code>$\mathcal{G}_w \subset \left\{1, ..., G\right\}$</code> 表示词中出现的 N-gram 的集合。针对任意一个 N-gram <code>$g$</code>，用向量 <code>$\mathbf{z}_g$</code> 表示，则我们利用一个词的所有 N-gram 的向量的加和表示该词。可以得到该模型的评分函数为：</p>
<p><code>$$ s \left(w, c\right) = \sum_{g \in \mathcal{G}_w}{\mathbf{z}_g^{\top} \mathbf{v}_c} $$</code></p>
<p>模型在学习不同词向量时可以共享权重 (不同词的可能包含相同的 N-gram)，使得在学习低频词时也可得到可靠的向量表示。</p>
<h3 id="wordrank">WordRank</h3>
<p>WordRank 是由 Ji 等人 <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> 提出的一种词向量表示方法，其将词向量学习问题转换成一个排序问题。</p>
<p>我们令 <code>$\mathbf{u}_w$</code> 表示当前词 <code>$w$</code> 的 <code>$k$</code> 维词向量，<code>$\mathbf{v}_c$</code> 表示当前词上下文 <code>$c$</code> 的词向量。通过两者的内积 <code>$\langle \mathbf{u}_w, \mathbf{v}_c \rangle$</code> 来捕获词 <code>$w$</code> 和上下文 <code>$c$</code> 之间的关系，两者越相关则该内积越大。对于一个给定的词 <code>$w$</code>，利用上下文集合 <code>$\mathcal{C}$</code> 同词的内积分数进行排序，对于一个给定的上下文 <code>$c$</code>，排序为：</p>
<p><code>$$ \begin{equation} \begin{split} \text{rank} \left(w, c\right) &amp;= \sum_{c' \in \mathcal{C} \setminus \left\{c\right\}}{I \left(\langle \mathbf{u}_w, \mathbf{v}_c \rangle - \langle \mathbf{u}_w, \mathbf{v}_{c'} \rangle \leq 0\right)} \\ &amp;= \sum_{c' \in \mathcal{C} \setminus \left\{c\right\}}{I \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'}  \rangle \leq 0\right)} \end{split} \end{equation} $$</code></p>
<p>其中，<code>$I \left(x \leq 0\right)$</code> 为一个 0-1 损失函数，当 <code>$x \leq 0$</code> 时为 1 其他情况为 0。由于 <code>$I \left(x \leq 0\right)$</code> 为一个非连续函数，因此我们可以将其替换为一个凸上限函数 <code>$\ell \left(\cdot\right)$</code>，其可以为任意的二分类损失函数，构建排序的凸上限如下：</p>
<p><code>$$ \text{rank} \left(w, c\right) \leq \overline{\text{rank}} \left(w, c\right) = \sum_{c' \in \mathcal{C} \setminus \left\{c\right\}}{\ell \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right)} $$</code></p>
<p>我们期望排序模型将更相关的上下文排在列表的顶部，基于此构建损失函数如下：</p>
<p><code>$$ J \left(\mathbf{U}, \mathbf{V}\right) := \sum_{w \in \mathcal{W}}{\sum_{c \in \Omega_w}{r_{w, c} \cdot \rho \left(\dfrac{\overline{\text{rank}} \left(w, c\right) + \beta}{\alpha}\right)}} $$</code></p>
<p>其中，<code>$\mathcal{W}$</code> 表示词典，<code>$\mathbf{U} := \left\{\mathbf{u}_w\right\}_{w \in \mathcal{W}}$</code> 和 <code>$\mathbf{V} := \left\{\mathbf{c}_w\right\}_{c \in \mathcal{C}}$</code> 分别表示词及其上下文词向量的参数，<code>$\Omega_w$</code> 表示与词 <code>$w$</code> 共现的上下文的集合，<code>$r_{w, c}$</code> 为衡量 <code>$w$</code> 和 <code>$c$</code> 之间关系的权重，<code>$\rho \left(\cdot\right)$</code> 为用于衡量排序好坏的单调递增的损失函数，<code>$\alpha \geq 0, \beta \geq 0$</code> 为超参数。可选的有：</p>
<p><code>$$ r_{w, c} = \begin{cases} \left(X_{w, c} / x_{\max}\right)^{\epsilon} &amp; \text{if} \ X_{w, c} &lt; x_{\max} \\ 1 &amp; \text{otherwise} \end{cases} $$</code></p>
<p>其中 <code>$x_{\max} = 100, \epsilon = 0.75$</code>。根据 <code>$\rho \left(\cdot\right)$</code> 的要求，损失函数在排序的顶部 (rank 值小) 的地方更加敏感，同时对于 rank 值较大的地方不敏感。这可以使得模型变得更加稳健 (避免语法错误和语言的非常规使用造成干扰)，因此可选的有：</p>
<p><code>$$ \begin{equation} \begin{split} \rho \left(x\right) &amp;:= \log_2 \left(1 + x\right) \\ \rho \left(x\right) &amp;:= 1 - \dfrac{1}{\log_2 \left(2 + x\right)} \\ \rho \left(x\right) &amp;:= \dfrac{x^{1 - t} - 1}{1 - t}, t \neq 1 \end{split} \end{equation} $$</code></p>
<p>损失函数可以等价的定义为：</p>
<p><code>$$ J \left(\mathbf{U}, \mathbf{V}\right) := \sum_{\left(w, c\right) \in \Omega}{r_{w, c} \cdot \rho \left(\dfrac{\overline{\text{rank}} \left(w, c\right) + \beta}{\alpha}\right)} $$</code></p>
<p>在训练过程中，外层的求和符号容易利用 SDG 算法解决，但对于内层的求和符号除非 <code>$\rho \left(\cdot\right)$</code> 是一个线性函数，否则难以求解。然而，<code>$\rho \left(\cdot\right)$</code> 函数的性质要求其不能是一个线性函数，但我们可以利用其凹函数的特性对其进行一阶泰勒分解，有：</p>
<p><code>$$ \rho \left(x\right) \leq \rho \left(\xi^{-1}\right) + \rho' \left(\xi^{-1}\right) \cdot \left(x - \xi^{-1}\right) $$</code></p>
<p>对于任意 <code>$x$</code> 和 <code>$\xi \neq 0$</code> 均成立，同时当且仅当 <code>$\xi = x^{-1}$</code> 时等号成立。因此，令 <code>$\Xi := \left\{\xi_{w, c}\right\}_{\left(w, c\right) \in \Sigma}$</code>，则可以得到 <code>$J \left(\mathbf{U}, \mathbf{V}\right)$</code> 的一个上界：</p>
<p><code>$$ \begin{equation} \begin{split} \overline{J} \left(\mathbf{U}, \mathbf{V}, \Xi\right) &amp;:= \sum_{\left(w, c\right)  \in \Omega}{r_{w, c} \cdot \left\{\rho \left(\xi_{wc}^{-1}\right) + \rho' \left(\xi_{wc}^{-1}\right) \cdot \left(\alpha^{-1} \beta + \alpha^{-1} \sum_{c' \in \mathcal{C} \setminus \left\{c\right\}}{\ell \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right) - \xi_{w, c}^{-1}}\right)\right\}} \\ &amp;= \sum_{\left(w, c, c'\right)}{r_{w, c} \cdot \left(\dfrac{\rho \left(\xi_{w, c}^{-1}\right) + \rho' \left(\xi_{w, c}^{-1}\right) \cdot \left(\alpha^{-1} \beta - \xi_{w, c}^{-1}\right)}{\lvert \mathcal{C} \rvert - 1} + \dfrac{1}{\alpha} \rho' \left(\xi_{w, c}^{-1}\right) \cdot \ell \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right)\right)} \end{split} \end{equation} $$</code></p>
<p>其中，<code>$\left(w, c, c'\right) \in \Omega \times \left(\mathcal{C} \setminus \left\{c\right\}\right)$</code>，至此我们可以通过均匀采样 <code>$\left(w, c\right) \in \Sigma$</code> 和 <code>$c' \in \mathcal{C} \setminus \left\{c\right\}$</code> 解决训练问题。</p>
<p>整个 WordRank 算法的伪代码如下：</p>


<div><pre class="pseudocode">
\begin{algorithm}
\caption{WordRank 算法}
\begin{algorithmic}
\STATE $\eta$ 为学习率
\WHILE{$\mathbf{U}$，$\mathbf{V}$ 和 $\Xi$ 未收敛}
    \STATE \COMMENT{阶段1：更新 $\mathbf{U}$ 和 $\mathbf{V}$}
    \WHILE{$\mathbf{U}$ 和 $\mathbf{V}$ 未收敛}
        \STATE 从 $\Omega$ 中均匀采样 $\left(w, c\right)$
        \STATE 从 $\mathcal{C} \setminus \left\{c\right\}$ 中均匀采样 $c'$
        \STATE \COMMENT{同时更新如下 3 个参数}
        \STATE $\mathbf{u}_w \gets \mathbf{u}_w - \eta \cdot r_{w, c} \cdot \rho' \left(\xi_{w, c}^{-1}\right) \cdot \ell' \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right) \cdot \left(\mathbf{v}_c - \mathbf{v}_{c'}\right)$
        \STATE $\mathbf{v}_c \gets \mathbf{v}_c - \eta \cdot r_{w, c} \cdot \rho' \left(\xi_{w, c}^{-1}\right) \cdot \ell' \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right) \cdot \mathbf{u}_w$
        \STATE $\mathbf{v}_{c'} \gets \mathbf{v}_{c'} - \eta \cdot r_{w, c} \cdot \rho' \left(\xi_{w, c}^{-1}\right) \cdot \ell' \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right) \cdot \mathbf{u}_w$
    \ENDWHILE
    \STATE \COMMENT{阶段2：更新 $\Xi$}
    \FOR{$w \in \mathcal{W}$}
        \FOR{$c \in \mathcal{C}$}
            \STATE $\xi_{w, c} = \alpha / \left(\sum_{c' \in \mathcal{C} \setminus \left\{c\right\}}{\ell \left(\langle \mathbf{u}_w, \mathbf{v}_c - \mathbf{v}_{c'} \rangle\right) + \beta}\right)$
        \ENDFOR
    \ENDFOR
\ENDWHILE
\end{algorithmic}
\end{algorithm}
</pre></div>

<h3 id="cw2vec">cw2vec</h3>
<p>cw2vec 是由 Cao 等人 <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup> 提出的一种基于汉字笔画 N-gram 的中文词向量表示方法。该方法根据汉字作为象形文字具有笔画信息的特点，提出了笔画 N-gram 的概念。针对一个词的笔画 N-gram，其生成过程如下图所示：</p>
<p><img src="/images/cn/2018-10-01-word-embeddings/cw2vec-stroke-n-gram-generation.png" alt="cw2vec-Stroke-N-gram-Generation"></p>
<p>共包含 4 个步骤：</p>
<ol>
<li>将一个词拆解成单个的汉字，例如：“大人” 拆解为 “大” 和 “人”。</li>
<li>将每个汉字拆解成笔画，例如：“大” 和 “人” 拆解为 “一，丿，乀，丿，乀”。</li>
<li>将每个笔画映射到对应的编码序列，例如： “一，丿，乀，丿，乀” 映射为 13434。</li>
<li>利用编码序列生成笔画 N-gram，例如：134，343，434；1343，3434；13434。</li>
</ol>
<p>模型中定义一个词 <code>$w$</code> 及其上下文 <code>$c$</code> 的相似度如下：</p>
<p><code>$$ sim \left(w, c\right) = \sum_{q \in S\left(w\right)}{\vec{q} \cdot \vec{c}} $$</code></p>
<p>其中，<code>$S$</code> 为由笔画 N-gram 构成的词典，<code>$S \left(w\right)$</code> 为词 <code>$w$</code> 对应的笔画 N-gram 集合，<code>$q$</code> 为该集合中的一个笔画 N-gram，<code>$\vec{q}$</code> 为 <code>$q$</code> 对应的向量。</p>
<p>该模型的损失函数为：</p>
<p><code>$$ \mathcal{L} = \sum_{w \in D}{\sum_{c \in T \left(w\right)}{\log \sigma \left(sim \left(w, c\right)\right) + \lambda \mathbb{E}_{c' \sim P} \left[\log \sigma \left(- sim \left(w, c'\right)\right)\right]}} $$</code></p>
<p>其中，<code>$D$</code> 为语料中的全部词语，<code>$T \left(w\right)$</code> 为给定的词 <code>$w$</code> 和窗口内的所有上次文词，<code>$\sigma \left(x\right) = \left(1 + \exp \left(-x\right)\right)^{-1}$</code>，<code>$\lambda$</code> 为负采样的个数，<code>$\mathbb{E}_{c' \sim P} \left[\cdot\right]$</code> 表示负样本 <code>$c'$</code> 按照 <code>$D$</code> 中词的分布 <code>$P$</code> 进行采样，该分布可以为词的一元模型的分布 <code>$U$</code>，同时为了避免数据的稀疏性问题，类似 Word2Vec 中的做法采用 <code>$U^{0.75}$</code>。</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Hinton, G. E. (1986, August). Learning distributed representations of concepts. In <em>Proceedings of the eighth annual conference of the cognitive science society</em> (Vol. 1, p. 12).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Bengio, Y., Courville, A., &amp; Vincent, P. (2013). Representation learning: A review and new perspectives. <em>IEEE transactions on pattern analysis and machine intelligence</em>, 35(8), 1798-1828.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Bengio, Y., Ducharme, R., Vincent, P., &amp; Jauvin, C. (2003). A Neural Probabilistic Language Model. <em>Journal of Machine Learning Research</em>, 3(Feb), 1137–1155.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Mikolov, T., Chen, K., Corrado, G., &amp; Dean, J. (2013). Efficient Estimation of Word Representations in Vector Space. <em>arXiv preprint arXiv:1301.3781</em>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://zh.wikipedia.org/zh/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81">https://zh.wikipedia.org/zh/霍夫曼编码</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://code.google.com/archive/p/word2vec/">https://code.google.com/archive/p/word2vec/</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Pennington, J., Socher, R., &amp; Manning, C. (2014). Glove: Global Vectors for Word Representation. In <em>Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing (EMNLP)</em> (pp. 1532–1543).&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Bojanowski, P., Grave, E., Joulin, A., &amp; Mikolov, T. (2017). Enriching Word Vectors with Subword Information. <em>Transactions of the Association for Computational Linguistics</em>, 5, 135–146.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Ji, S., Yun, H., Yanardag, P., Matsushima, S., &amp; Vishwanathan, S. V. N. (2016). WordRank: Learning Word Embeddings via Robust Ranking. In <em>Proceedings of the 2016 Conference on Empirical Methods in Natural Language Processing</em> (pp. 658–668).&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Cao, S., Lu, W., Zhou, J., &amp; Li, X. (2018). cw2vec: Learning Chinese Word Embeddings with Stroke n-gram Information. In <em>Thirty-Second AAAI Conference on Artificial Intelligence</em>.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]></description></item></channel></rss>