论文地址:http://aclweb.org/anthology/C18-1266

这篇文章的主要内容是实现了一个新的叫deepQuest的QE系统(已开源),里面包含了之前sentence-level QE的SOTA(现在已经不是了),POSTECH和他们这次新发明的Bi-RNN两个sentence-level的系统,以及在这两个sentence-level基础上的document-level QE系统,发布了一个新的Resources for document-level Quality Estimation数据集(也已开源),并在WMT 17和上述数据集上报告了结果。结果表明,Bi-RNN在sentence-level上效果不如POSTECH(但是训练快),作为document-level的基础系统效果更好。

论文内容

sentence-level QE通常预测的是机器翻译输出结果的post-editing effort,但document-level QE通常是在全自动的MT应用场景下预测文档质量分数(而非PE)。目前所有的神经网络QE方法都有复杂的结构,需要预训练和手动提取feature,而且没有document-level的方法。(吐槽:事实上我觉得预训练和复杂的网络结构都是必要的,甚至是很必要的……)所以我们提出了一个新的sentence-level方法(Bi-RNN),它不需要预训练,结构很简单,训练起来很快。我们还提出了一个新的神经网络的document-level的方法,它可以将任何细粒度的QE方法的结果进行综合,得到更粗粒度的QE结果,比如将sentence-level的输出综合处理得到document-level的结果。经过在sent-level和doc-level的一些欧洲语言的SMT和NMT上输出的测试,我们发现,对高质量NMT输出进行QE的主要挑战是在已经很流利的文本中找出错误。

Sentence-level

作者首先实现了WMT 17的冠军系统POSTECH。这个系统分成两个部分:

  • predictor:encoder-decoder RNN,基于context对词进行预测,生成表示向量
  • estimator:Bi-RNN,根据predictor生成的表示向量进行打分

其中predictor部分需要大量预训练。(这就和QEBrain的思路基本上是一样的,只不过具体用的架构不太一样。我可能还是需要去读一下具体是怎么做的。)

然后实现了新的一种架构,Bi-RNN。这个方法的思路非常简单:

  • 对输入和输出分别进行word embedding
  • 分别用一个bi-RNN对输入和输出的embedding进行学习,得到一系列隐状态$h_j$(两个RNN分开训练,但是输出结果连在一起,一起进行attention)
  • 对所有的隐状态进行attention,得到加权后的和
  • 进行sigmoid,将输出作为分数

attention的公式为:

$$ \alpha_j = \frac{\exp{(W_a h_j^T)}}{\sum_{k=1}^{J} \exp{(W_a h_j^T)}} \\ v = \sum_{j=1}^J \alpha_j h_j $$

Bi-RNN结构图

Document-level

之前我们可以看到,Bi-RNN输出了一个$v$向量,实际上可以把它看做是一个对整个句子的表示。POSTECH中Predictor也会输出一个类似的向量。我们可以把这些向量表示再做一次Bi-RNN,对结果进行attention(或者直接用最后一个隐状态),得到整个文档对应的向量,再对这个向量进行sigmoid,得到文档对应的分数。

document-level结构图

测试结果

Sentence-level

测试使用的是WMT 2017 QE的官方数据的一个超集,包括NMT和SMT的翻译结果,其中包括:

  • En-De:28000句(IT领域)
  • En-Lv:18768句(生命科学领域)

数据使用TERCOM进行标注,分数采用HTER。POSTECH的predictor使用Europarl和WMT 2017 News translation Task的语料进行预训练。

一些实现细节(当然,代码里有更多的细节):

  • 使用Keras进行实现(而且似乎支持Theano和TensorFlow两种backend)
  • 使用GRU作为RNN单元
  • word embedding维度为300
  • 词表大小为30K
  • encoder隐藏层单元大小为50
  • 用Adadelta optimizer最小化MSE

sent-level结果

可以得出以下结论:

  • En-De数据集中NMT的翻译质量高于SMT,而En-Lv数据集中NMT的翻译质量不如SMT,这影响了各个方法的表现
  • POSTECH方法在SMT数据上的表现比在NMT数据上高40%,这可能受到了数据质量或者句子长度的影响
  • 无预训练的POSTECH方法表现不如Bi-RNN,这可能是因为Bi-RNN能够把握NMT数据的流利度
  • (但是,还是有预训练的POSTECH方法效果最好)

Document-level

预测的分数采用的是几种BLEU值:

  • document-level BLEU(使用NLTK进行打分)
  • wBLEU:文档中句子BLEU值的加权平均,权重是句子长度
  • tBLEU:也是句子的BLEU值的加权平均,但是权重是TFIDF;对每个文档,都学习一个新的TFIDF模型,并据此计算TFIDF分数
$$ \text{wBLEU}_d = \frac{\sum_{i=1}^D \text{len}(R_i)\text{BLEU}_i}{\sum_{i=1}^D \text{len}(R_i)} $$ $$ \text{tBLEU} = \sum_{i=1}^D \text{TFIDF}_i \text{BLEU}_i $$

在document-level的测试中,使用的数据是WMT News Task中这几年提交的机器翻译结果,作者对数据进行了一定筛选,并把相应的数据集开源了(docQE)。

数据集的情况

document-level系统使用的是POSTECH/Bi-RNN系统输出的句子表示,并测试了使用attention/只使用最后一个状态的结果。

测试结果

通过上述结果可以发现:

  • tBLEU标记下QE系统表现最好,BLEU标记下QE系统表现最差。这可能是因为tBLEU的计算方式和这种从word representation到sentence到document的结构是最类似的。
  • 以Bi-RNN作为输入representation的效果整体优于POSTECH,而且训练得还快。
  • attention的贡献不是统计显著的,这可能是因为相关距离会变化,很难找到最优的权重。
  • 单独筛选训练数据不会提高表现。
  • POSTECH非常需要预训练。
  • De-En和En-Ru的预测难度最大,这可能是因为语言之间词序差异很大,相关的MT输出质量通常也比较低。

运行结果

TBD

论文地址:https://arxiv.org/pdf/1809.00129.pdf

这篇文章也是WMT18 QE Task的提交系统之一,在word-level task上取得了较好的效果(虽然我觉得一部分原因是QEBrain和UNQE没有参加一部分task)。它的主要思路是在之前的一篇文章[1]的基础上做了改进,用卷积层起到类似于attention的作用。这个思路的效果看起来不如一般的attention。(而且文章写得一点也不清楚,代码库也找不到,我还是不知道模型的具体结构是什么样的。)

模型结构

模型结构

(图里的模型结构画得一点也不确切……)

这篇文章的模型是在[1]的基础上改进出来的,中间多加了一层卷积。

模型的输入是三元组$\langle s, t, \mathcal{A} \rangle$,其中$s = s_1, ..., s_M$是源句,$t = t_1, ..., t_N$是译句,$\mathcal{A} \subseteq {(m, n) | 1 \leq m \leq M, 1 \leq n \leq N}$是alignment。

模型分成三个主要部分:

  • 词和POS的embedding层
  • 卷积层
  • RNN和FF层

embedding层的vector是这样构成的($\Vert$表示row-wise concatenation):

  • 记embedding的维度为$d$,令源词和译词采用同样的embedding参数,记源词的embedding为$e_{s_i}$,译词的embedding为$e_{t_j}$
  • 将每个译词自己的embedding和与它对齐的源词的embedding的平均值连接在一起,得到$\mathbf{x}'_j = ave(e_{s_{\mathcal{A}(:, t_j)}}) \Vert e_{t_j}$,这是一个长度为$2d$的向量
  • 将$\mathbf{x}'_j$和$\mathbf{x}'_{j-1}$和$\mathbf{x}'_{j+1}$连接在一起,得到$\mathbf{x}_j = \mathbf{x}'_{j-1} \Vert \mathbf{x}'_j \Vert \mathbf{x}'_{j+1}$,这是一个长度为$6d$的向量

然后将这些vector连接在一起进行卷积($\oplus$表示column-wise concatenation):

  • 将$\mathbf{x}_j$连接在一起,构成一个矩阵:$\mathbf{x}_{1:N} = \mathbf{x}_1 \oplus \mathbf{x}_2 ... \oplus \mathbf{x}_N$
  • 然后对上述矩阵进行一维卷积:$c_i = f(\mathbf{w} \cdot \mathbf{x}_{i:i+h-1} + b)$,得到feature$\mathbf{c} = {c_1, c_2, ..., c_N}$(进行了padding)
  • 在不同的窗口大小下($\mathcal{H} = {1, 3, 5, 7}$)各学习$n_f = 64$个feature,将这些feature连接起来,得到$C \in \mathbb{R}^{N \times |\mathcal{H}| \cdot n_f}$的卷积层输出,相当于每个词由长度为$\mathcal{H}| \cdot n_f = 256$的向量表示(这句是我猜的)
  • 最后再把上述向量和译词的POS tag embedding和与译词对齐的源词的POS tag embedding连接起来(文中没有说POS tag是怎么来的,但[1]中是用TurboTagger标记的;我猜可能也要进行平均)

然后对每个词对应的向量表示进行处理(似乎使用了stacked RNN的方法,我还没太搞懂):

  • 两层FF(ReLU),隐藏层大小为400
  • 一层Bi-GRU,隐藏层大小为200,前向表示和后向表示连接后进行layer normalization
  • 两层FF(ReLU),隐藏层大小为200
  • 一层Bi-GRU,隐藏层大小为100,同样进行layer normalization
  • 一层FF(ReLU),隐藏层大小为100
  • 一层FF(ReLU),隐藏层大小为50

(我猜测每个词对应的网络参数是相同的?)

然后把最后一层输出的FF feature和Marmot输出的31个baseline feature连接起来,通过softmax来预测OK/BAD label。

实验结果

实验结果

这个模型取得了比较好的结果。

作者还进行了一些sensitivity analysis(调整dropout rate)和ablation analysis(删除模型中的一些部分,观察效果),具体内容就不写了。


  1. Pushing the Limits of Translation Quality Estimation

论文地址:https://www.jstage.jst.go.jp/article/transinf/E101.D/9/E101.D_2018EDL8019/_article/-char/en

这篇论文描述了一种新的用于Quality Estimation的神经网络结构,在WMT18 QE Task中取得了较好的成绩(仅次于QEBrain,同样大大超过了SOTA)。

相关工作

传统的QE方法是把它看成是一个有监督回归/分类模型。典型的做法如QuEst:先从输入中提取feature,再根据feature用SVR进行打分。这种做法存在的问题之一是,提取feature的过程与源语言本身密切相关,因此限制了它在不同语言中的应用。

之后研究者们开始在QE中应用deep learning,可以分成两大类:

  • neural-aware QE:将neural feature(如word embedding、translation condition probability、cross entropy等)集成到QE系统中,可以有效提高系统表现。
  • pure neural QE:直接建立一个用于QE任务的神经网络;目前的SOTA是用两个分开的网络(RNNsearch predictor + RNN estimator)分别进行训练,然后输出结果。这种方法的表现比neural-aware QE更好。

本文中的做法是将RNNsearch和RNN组成一个整体的网络,共同进行训练。

(之后的实验结果将说明,pure neural QE > neural-aware QE > traditional QE,而在pure neural QE中,unified network又好于separated network。)

模型结构

模型结构图

(这篇文章把模型结构讲得比较细。)

模型分成两个主要模块:

  • RNNsearch:从句对中提取quality vector
  • RNN:用quality vector对翻译质量进行预测,可以看成是有监督回归任务

这两个模块共同进行训练。其中RNNsearch中间生成的context vector是$c_1, ..., c_n$,decoder RNN的隐状态是$s_0, s_1, ..., s_n$,$t_1, ..., t_j$是中间表示,可以通过下式计算:

$$t_j = \tanh{(U_o s_{j-1} + V_o E y_{j-1} + C_o c_j)}$$

其中$U_o, V_o, C_o$是模型参数,$E$是目标语言的embedding矩阵。

给定输入$(x_1, ..., x_m)$,decoder将生成翻译输出$(y_1, ..., y_n)$,其中生成每个词的条件概率为:

$$p(y_j | \{y_1, ..., y_{j-1}\}, x) = g(y_{j-1}, s_{j-1}, c) = \frac{\exp{(y^T_j W_o t_j)}}{\sum_{k=1}^{K_y} \exp{(y_k^T W_o t_j)}}$$

其中$W_o$是权重矩阵。(显然上式只是对$y^T_j W_o t_j$做了一个softmax。)为了通过上述条件概率对翻译质量进行描述,可以这样计算quality vector:

计算quality vector的图示

$$q_{y_j} = [(y^T_j W_o) \odot t^T_j]^T$$

(所以这里就直接用了翻译条件概率……)

最后将这些quality vector依次输入到RNN(作者使用的是GRU单元)中,将最后一个输出作为QE得分:

$$v_j = f(v_{j-1}, q_{y_j})$$ $$QE_{score} = W_{QE} \times v_n$$

其中$W_{QE}$是权重矩阵。最终分数没有用logistic sigmoid函数进行平均,而是直接进行了clip。

模型训练

由于QE任务的训练集太小了,因此RNNsearch和QE RNN先分别用平行语料(WMT17翻译任务的训练语料)和QE训练语料进行了预训练,然后才共同用QE训练语料进行训练。训练目标是最小化MAE:

$$J(\theta) = \frac{1}{N} \sum{n=1}^{N} |QE_{score}(x^{(n)}, y^{(n)}, \theta) - HTER^{(n)}|$$

由于模型的各部分是一起训练的,因此输出的quality vector是可以进行训练的(而不是像estimator-predictor方法中,RNNsearch的输出是固定的翻译结果),能够提取出更准确的feature。

实验结果

表中列出的系统包括:

  • QuEst:传统QE方法
  • SHEF/QUEST-EMB:neural-aware QE方法
  • JXNU/Emb+RNNLM+QuEst+SNM:neural-aware QE方法
  • Predictor-Estimator:pure neural QE方法
  • UNQE:本文的方法

实验结果

分析结果可以得到以下结论:

  • pure neural QE方法好于neural-aware QE方法好于传统QE方法
  • UNQE方法好于Predictor-Estimator方法
  • ensemble是有效的
  • 对预测分数进行logistic sigmoid不如直接进行clip

一些想法

这篇文章的做法是直接利用RNNsearch的翻译结果(或者说生成翻译的条件概率)进行Quality Estimation,那么它和“直接用一个最强的翻译系统进行翻译然后比较翻译结果和实际翻译输出”有什么差异呢?文中也讲到,如果真的直接用一个RNNsearch系统的翻译输出作为feature然后去预测,效果是不如像这个系统这样,将RNNsearch + QE RNN共同进行训练的。我猜测原因可能包括:

  1. RNNsearch还是不够好,应该尝试直接用Transformer的翻译输出作为feature进行预测,然后再将结果和QEBrain进行比较
  2. MT系统内部训练时计算loss的方式(应该是cross entropy吧)和HTER打分是有差异的,因此需要额外的训练,使得它不止可以输出正确的翻译,还可以对翻译的实际得分有更好的估计

至于模型本身的结构,作者似乎没有像QEBrain那样考虑不同的estimator结构对结果的影响,如果尝试不同的结构(如LSTM、Bi-LSTM等)是否效果会更好?

以及一个问题:HTER是对翻译质量的最好的度量方式吗?如果直接换成人类打分(像Task3和Task4那样)会怎样?

论文地址:https://arxiv.org/pdf/1807.09433.pdf

这篇文章描述了2018 WMT Quality Estimation中效果最好的系统。作者认为他们的工作有以下几项主要贡献:

  1. 提出了一个新的经过预训练的基于Bi-Transformer的prior-knowledge模型,且可以用于APE(auto post-editing)
  2. 提出了3种mis-match feature
  3. 用Bi-LSTM通过输入特征进行quality estimation
  4. 提出了一种在计算流图中使用BPE的方法

Quality Estimation的传统方法和形式定义

一种传统方法是把预测sentence-level得分看做是一个constraint regression问题,把预测word-level标签看做是sequence labeling问题;然后先提取特征,再对翻译质量进行预测。

从统计学的角度,可以把翻译系统形式化地看成是$p(\mathbf{t} | \mathbf{s}) = p(\mathbf{t} | \mathbf{z}) p(\mathbf{z} | \mathbf{s})$,其中$\mathbf{s}$表示源句的token sequence,$\mathbf{t}$表示译句,$\mathbf{z}$是表示encode过的源句的隐变量。因此,可以把$p(\mathbf{z} | \mathbf{s})$看成是encoder,$p(\mathbf{t} | \mathbf{z})$看成是decoder。

在QE任务中,MT系统是未知的,输入数据是$(\mathbf{s}, \mathbf{m}, \mathbf{t})$,其中$\mathbf{m}$是未知系统的输出,$\mathbf{t}$是对$\mathbf{m}$ post-edit之后的结果。一般来说,至少可以在两个层面对$\mathbf{m}$进行评价:

  • word-level:根据$\mathbf{m}$和$\mathbf{t}$对$\mathbf{m}$中的token生成的OK/BAD标签
  • sentence-level:根据$\mathbf{m}$和$\mathbf{t}$之间的差异计算HTER分数

因此可以假定训练数据实际上是$(\mathbf{s}, \mathbf{m}, \mathbf{t}, h, \mathbf{y})$,其中$h$是HTER,$\mathbf{y}$是OK/BAD标签。QE任务即训练回归模型$p(h | \mathbf{s}, \mathbf{m})$和sequence labeling模型$p(\mathbf{y} | \mathbf{s}, \mathbf{m})$。

(这项工作的架构类似于predictor-estimator的架构,但是两边是共同训练的,因此效果得到提升。)

Conditional Language/Feature Extration Model: Bilingual Expert Model

作者首先形式化地描述了如何训练这个模型(实际上我没太看懂)。

通过贝叶斯公式,可以写出隐变量$\mathbf{z}$的后验分布公式:

$$p(\mathbf{z} | \mathbf{t}, \mathbf{s}) = \frac{p(\mathbf{t} | \mathbf{z}) p(\mathbf{z} | \mathbf{s})}{p(\mathbf{t} | \mathbf{s})}$$

由于$p(\mathbf{t} | \mathbf{s})$无法直接计算,因此用分布$q(\mathbf{z} | \mathbf{t}, \mathbf{s})$通过最小化KL散度来逼近实际的后验:

$$\min{D_{KL} (q(\mathbf{z} | \mathbf{t}, \mathbf{s}) || p(\mathbf{z} | \mathbf{t}, \mathbf{s}))}$$

可以把上述目标函数换成下面这个(我猜这和KL散度的性质有关,但我不会):

$$\max{\mathbb{E}_{q(\mathbf{z} | \mathbf{t}, \mathbf{s})}[p(\mathbf{t} | \mathbf{z})] - D_{KL} (q(\mathbf{z} | \mathbf{t}, \mathbf{s}) || p(\mathbf{z} | \mathbf{s}))}$$

这个新目标函数的优点是不需要直接估计机器翻译模型$p(\mathbb{t} | \mathbb{s})$。(至少在这里仍然把MT和QE区分开了,但在实际模型架构中几乎是一样的。)而且可以直接计算$p(\mathbf{z} | \mathbf{s})$;左边的期望似然实际上是一个VAE(variational autoencoder),可以进行估计:

$$\max{\mathbb{E}_{q(\mathbf{z} | \mathbf{t}, \mathbf{s})}[p(\mathbf{t} | \mathbf{z})] \approx p(\mathbf{t} | \mathbf{\tilde{z}})}, \quad \tilde{z} \sim q(\mathbf{z} | \mathbf{t}, \mathbf{s})$$

下面只需通过Transformer构造出$p(\mathbf{t} | \mathbf{z})$和$q(\mathbf{z} | \mathbf{t}, \mathbf{s})$这两个概率。


Transformer部分模型架构如下图右侧部分:

模型整体结构

其中有三个主要模块:

  • self-attention encoder:encode源句
  • 前向+后向self-attention encoder:encode译句
  • reconstructor:重新生成译句

(这架构和Transformer几乎没有区别……除了译句encoder换成了双向的)

将$p(\mathbf{t} | \mathbf{z})$和$q(\mathbf{z} | \mathbf{t}, \mathbf{s})$进行如下分解:

$$p(\mathbf{t} | \mathbf{z}) = \prod_{k} p(t_k | \overrightarrow{\mathbf{z}_k}, \overleftarrow{\mathbf{z}_k})$$ $$q(\mathbf{z} | \mathbf{t}, \mathbf{s} = \prod_{k} q(\overrightarrow{\mathbf{z}_k} | \mathbf{s}, \mathbf{t}_{< k}, \overleftarrow{\mathbf{z}_k} | \mathbf{s}, \mathbf{t}_{> k})$$

三种特征

在训练完expert model之后,可以从中提取句对$(\mathbf{s}, \mathbf{m})$中的3种特征:

  • 隐变量$\mathbf{z}_k$:它应当包含了源句和译句的所有信息,以及正确翻译第k个token所需的语义信息
  • token embedding:对于第k个token,使用它前后token的embedding,即$(\mathbf{e}_{t_{k-1}}, \mathbf{e}_{t_{k+1}})$
  • 分类分布:令$p(t_k | \cdot)$为类别数量与词表大小相等的分类分布(categorical distribution),则$p(t_k | \cdot) \sim \text{Categorical}(softmax(\mathbf{I}_k))$

于是可以构造4维的mis-matching feature:

$$\mathbf{f}_k^{mm} = (\mathbf{I}_{k, m_k}, \mathbf{I}_{k, i_{max}}, \mathbf{I}_{k, m_k} - \mathbf{I}_{k, i_{max}}, \mathbb{I}_{m_k \neq i_{max}})$$

其中$m_k$是翻译输出中的第k个token,$i_max = \arg\max_i{\mathbf{I}_k}$为expert model预期的输出token,$\mathbb{I}$是概率分布。

(这预期输出token基本上就相当于是自己翻译了一遍吧……)

Bi-LSTM Quality Estimation

实验中发现encoder self-attention、Bi-Transformer和Bi-LSTM+CRF的效果都不如普通的Bi-LSTM,可能是因为训练数据不够多。因此直接使用了Bi-LSTM。

Bi-LSTM输入expert model生成的feature:

$$\overrightarrow{\mathbf{h}_{1:T}}, \overleftarrow{\mathbf{h}_{1:T}} = \text{Bi-LSTM}(\{\mathbf{f}_k\}_{k=1}^T)$$

然后通过回归方法预测HTER(因为HTER是整个句子的评分,因此只考虑Bi-LSTM的最后两个状态):

$$\arg\min{\lVert h - \text{sigmoid}(\mathbf{w}^T [\overrightarrow{\mathbf{h}_{T}}, \overleftarrow{\mathbf{h}_{T}}]) \rVert^2_2}$$

通过sequence labeling方法预测词的标签(其中XENT是cross entropy):

$$\arg\min{\sum_{k=1}^T \text{XENT}(y_k, \mathbf{W}[\overrightarrow{\mathbf{h}_{k}}, \overleftarrow{\mathbf{h}_{k}}])}$$

计算流图中的BPE

对于sentence-level QE,由于HTER是全局参数,显然使用BPE和不使用BPE没有太大的差别。但是对于word-level QE,BPE下序列的长度$L_b \neq L_{\omega}$(原序列长度)。因此作者提出了一种对一个词的所有subword unit的feature进行平均的方法:将BPE信息存储在一个$L_{\omega} \times L_b$的稀疏矩阵$S$中,其中仅当第j个subword unit属于第i个词时,$s_{ij} \neq 0$。此时就可以通过矩阵乘法计算平均后的feature,这使得计算流图是可微的。

通过这一方法使用BPE后,效果有一定的提升。

左侧为矩阵,右侧为实验效果

实验结果

预处理:筛选长度<=70且长度比在1/3~3范围内的句对

参数:

  • Bi-Transformer中每个模块的层数为2
  • feed-forward层的大小为512
  • 8 head self-attention

WMT17中sentence-level QE的结果

WMT18中sentence-level QE的结果

WMT17/18中word-level QE的结果

总的来说这一模型大获全胜。

在实验中,即使只留下mis-match feature(而去掉另外两种),结果仍然是比较好的(皮尔森相关系数r降低了约0.04)。(这不禁令人怀疑QE和MT到底有什么区别。)

论文地址:http://www.aclweb.org/anthology/N13-1073

这篇文章对IBM Model 2,一种在无监督情况下将双语语料进行对齐的方法进行了改进,提高了计算速度和对齐质量。

IBM Model 2

文章本身很短,但是为了明白文章在讲什么,首先需要搞懂IBM Model 2是什么。这篇文章用Fr-En翻译的例子说明了IBM Model 2的定义和训练方法。

用$(f_1, ..., f_m)$表示源句中的$m$个词,$(e_1, ..., e_l)$表示译句中的$l$个词,用$(f^{(k)}, e^{(k)})$表示第$k$个句对。

IBM Model 2是一种Noisy-Channel Approach,也就是说,它的模型分成以下两个部分:

  • 语言模型:$p(e)$,表示英语句子$e$在英语中出现的概率
  • 翻译模型:$p(f | e)$,表示在给定译句为$e$的条件下,源句为$f$的概率。

有趣的一点是,翻译模型是$p(f | e)$而非$p(e | f)$。(我也不知道为什么)

对齐模型(alignment model)

在翻译模型$p(f | e)$中加入对齐变量(alignment variables)$a_1, ..., a_m \in {0, 1, ..., l}$,得到$p(f_1 ... f_m, a_1 ... a_m | e_1 ...e_l, m)$。(上述模型假设已知分布$p(m | l)$,因此把$m$看作是定值)。其中$a_j$表示源句中的$f_j$与译句中的$e_{a_j}$对齐,或者说在概率模型中,$f_j$是由$e_{a_j}$生成的;$e_0$表示NULL,如果$a_j = 0$,说明$f_j$是由NULL生成的。

(上述“生成”说的是概率模型的生成,并不是实际翻译中的生成。)

IBM-M2模型的正式定义

一个IBM-M2模型包括一个固定的英语词集合$\mathcal{E}$,一个固定的法语词集合$\mathcal{F}$,以及$M$和$L$,分别表示法语和英语句子的最大长度。模型的参数如下:

  • $t(f | e), f \in \mathcal{F}, e \in \mathcal{E} \cup {\text{NULL}}$:表示从英语词$e$生成法语词$f$的概率
  • $q(j | i, l, m), l \in {1, ..., L}, m \in {1, ..., M}, i \in {1, ..., n}, j \in {0, ..., l}$:英语和法语句子的长度分别为$l$和$m$时,$a_i = j$($f_i$与$e_j$对齐)的概率

对于任意英语句子$e_1, ..., e_l$和长度$m$,定义法语句子$f_1, ..., f_m$和对齐变量$a_1, ..., a_m$的条件分布为

$$p(f_1 ... f_m, a_1 ... a_m | e_1 ... e_l, m) = \prod_{i=1}^{m} q(a_i | i, l, m) t(f_i | e_{a_i})$$


在这个模型中我们使用了一些独立性假设。令$L$为表示英语句子长度的随机变量,$E_1, ..., E_l$是表示英语句子中的词的随机变量;$M$是表示法语句子长度的随机变量,$F_1, ..., F_m$和$A_1, ..., A_m$是表示法语句子中的词和对齐的随机变量,则我们的目标是建立一个这样的模型:

$$P(F_1=f_1 ... F_m=f_m, A_1=a_1 ... A_m=a_m | E_1=e_1 ... E_l=e_l, L=l, M=m)$$
可以通过链式法则把上式分解成两项的乘积:

  • $P(A_1=a_1 ... A_m=a_m | E_1=e_1 ... E_l=e_l, L=l, M=m)$
  • $P(F_1=f_1 ... F_m=f_m | A_1=a_1 ... A_m=a_m, E_1=e_1 ... E_l=e_l, L=l, M=m)$

对于第一项,作如下独立性假设:

$$P(A_1=a_1 ... A_m=a_m | E_1=e_1 ... E_l=e_l, L=l, M=m) = \prod_{i=1}^{m} P(A_i=a_i | L=l, M=m)$$

即对齐变量$A_i$只与源句和译句的长度有关,和具体的词无关。(显然这只是一种假设)

对于第二项,作如下独立性假设:

$$P(F_1=f_1 ... F_m=f_m | A_1=a_1 ... A_m=a_m, E_1=e_1 ... E_l=e_l, L=l, M=m) = \prod_{i=1}^{m} P(F_i=f_i | E_{a_i} = e_{a_i})$$

即法语词$F_i$只与和它对齐的英语词$E_{a_i}$有关,和其他词均无关。(显然这只是一种假设)

IBM-M2模型的用途

  1. 翻译:$\arg\max_{e} p(e) p(f|e)$
  2. 语言(词法)模型:$t(f | e)$
  3. 对齐模型:$a_i = \arg\max_{j\in{0, ..., l}} (q(j | i, l, m) \times t(f_i | e_j))$

其中对齐模型是比较重要的一种用途。

估计IBM-M2模型的参数

数据观测充分的情况

在这种情况下,我们假设训练数据是这样的:$(f^{(k)}, e^{(k)}, a^{(k)})$。(一般来说,$a^{(k)}$是观察不到的)

这样就可以利用极大似然对参数进行估计:

  • $c(e, f)$:训练数据中英语词$e$与法语词$f$对齐的次数
  • $c(e)$:训练数据中英语词$e$与任意法语词对齐的总次数
  • $c(j | i, l, m)$:长度为$l$的法语句子中第$i$个词与长度为$m$的英语句子中第$j$个词对齐的次数
  • $c(i, l, m)$:训练数据中法语句子长度为$l$,英语句子长度为$m$的总数

$$t_{ML} (f | e) = \frac{c(e, f)}{c(e)}$$

$$q_{ML} (j | i, l, m) = \frac{c(j | i, l, m)}{c(i, l, m)}$$

算法伪代码

数据观测不充分的情况

在这种情况下,我们假设训练数据是这样的:$(f^{(k)}, e^{(k)})$。我们采用EM算法对参数进行估计:

  • 首先为各$t_{ML} (f | e)$和$q_{ML} (j | i, l, m)$参数估计一个初始值(比如随机取值)
  • 按照当前参数取值统计$c(e, f)$、$c(e)$、$c(j | i, l, m)$和$c(i, l, m)$的值
  • 更新各$t_{ML} (f | e)$和$q_{ML} (j | i, l, m)$参数,迭代直到收敛

其中最主要的区别是把原来的

$$\delta(k, i, j) = 1 , \text{if} , a_i^{(k)} = j, 0 , \text{otherwise}$$(只有确实对齐时才取1,其他时候取0)

换成了

$$\delta(k, i, j) = \frac{q(j | i, l_k, m_k) t(f_i^{(k)} | e_j^{(k)})}{\sum_{j=0}^{l_k} q(j | i, l_k, m_k) t(f_i^{(k)} | e_j^{(k)})}$$(在当前参数下$a_i=j$的概率)

可以证明EM算法是收敛的,但是可能会收敛到局部极小值。所以可以用Model 1对参数进行初始化。详细的内容略。

算法伪代码

fast align

这一模型采用了IBM-M2模型的基本思路,但是减少了其中的参数个数。按论文中的表示法,这个模型是这样定义的:

  • 令$n$表示源句长度,$m$表示译句长度,定义两个新的参数$p_0$和$\lambda$
  • 令$h(i, j, m, n) = -|\frac{i}{m} - \frac{j}{n}|$
  • 令$\delta(a_i = j | i, m, n)$表示源句和译句长度分别为$m$和$n$时,$a_i = j$的概率(相当于之前的$q(j | i, l, m)$)
  • 令$\theta(e_i | f_{a_i})$表示从英语词$e_i$生成法语词$f_{a_i}$的概率(相当于之前的$t(f | e)$)
$$\delta(a_i = j | i, m, n) = \begin{cases} p_0 & j = 0 \\ (1 - p_0) \times \frac{e^{\lambda h(i, j, m, n)}}{Z_{\lambda}(i, m, n)} & 0 < j \leq n \\ 0 & \text{otherwise} \end{cases} $$

其中$Z_{\lambda}(i, m, n) = \sum_{j'=1}^{n} \exp{\lambda h(i, j', m, n)}$

这相当于是把原来每组$(i, j, m, n)$都对应一个参数的情况修正成了只通过已知函数$h$和$p_0$、$\lambda$两个参数来确定对齐。其中$p_0$表示的是无对齐的概率

根据参数计算给定句对的最大似然概率和对齐

给定句对$(f, e)$和参数,则:

  • 译句中第$i$个词为$e_i$,且$e_i$和$f_{a_i}$对齐的概率为:$p(e_i, a_i | f, m, n) = \delta(a_i | i, m, n) \times \theta(e_i | f_{a_i})$
  • 译句中第$i$个词为$e_i$的概率为:$p(e_i | f, m, n) = \sum_{j=0}^{n} p(e_i, a_i=j | f, m, n)$
  • 因此:$p(e | f) = \prod_{i=1}^{m} p(e_i, a_i=j | f, m, n) = \prod_{i=1}^{m} \sum_{j=0}^{n} \delta(a_i | i, m, n) \times \theta(e_i | f_{a_i})$

通过一些优化手段,我们可以使$\delta(a_i | i, m, n)$的计算复杂度是$O(1)$的。


显然$\delta(a_i | i, m, n)$的计算瓶颈在于$Z_{\lambda}(i, m, n)$;$Z_{\lambda}(i, m, n)$显然可以在$O(n)$时间复杂度内进行计算,但事实上可以是$O(1)$的。考虑到$h(i, j, m, n) = -|\frac{i}{m} - \frac{j}{n}|$,事实上$Z_{\lambda}(i, m, n)$是两个等比数列的和:

  • 令$j_{\uparrow} = \lfloor \frac{i \times n}{m} \rfloor$,$j_{\downarrow} = j_{\uparrow} + 1$
  • 则$Z_{\lambda}(i, m, n) = \sum_{j'=1}^{j_{\uparrow}} \exp{\lambda h(i, j', m, n)} + \sum_{j' = j_{\downarrow}}^{n} \exp{\lambda h(i, j', m, n)}$
  • 其中$\sum_{j'=1}^{j_{\uparrow}} \exp{\lambda h(i, j', m, n)} = e^{\lambda j_{\uparrow}} + e^{\lambda (j_{\uparrow} - 1/n)} + e^{\lambda (j_{\uparrow} - 2/n)} + ...$
  • $\sum_{j' = j_{\downarrow}}^{n} \exp{\lambda h(i, j', m, n)} = e^{\lambda j_{\downarrow}} + e^{\lambda (j_{\downarrow} - 1/n)} + e^{\lambda (j_{\downarrow} - 2/n)} + ...$

因此可以在$O(1)$时间内计算$Z_{\lambda}(i, m, n)$。

根据训练数据计算参数

这一模型也可以通过EM算法来进行训练。$\theta(e_i | f_{a_i})$的更新方法和之前类似,并使用了(一些我看不懂的数学)进行优化;$\lambda$参数则需要用梯度方法来进行更新(另一些我没看懂的数学)。事实上,$\delta(j | i, m, n)$的导数也具有类似的规律性,因此也可以用相同的方法来计算梯度,复杂度比较低。

评价

这个模型能够用无监督且非常快速的方式计算出源句和译句之间的对齐,是一种非常有趣且已经被广泛使用的方法。不过由于模型和方法本身的限制,这个模型的对齐质量仍然不是很高。不过,在NMT方法中我们仍然可以利用这一方法生成的对齐的质量来对训练语料进行初步的预处理。

论文地址:Findings of the WMT 2018 Shared Task on Quality Estimation

这篇文章报告了WMT18 Quality Estimation任务的结果。

各系统及提交者

本次参与评测的一共有10个系统(其中UAlacant和RTM因为迟交没有计入正式排名):

系统名称 提交者 具体提交 参与任务 Task1 Task2 Task3 Task4
CMU-LTI CMU 1. CMU-LTI T2 - 次于QEBrain,和SHEF-PT表现相当 - -
JU-USAAR Jadavpur University & University of Saarland 1. Bag-of-Words
2. Doc2Vec
T2 - 低于baseline - -
MQE Vicomtech 1. sMQE
2. uMQE
T1 和baseline持平 - - -
QEbrain 阿里 1. QEBrain DoubleBi w/ BPE+word-tok
2. QEBrain DoubleBi w/ BPE+word-tok (ensemble)
T1, T2 QEBrain和UNQE并列第一,远高于其他系统 第一名,且gap error detection子任务表现非常好 - -
RTM Biçici 1. RTM
2. RTM_MIX1
3. RTM_MIX5
4. RTM_MIX6
5. RTM_MIX7
T1-T4 在NMT数据集上接近UNQE和QEBrain的结果 低于baseline 低于baseline 远不如baseline
SHEF University of Sheffield 1. SHEF-PT
2. SHEF-bRNN
3. SHEF-ATT-SUM
4. SHEF-PT-indomain
5. SHEF-mtl-bRNN
6. SHEF-mtl-PT-indomain
T1-T4 大致处于排名中间位置 第二名(因为很多系统没有参与Task2) 与baseline相当 略高于baseline
TSKQE 汉堡大学 1. TSKQE1
2. TSKQE2
T1 第三名(低于QEBrain和UNQE) - - -
UAlacant University of Alacant 1. UAlacant T1, T2 和baseline相当 低于baseline
UNQE 江西师范大学 UNQE T1 和QEBrain并列第一,远高于其他系统 - - -
UTaru University of Taru 1. UTartu/QuEst+Attention
2. UTartu/QuEst+Att+CrEmb3
T1, T2 略高于baseline 低于baseline - -

可以看出,这次比赛中,QEBrain和UNQE系统的效果是最好的,其次是CMU-LTI、TSKQE和SHEF。

QEBrain(T1,T2,阿里)

QEBrain系统的参赛者已经把论文贴到Arxiv上了(“Bilingual Expert” Can Find Translation Errors),之后我会再去仔细读……不过简单来说好像是这样的:

  • feature extraction (target language) model(作为特征提取器)
    • multi-head self-attention
    • 源语言的transformer encoder
    • 目标语言的bi-transformer encoder
  • 预训练过的双向transformer(作为预测器)
    • 输入上述特征提取器得到的特征和baseline系统提供的特征

并且进行了ensemble。

UNQE(T1,江西师范大学)

他们把论文投到IEICE了(A Unified Neural Network for Quality Estimation of Machine Estimation),之后我会再去仔细读……不过简单来说好像是这样的:

  • bi-RNN encoder-decoder + attention:从翻译输出中提取quality vector
  • RNN:通过quality vector预测翻译输出的HTER值

模型进行了预训练;输出结果进行了模型平均。

CMU-LTI(T2,CMU)

他们也把论文贴到arXiv了(Contextual Encoding for Translation Quality Estimation)。模型分为三个主要部分:

  • embedding layer:表示词和POS tag
  • 1d convolution layer:将每个词和它的local context结合起来
  • stack of feed-forward and RNN: 将每个词和它的global context结合起来;同时输入一些句法feature

TSKQE(T1,汉堡大学)

我确实没找到他们今年的论文(只找到了去年的,UHH Submission to the WMT17 Quality Estimation Shared Task);他们的做法好像是对源句应用sequence kernel、tree kernel,对译句应用candidate translation和back-translation,预测HTER得分。(我并没有看懂这些,好像是一种非深度学习的approach)

SHEF(T1-T4,University of Sheffield)

唯一在四个任务上都有正式提交的系统。我仍然没有找到他们今年的论文,但我找到了他们的一个类似的开源项目。今年他们提交了两个不同架构的系统:

  • SHEF-PT:由Predictor和Estimator组成
    • Predictor:经过一定修改的encoder-decoder RNN模型
    • Estimator:bi-RNN,基于Predictor的输出进行预测
    • 可以进行multi-task learning
  • SHEF-bRNN:
    • 用两个bi-RNN(GRU)学习(source, translation)对,输出word-level的预测
    • 用attention机制对bi-RNN的输出(word-level的预测)进行加权平均,得到sentence-level的预测

对于phrase-level的预测,他们使用的是标准的基于attention的MT架构,将word-level的预测加权平均得到结果;对于预测source tag的任务,是把两边的输出反过来;对于document-level的任务,同时使用了PT和bRNN两种架构。


剩余的分数不太高的系统就不仔细看了。感觉NN方法占据了绝对优势。

Task1(句级QE)结果及讨论

这一任务的目标是对翻译输出的质量进行打分或排名。训练数据的label包括HTER、post-editing时间和post-editing中键盘敲击统计。

评价方法主要是皮尔森相关系数r(打分)和斯皮尔曼等级相关系数(排名)。

baseline是QUEST++:提取feature,用SVR+RBF kernel进行回归训练。

En-De数据集测试结果

De-En数据集测试结果

En-Lv数据集测试结果

En-Cs数据集测试结果

在该任务上表现最好的系统显然是QEBrain和UNQE,且它们的表现都远好于第三名;其中SHEF-PT是去年在该任务上表现最好的。这说明了Transformer技术应用在QE任务上之后大大提高了QE的表现。

SMT和NMT数据集的生成方法相同(分别用SMT和NMT系统对一个初始数据集进行翻译,进行post-edit,再移除其中过多的HTER=0的句对),但由于NMT的翻译效果远优于SMT,导致NMT数据集比较小,这也使得我们无法直接对SMT和NMT数据集上的结果进行比较;同时,NMT数据集上的平均HTER分数也更低,这些可能是导致En-De数据集上各系统普遍在NMT数据上表现较差的原因。但是在En-Lv数据集上,这一趋势完全是相反的,NMT数据上系统的表现较好。不过系统在不同数据集上的排名是类似的,说明QE系统一般具有鲁棒性。

另一个事实是,没有系统使用了post-editing时间和post-editing中键盘敲击统计这两种label。

Task2(词级QE)结果及讨论

这个任务相当于有三个子任务,分别对三种不同的token进行标记,并分别进行测试:

  • 译句中的普通token:根据post-edited版本进行标注,应被替换和删除的标记为BAD,其余标为OK
  • 译句中的gap token:在译句中每个token之后和句首插入gap token(也就是说,如果原来有N个token,插入之后会变成2*N+1个token),如果gap token对应位置相比post-edited版本发生漏词,则该gap token标记为BAD;否则标为OK
  • 源句中的token:使用fastalign工具将源句和post-edited版本的译句进行对齐;对于源句中的每个token,如果和它对齐的post-edited版本的译句中的token在译句中被删除或替换,则该token标记为BAD;否则标为OK

评价方式:对上述每种token的OK和BAD类别分别计算F1分数并相乘,以F1-mult作为最终评分标准。

baseline:提取feature后,作为sequence prediction问题,用CRF算法进行训练。

En-De数据集测试结果

De-En数据集测试结果

En-Cs数据集测试结果

En-Lv数据集测试结果

由于在各个数据集上进行提交的系统都不太一样,所以很难进行完整的比较。

参与En-De和De-En任务的系统最多;和往年一样,Task1的结果和Task2的结果相关性很强,所以QEBrain在task2也获胜了。由于UNQE等系统没有参与Task2,表现次好的系统是SHEF-PT,落后得稍微少一点。

对于En-De数据集,很显然各个系统在NMT数据集上的表现远差于SMT数据集;而En-Lv数据集中,系统在SMT数据集上表现更好,这和Task1也相同。

只有很少几个系统提交了gap检测和导致错误的源词的新任务;这些系统的表现都比较一般,但结果和在主任务上的表现是相关的。QEBrain系统在gap检测上的表现非常之好(没有在其他任务上提交)。并且从分数可以看出,预测源句中导致错误的token比预测译句中的错误token更难;这可能是因为“源句中导致错误的token”有更多的可能性。

En-Lv NMT数据集上,所有系统都只能达到baseline的效果;En-Cs数据集上所有系统的表现都差不多。这可能是因为预处理数据资源不够。

Task3(短语级QE)结果及讨论

短语有四类标注:

  • OK:正确的短语
  • BAD:包含错误的短语
  • BAD_word_order:短语在句中位于错误的位置
  • BAD_omission:短语前后缺词

这一任务分成两个子任务:

  • Task3a:和Task2一样,在译句中每个token之后和句首插入gap token;然后用SMT decoder将译句分成短语,对短语进行标注:最后将标注结果标到具体的词上,相当于这也是一个word-level的任务
  • Task3b:直接对短语进行标注,每个短语前后各有一个gap token,gap可能被标注为OK或BAD_omission。

评价方式:

  • Task3a:和Task 2相同,都是OK和BAD类别下的F1-mult
  • Task3b:短语级别的F1-mult

这一任务只有De-En数据集,数据是手动标注的(而非post-edit后再自动生成的)。

baseline:提取feature后,作为sequence labelling问题,用CRF算法进行训练。

De-En数据集测试结果

和Task2的De-En结果相比,BAD类别的F1分数显著降低了。这一现象可能是因为数据生成的方式导致的,phrase label粒度更粗一些。

事实上,只有SHEF-PT和SHEF-bRNN系统参与了这一任务;它们在Task3a上的表现和baseline差不多,在Task3b上还不如baseline。作者据此认为短语级别的预测仍然是很有挑战的任务,但我觉得样本量太少了,也不是很有代表性。不过这可能说明我们需要更好的神经网络结构。

Task4(文档级QE)结果及讨论

这一任务的要求是对整个文档的翻译质量进行打分。文档中在accuracy、fluency和style三个方面出错的词被标出,并根据严重程度分为minor、major和critical三类;文档的真实得分由人类打出。

评价方式是预测得分和真实得分的皮尔森相关系数r。

baseline:QUEST++

En-Fr数据集测试结果

显然,baseline的得分已经很高了;只有SHEf-PT-indomain的分数稍高于baseline。这说明Task4是一项很难的任务;同时很难评价系统在这一任务上的表现。

今天我决定照着UserManual里给出的方法训练一个小型的模型尝试一下,了解一下各个步骤都在做什么。

一些微小的问题

tensorflow-gpu

我首先尝试在自己的电脑上安装tensorflow-gpu。最后我虽然装上了,但却决定不用它了,因为我意识到我的这块普通显卡过于菜了(以至于nvidia-smi不能打印它的具体信息),这么做没什么太大的意义。

PyCharm和virtualenv

目前我的所有Python项目都是通过这两个东西运行的,看起来还不错;可是virtualenv存在一个问题,就是不容易卸载,或者说卸载包的时候可能会出一点问题——反正我卸载tensorflow-gpu再安装tensorflow之后,根本都找不到Module tensorflow了。但这大概不算什么大问题,因为网上的人都说[1],"virtualenv is cheap",如果把当前的环境搞乱了,直接删了新建一个就好。

virtualenv还有一个我之前没有想到的好处。它不止可以管理Python包,还可以管理环境变量。UserManual里要求在$PYTHONPATH里加上项目根路径,我一开始不太理解为什么,后来发现如果不加的话根本就找不到THUMT自己的包。我还以为是PyCharm没有定义好源文件夹的问题或者tensorflow挂了的问题呢。看来我对Python模块化和类编程根本就不是很熟悉……

总之在virtualenv里可以在venv/bin/activate中增加以下命令来修改虚拟环境中的环境变量[2]

1
2
_OLD_PYTHONPATH="$PYTHONPATH"
export PYTHONPATH="/path/to/THUMT:$PYTHONPATH"

然后在deactivate()函数中增加以下内容:

1
export PYTHONPATH="$_OLD_PYTHONPATH"

可以使用printenv PYTHONPATH以查看设置情况。

当然实际上应该写得更复杂一点,activate文件中本身就有设置和取消设置环境变量的例子,这里就先这样好了。

准备数据

语料

UserManual中使用的示例语料来自http://data.statmt.org/wmt17/translation-task/preprocessed/de-en/,是经过预处理的语料。不过这些语料到底经历了怎样的预处理呢……

被预处理完的corpus是这个样子的(取了前5个句子):

Deutsch English
Europäische Kommission - Upcoming events European Commission - Upcoming events
die Nachricht : the news :
die Anmeldung zur Veranstaltung kann vorgenommen werden . registration for the event can be submitted .
Hintergrund : the background :
die folgen dem Vorbild der &quot; Gemeindeversammlung &quot; bzw. lokaler Bürgerforen , bei denen Vertreter der Politik sich mit Bürgerinnen und Bürgern über politische Fragen und anstehende Entscheidungen austauschen . the concept of builds on the model of &quot; town hall meetings &quot; or local fora during which politicians listen and debate with citizens about policies and decisions being taken .

被预处理完的测试数据是这个样子的:

Deutsch English
Gutach : noch mehr Sicherheit für Fußgänger Gutach : increased safety for pedestrians
Sie stehen keine 100 Meter voneinander entfernt : am Dienstag ist in Gutach die neue B 33 @-@ Fußgängerampel am Dorfparkplatz in Betrieb genommen worden - in Sichtweite der älteren Rathausampel . they are not even 100 metres apart : on Tuesday , the new B 33 pedestrian lights in Dorfparkplatz in Gutach became operational - within view of the existing Town Hall traffic lights .
zwei Anlagen so nah beieinander : Absicht oder Schildbürgerstreich ? two sets of lights so close to one another : intentional or just a silly error ?
diese Frage hat Gutachs Bürgermeister gestern klar beantwortet . yesterday , Gutacht &apos;s Mayor gave a clear answer to this question .
&quot; die Rathausampel ist damals installiert worden , weil diese den Schulweg sichert &quot; , erläuterte Eckert gestern . &quot; at the time , the Town Hall traffic lights were installed because this was a school route , &quot; explained Eckert yesterday .

至少可以看出有一部分符号被转义了(@-@),而且符号也进行了分词。

根据prepare.sh,训练数据经过了以下处理:

测试数据是从.sgm格式转换来的,所以前面多一个input-from-sgm,其他的处理都一样。

BPE

然后就是用rsennrich/subword-nmt中提供的脚本对原始语料进行BPE处理。此处我尝试对训练语料(单语大小约800M)跑了一下BPE,发现花了一个多小时,遂放弃,准备把其中一个测试集当做训练集来用。

以及现在subword-nmt这个仓库的使用方式已经有了一些变化,目前推荐的是pip install subword-nmt,然后直接通过包来调用脚本(而不是直接调用脚本):

1
subword-nmt learn-joint-bpe-and-vocab --input {train_file}.L1 {train_file}.L2 -s {num_operations} -o {codes_file} --write-vocabulary {vocab_file}.L1 {vocab_file}.L2

于是得到了BPE编码文件(其中</w>应该表示的是词尾):

2018.11.28 UPDATE:感谢评论区@ao ben指出,BPE编码文件中</w>表达的应该是单词的结尾。阅读了一些代码[5]之后,我想这个文件可能从上到下表示了将词中的字母进行合并的顺序。

1
2
3
4
5
6
7
8
9
10
11
12
#version: 0.2
e n</w>
e r
i n
t h
e r</w>
c h
a n
e n
u n
th e</w>
...

和两种语料上的词汇表:

1
2
3
4
5
6
7
8
9
10
11
12
, 3761
. 2782
die 2067
der 1761
und 1263
&quot; 1156
in 1022
@-@ 710
das 667
zu 645
von 629
... (Deutsch)
1
2
3
4
5
6
7
8
9
10
11
12
the 4290
, 3050
. 2776
of 1700
to 1693
a 1369
in 1291
and 1259
&quot; 1182
@-@ 658
is 615
... (English)

然后用上述得到的BPE编码文件和词汇表对训练集、验证集、测试集的源语言一侧分别进行编码。以训练集为例,此时就得到了一堆这样的东西:

Deutsch Deutsch (BPE)
Gutach : noch mehr Sicherheit für Fußgänger G@@ u@@ t@@ a@@ c@@ h : noch mehr S@@ i@@ c@@ h@@ er@@ h@@ e@@ i@@ t für F@@ u@@ ß@@ g@@ ä@@ n@@ g@@ er
Sie stehen keine 100 Meter voneinander entfernt : am Dienstag ist in Gutach die neue B 33 @-@ Fußgängerampel am Dorfparkplatz in Betrieb genommen worden - in Sichtweite der älteren Rathausampel . Sie s@@ t@@ e@@ h@@ en keine 1@@ 0@@ 0 M@@ e@@ t@@ er v@@ o@@ n@@ ein@@ an@@ der e@@ n@@ t@@ f@@ er@@ n@@ t : am D@@ i@@ e@@ n@@ s@@ t@@ a@@ g ist in G@@ u@@ t@@ a@@ c@@ h die n@@ e@@ u@@ e B 3@@ 3 @-@ F@@ u@@ ß@@ g@@ ä@@ n@@ g@@ er@@ a@@ m@@ p@@ e@@ l am D@@ o@@ r@@ f@@ p@@ a@@ r@@ k@@ p@@ l@@ a@@ t@@ z in B@@ e@@ t@@ r@@ i@@ e@@ b g@@ e@@ n@@ o@@ m@@ m@@ en worden - in S@@ i@@ c@@ h@@ t@@ w@@ e@@ i@@ te der ä@@ l@@ t@@ er@@ en R@@ a@@ t@@ h@@ a@@ u@@ s@@ a@@ m@@ p@@ e@@ l .
zwei Anlagen so nah beieinander : Absicht oder Schildbürgerstreich ? zwei A@@ n@@ l@@ a@@ g@@ en so n@@ a@@ h b@@ e@@ i@@ ein@@ an@@ der : A@@ b@@ s@@ i@@ c@@ h@@ t oder S@@ c@@ h@@ i@@ l@@ d@@ b@@ ü@@ r@@ g@@ er@@ s@@ t@@ r@@ e@@ i@@ c@@ h ?
diese Frage hat Gutachs Bürgermeister gestern klar beantwortet . diese F@@ r@@ a@@ g@@ e hat G@@ u@@ t@@ a@@ c@@ h@@ s B@@ ü@@ r@@ g@@ er@@ m@@ e@@ i@@ s@@ t@@ er ge@@ s@@ t@@ er@@ n k@@ l@@ a@@ r be@@ an@@ t@@ w@@ o@@ r@@ t@@ e@@ t .
&quot; die Rathausampel ist damals installiert worden , weil diese den Schulweg sichert &quot; , erläuterte Eckert gestern . &quot; die R@@ a@@ t@@ h@@ a@@ u@@ s@@ a@@ m@@ p@@ e@@ l ist d@@ a@@ m@@ als i@@ n@@ s@@ t@@ a@@ l@@ l@@ i@@ er@@ t worden , w@@ e@@ i@@ l diese den S@@ c@@ h@@ u@@ l@@ w@@ e@@ g s@@ i@@ c@@ h@@ er@@ t &quot; , er@@ l@@ ä@@ u@@ t@@ er@@ te E@@ c@@ k@@ er@@ t ge@@ s@@ t@@ er@@ n .
English English (BPE)
Gutach : increased safety for pedestrians G@@ u@@ t@@ a@@ c@@ h : i@@ n@@ c@@ re@@ a@@ s@@ e@@ d s@@ a@@ f@@ e@@ t@@ y for p@@ e@@ d@@ e@@ s@@ t@@ r@@ i@@ a@@ n@@ s
they are not even 100 metres apart : on Tuesday , the new B 33 pedestrian lights in Dorfparkplatz in Gutach became operational - within view of the existing Town Hall traffic lights . they are not even 1@@ 0@@ 0 m@@ e@@ t@@ re@@ s a@@ p@@ a@@ r@@ t : on T@@ u@@ e@@ s@@ d@@ a@@ y , the new B 3@@ 3 p@@ e@@ d@@ e@@ s@@ t@@ r@@ i@@ an l@@ i@@ g@@ h@@ t@@ s in D@@ o@@ r@@ f@@ p@@ a@@ r@@ k@@ p@@ l@@ a@@ t@@ z in G@@ u@@ t@@ a@@ c@@ h b@@ e@@ c@@ a@@ m@@ e o@@ p@@ e@@ r@@ a@@ t@@ i@@ o@@ n@@ a@@ l - w@@ i@@ t@@ h@@ in v@@ i@@ e@@ w of the e@@ x@@ i@@ s@@ t@@ ing T@@ o@@ w@@ n H@@ all t@@ r@@ a@@ f@@ f@@ i@@ c l@@ i@@ g@@ h@@ t@@ s .
two sets of lights so close to one another : intentional or just a silly error ? two s@@ e@@ t@@ s of l@@ i@@ g@@ h@@ t@@ s so c@@ l@@ o@@ s@@ e to one a@@ n@@ other : i@@ n@@ t@@ e@@ n@@ t@@ i@@ o@@ n@@ a@@ l or j@@ u@@ s@@ t a s@@ i@@ l@@ l@@ y e@@ r@@ r@@ o@@ r ?
yesterday , Gutacht &apos;s Mayor gave a clear answer to this question . y@@ e@@ s@@ t@@ e@@ r@@ d@@ a@@ y , G@@ u@@ t@@ a@@ c@@ h@@ t &apos;s M@@ a@@ y@@ or g@@ a@@ v@@ e a c@@ l@@ e@@ a@@ r a@@ n@@ s@@ w@@ e@@ r to this q@@ u@@ e@@ s@@ t@@ i@@ on .
&quot; at the time , the Town Hall traffic lights were installed because this was a school route , &quot; explained Eckert yesterday . &quot; at the time , the T@@ o@@ w@@ n H@@ all t@@ r@@ a@@ f@@ f@@ i@@ c l@@ i@@ g@@ h@@ t@@ s were i@@ n@@ s@@ t@@ a@@ l@@ l@@ e@@ d because this was a s@@ c@@ h@@ o@@ o@@ l r@@ o@@ u@@ t@@ e , &quot; e@@ x@@ p@@ l@@ a@@ i@@ n@@ e@@ d E@@ c@@ k@@ e@@ r@@ t y@@ e@@ s@@ t@@ e@@ r@@ d@@ a@@ y .

我猜@@指示的是词中间的分词。显然这不是一个正常的学习状况——因为学习的语料太少,词语出现频率不够,很多常见词都被切成字母了。我猜这将导致最后的测试结果不太像人类语言(如果还能跑出测试结果的话……)。不过可以看出,这个BPE还是学到了一些最常用的词汇的,比如德语的sie,am,ist,diese,den,英语的they,are,other,all等。

shuffle

据说这一步可以提高翻译质量(虽然我目前还不知道为什么)。我之前猜测可能和ensemble有关,不过这一点还需要思考一下。

生成NMT使用的词表

这一步的工作不需要用到之前生成的BPE操作和词表,而是由THUMT里的脚本直接从训练数据中再生成一次词表。我目前还不知道为什么要这么做——当然,这么做肯定没有问题,而且还有通用性。显然里面添加了一些控制字符。

1
2
3
4
5
6
7
8
9
10
11
<pad>
<eos>
<unk>
e@@
i@@
n@@
s@@
t@@
a@@
h@@
... (Deutsch)
1
2
3
4
5
6
7
8
9
10
11
<pad>
<eos>
<unk>
e@@
a@@
i@@
t@@
o@@
r@@
n@@
... (English)

训练

训练的时候主要有这样的一些参数:

  • input:经过BPE和shuffle的训练数据(de+en)
  • vocabulary:通过脚本从经过BPE处理的训练数据中提取的词表(de+en)
  • model:使用的模型(目前使用的是推荐的transformer
  • validation:经过BPE的验证数据(de)
  • references:经过BPE的验证数据(en)
  • parameters:其他超参数
    • batch_size:每个batch训练多少个词
    • device_list:使用哪些显卡进行训练
    • train_steps:迭代次数
    • eval_steps:训练多少步输出一次在验证集上的BLEU值
    • keep_checkpoint_max:最多保留几个中间checkpoint
    • keep_top_checkpoint_max:最多保留几个最佳checkpoint

目前我正在我的垃圾小电脑上用batch_size=400, train_steps=2000的参数训练(毕竟现在训练集只有25万个词),已经输出了两个checkpoint,但它似乎卡在计算模型在验证集上的BLEU值这一步上了……好像验证这一步的确是比较慢的,我打算明天再看到底是TensorFlow卡死了,还是单纯太慢了。

To be continued...

UPDATE:跑了一晚上,终于验证出一个结果了。程序输出如下图:

1
2
3
INFO:tensorflow:BLEU at step 2000: 0.001024
INFO:tensorflow:Copying train/model.ckpt-2000 to train/eval/model.ckpt-2000
INFO:tensorflow:Best score at step 2000: 0.001024

并在train/eval中保留了这个checkpoint。

(0.001,这个BLEU值还真是惊人的低呢……虽然训练过程只花了大约两个小时,验证花了可能得有10个小时……)

测试

下面就可以尝试用训练出的模型对测试集进行翻译了。使用的参数包括:

  • models:模型
  • checkpoints:模型checkpoints位置,可以通过输入多个模型的checkpoints位置进行ensemble
  • input:经过BPE的测试数据(de)
  • output:翻译结果(en)
  • vocabulary:通过脚本从经过BPE处理的训练数据中提取的词表(de+en),需要与训练使用的词表保持一致
  • parameters:其他超参数

垃圾小电脑大约需要1.5小时才能跑完一个batch,不知道一共有多少个batch……

To be continued...

2018.10.8 UPDATE:跑完了,一共94个batch。删除BPE分词之后,得到了这样的东西:

Deutsch English English (Translated)
Obama empfängt Netanyahu Obama receives Netanyahu <unk> Progen<unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>
das Verhältnis zwischen Obama und Netanyahu ist nicht gerade freundschaftlich . the relationship between Obama and Netanyahu is not exactly friendly . <unk> <unk> staff<unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>
die beiden wollten über die Umsetzung der internationalen Vereinbarung sowie über Teherans destabilisierende Maßnahmen im Nahen Osten sprechen . the two wanted to talk about the implementation of the international agreement and about Teheran &apos;s destabilising activities in the Middle East . <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>
bei der Begegnung soll es aber auch um den Konflikt mit den Palästinensern und die diskutierte Zwei @-@ Staaten @-@ Lösung gehen . the meeting was also planned to cover the conflict with the Palestinians and the disputed two state solution . <unk> <unk> <unk> st<unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>
das Verhältnis zwischen Obama und Netanyahu ist seit Jahren gespannt . relations between Obama and Netanyahu have been strained for years . <unk> <unk> <unk> <unk> st<unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>

可以看出,这个模型根本什么都没翻译出来。考虑到BPE把词都切成字母了,这一点也可以想象得到。最后可以通过Moses里提供的脚本计算验证集的BLEU值:

1
BLEU = 0.00, 0.0/0.0/0.0/0.0 (BP=1.000, ratio=5.679, hyp_len=372780, ref_len=65647)

虽然我猜BLEU值应该并没有低到严格为0,但是显然已经被四舍五入为0了。简直低破天际。

模型平均和集成

THUMT支持model averaging(把训练过程中生成的部分checkpoint进行平均)和model ensemble(对同一模型的不同训练结果进行ensemble)。以后有时间的话我要去读一下ensemble是怎么实现的。不过现在就不用这些功能了……

可视化

TensorBoard

在训练过程中,train/文件夹下打印出了一个events.out.tfevents文件,可以用TensorBoard进行可视化。

TensorBoard整体示意图(其中只有Graph的内容能看懂)

batch_examples

batch_examples:处理数据

从代码中可知,这个结点在trainer.py中通过调用record.py中的get_input_features函数生成,其中batch_examples函数大概是做了一个将输入数据按长度分块的工作,内部调用了tf.contrib.training.bucket_by_sequence_length函数。

embedding

Transformer结点中显示在左下角的是embedding结点:

embedding:将one hot向量embed成稠密向量

source_embeddingtarget_embedding分别定义于transformer.py/encoding_graphtransformer.py/decoding_graph中,它们并不是Encoder和Decoder结点的一部分。至于bias……好吧,我目前还不知道这个bias是干什么的。

(不,我现在意识到了,之前的描述中为了简便起见忽略了所有bias项,但显然这些项还是得有的。)

encoder

encoder:整个Transformer的encoder

图中encoder的输入有两个:一个是dropoutadding_timing_signal -> dropout),一个是attention_biasSequenceMask -> attention_bias)。我觉得数据应该是通过dropout输入的(因为按照Transformer的论文,数据是加了time signal之后输入到encoder的……),不过我现在只发现数据从batch_examples输入到SequenceMask了。

以及几乎所有结点都有一个叫create_train_op的输入,这个结点定义在optimize.py里,我猜测它是TensorFlow生成的后向图,用于对参数进行更新。

encoder内部的6个layer

encoder的内部是这样的:6个layer连在一起,这一点倒是很清楚。

encoder中一个layer的结构:attention+前馈网络

每一层内部都是self_attention加上feed_forward

attention的内部结构:multi-attention+layer-normalization

self_attention这个部分中,主要就是multihead_attention进行dropout和layer-normalization。

multi-attention的内部结构:split+merge

在这个结点中,输入似乎首先被用于计算出q、k、v三个部分,然后再在q、k、v的计算中各自进行多个操作(所以只有3个split_heads结点……?),最后再通过combine_heads合并在一起。

decoder

decoder

decoder的输入包括翻译后的数据(如果有的话)、bias和encoder的输出。

decoder内部由6层组成

decoder内部也由6个layer组成,其中每一个layer的输入除了前一个layer的输入外,还有数据、bias和encoder的输出(大概是这样的)。

decoder的一层:self-attention + encoder-decoder attention + 前馈网络

每个layer内部由self_attentionencdec_attentionfeed_forward三部分组成,其中接收encoder输出的是encdec_attentionself_attentionencdec_attention的结构与encoder的self_attention结构基本相同,但是在q、k、v的计算上有一些差异。以及feed_forward中含有一个ffn_layer

softmax

linear + softmax:输出概率

decoder的输出通过softmax层得到概率。(大概是这样的)

Relevance

UserManual中提供了计算每个源句和翻译出来的目标句之间的relevance矩阵的工具。不过鉴于我这个结果的翻译质量,就先不去尝试了……


  1. StackOverflow - How can I remove unused packages from virtualenv?

  2. StackOverflow - How do you set your pythonpath in an already-created virtualenv?

  3. Moses - Preparing Training Data

  4. Moses - Truecaser

  5. PLM's blog - subword-units

代码:THUMT

目录结构

目前thumt/文件夹下的目录结构是这样的:

  • bin/
    • get_relevance.py:输入训练好的模型checkpoints、模型在测试数据上的输入和输出、词表,输出测试数据中每个句子及其翻译之间的关联矩阵。(似乎只对Transformer和RNNsearch模型有效)。
    • scorer.py:暂时不知道是做什么的。
    • trainer.py:用于训练模型,输入训练数据、词表、验证数据、参数,输出训练模型的checkpoints和在验证集上的得分。
    • translator.py:用训练好的模型对测试数据进行翻译,输入模型checkpoints、测试数据、词表,输出翻译结果。
  • data/
    • __init__.py:这是一个模块。
    • cache.py:从字义上看好像是存储feature用的,实际上看不懂。
    • dataset.py:输入训练和验证数据文件,将数据分成batch。
    • record.py:看起来和dataset.py有点像,仍然不知道是干什么的。
    • vocab.py:加载和处理词表。
  • interface/
    • __init__.py:这是一个模块。
    • model.py:表示NMT模型的抽象类NMTModel
  • layers/
    • __init__.py:这是一个模块。
    • attention.py:Attention机制的实现。
    • nn.py:一些神经网络层的实现,包括linearmaxout
    • rnn_cell.py:GRU的实现,以及一些wrapper。
  • models/
    • __init__.py:这是一个模块。
    • rnnsearch.py:RNNsearch模型的实现。
    • rnnsearch_lrp.pyLRP和RNNsearch模型的实现。
    • seq2seq.py:Seq2Seq模型的实现。
    • transformer.py:Transformer模型的实现。
    • transformer_lrq.py:LRP和Transformer模型的实现。
  • scripts/
    • build_vocab.py:通过输入的测试数据创建词表。
    • checkpoint_averaging.py:输入模型checkpoints,输出平均结果。
    • convert_old_model.py:看起来好像是用于把旧实现生成的模型转换成新模型的。
    • convert_vocab.py:不知道是干什么的。
    • input_converter.py:把输入转换成tf.Record格式。不知道有什么用。
    • shuffle_corpus.py:随机打乱训练数据。
    • visualize.py:对Transformer或RNNsearch输出的关联矩阵进行可视化。
  • utils/
    • __init__.py:这是一个模块。
    • bleu.py:BLEU值的计算。
    • common.py:看起来好像是一些用于推导形状的函数。
    • hooks.py:用于保存模型checkpoint。
    • inference.py:实现了Beam Search和不知道是什么的Inference。
    • lrp_utils.py:看名字可能和LRP有关,实际上好像有很多模型的实现,并不知道是干什么的。
    • optimize.py:不知道是干什么的。
    • parallel.py:看起来好像是用于多GPU训练的。
    • sampling.py:?
    • weight_ratio.py:?
  • __init__.py:这是一个模块。

训练过程

一般来说训练过程可以分成以下几个阶段:

  • 准备数据
    • 训练集、验证集、测试集语料
    • 用训练集生成BPE操作和词典(大概?)
    • 用上述BPE操作和词典对训练集、验证集和测试集的源语言部分分别进行处理
    • 将训练集随机排序(shuffle_corpus.py
    • 通过训练集生成词表(build_vocab.py
  • 训练:输入训练集、验证集和词表,输出模型checkpoints、在验证集上得分最高的模型,以及模型在训练过程中在验证集上的评测结果
  • 测试:
    • 输入测试集、词表和模型checkpoints,输出翻译结果(translator.py),经过一定处理后可以得到BLEU分值
    • 可以进行model averaging(checkpoint_averaging.py
    • 可以进行model ensemble(translator.py
  • 可视化:输入测试集、词表、模型checkpoints,输出模型在每个翻译句对上的关联矩阵(get_relevance.pyvisualize.py

明天我打算用比较少的数据在自己的电脑上试验一下。

论文地址:https://arxiv.org/abs/1406.1078

这篇文章提出了RNN Encoder-Decoder架构,使得RNN能够处理序列数据的输入输出:先把序列数据encode成一个定长vector,再把它decode成另一个序列。有趣的一点是,这篇文章的题目里带了“SMT”这个词,说明它并不是一种纯NMT的方法——事实上论文里用它替代了现存的方法里给短语打分的部分。当然这种方法也是可以直接用于整句翻译的(On the Properties of Neural Machine Translation: Encoder-Decoder Approaches),但由于RNN的特性,使得在长句上表现不太好,最后又改进出了Attention方法目前我还不知道这篇文章和Seq2Seq具体是什么关系。

2018.10.11 UPDATE:Seq2Seq和这篇文章提出的架构很类似,但是提高了长句翻译的表现(通过把句子倒过来的trick),一般说Seq2Seq架构的时候应该指的是那篇文章(至少我认为是这样)。本文的另一个重要贡献是LSTM的简化版,GRU单元

简介

本文中提出了一种新的模型,称为RNN Encoder-Decoder,包括两个RNN。一个RNN(encoder)把符号序列编码成一个定长向量表示(fixed-length vector representation);另一个RNN(decoder)把该表示解码成另一个符号序列。这两个RNN共同被训练,以最大化输出目标序列的概率。我们同时提出了一种新的隐藏层单元(hidden unit)。将该模型计算出的短语对条件概率作为现有SMT模型的额外特征之后,SMT的翻译结果提升了;且可以发现,该模型学到的短语中间表示在语义上和句法上都是有意义的。

RNN

RNN是一个神经网络,它输入变长序列$\mathbf{x} = (x_1, ..., x_T)$,内部有一个隐状态$\mathbf{h}$,输出(可选)为$\mathbf{y}$。在每个时刻$t$,RNN的隐状态$\mathbf{h}_{\langle t \rangle}$会被更新:

$$\mathbf{h}_{\langle t \rangle} = f(\mathbf{h}_{\langle t - 1 \rangle}, x_t)$$

其中$f$是一个非线性激活函数,可能很简单,也可能很复杂(如LSTM)。

RNN可以通过被训练为预测序列中的下一个符号来学习序列的概率分布。在这种情况下,$t$时刻输出的就是概率分布$p(x_t | x_{t-1}, ..., x_1)$。比如说,一个multinomial distribution(1-K编码)就可以用一个softmax激活函数输出(这里并没有看懂……):

$$p(x_{t, j} = 1 | x_{t-1}, ..., x_1) = \frac{\exp{(\mathbf{w}_j\mathbf{h}_{\langle t \rangle})}}{\sum_{j'=1}^{K} \exp{(\mathbf{w}_{j'}\mathbf{h}_{\langle t \rangle})}}$$

其中$j = 1, ..., K$,$\mathbf{w}_j$是权重矩阵$\mathbf{W}$的行。

现在就可以计算出序列$\mathbf{x}$出现的概率了:

$$p(\mathbf{x}) = \prod_{t=1}^T p(x_t | x_{t-1}, ..., x_1)$$

通过这一学到的分布,生成一个新的序列的方法是显然的,逐步选择符号即可。

RNN Encoder-Decoder

之前已经说过了,RNN Encoder-Decoder是把一个变长序列编码为一个定长向量表示,再把这个表示解码为另一个变长序列的过程。从概率论的角度看(但是我不知道为什么要从概率论的角度看),这是学习两个变长序列之间的条件概率的方法:

$$p(y_1, ..., y_{T'} | x_1, ..., x_T)$$

Encoder

Encoder是一个RNN,它顺序读入输入序列$\mathbf{x}$,并逐步更新隐状态(和普通的RNN是一样的):

$$\mathbf{h}_{\langle t \rangle} = f(\mathbf{h}_{\langle t - 1 \rangle}, x_t)$$

读到序列结尾(EOS)之后,RNN的隐状态就是整个输入序列对应的表示$\mathbf{c}$。

Decoder

Decoder也是一个RNN,它通过隐状态$\mathbf{h}_{\langle t \rangle}$预测下一个符号$y_t$。不过,$y_t$和$\mathbf{h}_{\langle t \rangle}$都依赖于$y_{t-1}$和$\mathbf{c}$,所以$t$时刻的隐状态为:

$$\mathbf{h}_{\langle t \rangle} = f(\mathbf{h}_{\langle t - 1 \rangle}, y_{t-1}, \mathbf{c})$$

相似地,下一个符号的条件分布就是(虽然不是很懂这是怎么相似出来的):

$$P(y_t | y_{t-1}, y_{t-2}, ..., y_1, \mathbf{c}) = g(\mathbf{h}_{\langle t \rangle}, y_{t-1}, \mathbf{c})$$

Encoder+Decoder

RNN Encoder-Decoder图示

Encoder和Decoder共同进行训练,以最大化conditional log-likelihood:

$$\max_{\mathbf{\theta}} \frac{1}{N} \sum_{n=1}^N \log{p_{\mathbf{\theta}}(\mathbf{y}_n | \mathbf{x}_n)}$$

其中$\mathbf{\theta}$是模型参数,每个$(\mathbf{x}_n, \mathbf{y}_n)$都是训练集中的一个输入输出对。由于decoder的输出是可微分的, 因此可以通过基于梯度的算法来估计模型参数。

训练完RNN Encoder-Decoder之后,模型可以通过两种方式使用。一种是根据输入序列来生成输出序列。另一种是对给定的输入输出序列进行打分,分数就是概率$p_{\mathbf{\theta}}(\mathbf{y} | \mathbf{x})$。

新的隐藏单元

隐藏单元图示

这一单元的灵感来自LSTM,但是计算和实现都简单得多。图中$z$是update gate,用于控制当前隐状态是否需要被新的隐状态$\tilde{h}$更新;$r$是reset gate,用于确定是否要丢弃上一个隐状态。

这个计算方法是否说明,是很多个隐藏单元一起更新和训练……但是为什么输入是个向量呢?大概是因为1-K表示法和Embedding?

2018.10.11 UPDATE:用一般的术语来说,下列内容实际上说明的是“一个GRU cell中的一个unit的计算过程”,因此$r_j$、$z_j$和$h_j^{\langle t \rangle}$都是标量。在本文中,layer=cell。

$r_j$通过下式计算:

$$r_j = \sigma([\mathbf{W}_r\mathbf{x}]_j + [\mathbf{U}_r \mathbf{h}_{\langle t-1 \rangle}]_j)$$

其中$\sigma$是Logistic Sigmoid函数,$[.]_j$是向量的第$j$个元素,$\mathbf{x}$是输入,$\mathbf{h}_{\langle t-1 \rangle}$是上一个隐状态,$\mathbf{W}_r$和$\mathbf{U}_r$是学习到的权重矩阵。

$z_j$类似地通过下式计算:

$$z_j = \sigma([\mathbf{W}_z\mathbf{x}]_j + [\mathbf{U}_z \mathbf{h}_{\langle t-1 \rangle}]_j)$$

单元$h_j$的实际激活状态通过下式计算:

$$h_j^{\langle t \rangle} = z_j h_j^{\langle t-1 \rangle} + (1 - z_j) \tilde{h}_j^{\langle t \rangle}$$

其中

$$\tilde{h}_j^{\langle t \rangle} = \phi([\mathbf{W}\mathbf{x}]_j + [\mathbf{U}(\mathbf{r} \odot \mathbf{h}_{\langle t-1 \rangle})]_j)$$

(虽然我看不懂这个式子是怎么使用$r_j$的,以及它对激活状态有什么影响……)reset gate通过与$\mathbf{h}_{\langle t-1 \rangle})$点乘对$\tilde{h}_j^{\langle t \rangle}$产生影响。


另一种对GRU的描述方式

SMT模型和RNN Encoder-Decoder的结合

传统的SMT系统的目标是对于源句$\mathbf{e}$,找到一个使下式最大化的翻译$\mathbf{f}$:

$$p(\mathbf{f} | \mathbf{e}) \propto p(\mathbf{e} | \mathbf{f}) p(\mathbf{f})$$

其中$p(\mathbf{e} | \mathbf{f})$称为翻译模型(translation model),$p(\mathbf{f})$称为语言模型(language model)。

但在实际中,大部分SMT系统都把$\log{p(\mathbf{f} | \mathbf{e})}$做为一个log-linear模型,包括一些额外的feature和相应的权重:

$$\log{p(\mathbf{f} | \mathbf{e})} = \sum_{n=1}^N w_n f_n(\mathbf{f}, \mathbf{e}) + \log{Z(\mathbf{e})}$$

其中$f_n$是feature,$w_n$是权重,$Z(\mathbf{e})$是与权重无关的normalization constant。

在基于短语的SMT模型中,翻译模型$p(\mathbf{e} | \mathbf{f})$被分解为源句和目标句中短语匹配的概率。这一概率再一次被作为log-linear模型中的额外feature进行优化。


作者在一个短语对表中训练RNN Encoder-Decoder,并将得到的分数作为log-linear模型中的额外feature。目前的做法是把得到的短语对分数直接加入现有的短语对表中;事实上也可以直接用RNN Encoder-Decoder代替这个表,但这就意味着对于每个源短语,RNN Encoder-Decoder都需要生成一系列好的目标短语,因此需要进行很多采样,这太昂贵了。

实验

在WMT'14的En-Fr任务上进行了评测。对于每种语言都只保留了最常见的15000个词,将不常用的词标记为[UNK]。

实验中,RNN Encoder-Decoder的encoder和decoder各有1000个隐藏单元。每个输入符号$x_{\langle t \rangle}$和隐藏单元之间的输入矩阵用两个低秩(100)矩阵来模拟,相当于学习了每个词的100维embedding。隐藏单元中的$\tilde{h}$使用的是双曲余弦函数(hyperbolic tangent function)。decoder中隐状态到输出的计算使用的是一个深度神经网络,含有一个包含了500个maxout单元的中间层。

RNN Encoder-Decoder的权重初值都是通过对一个各向同性的均值为零的高斯分布采样得到的,其标准差为0.01。(但是另一种权重矩阵的初值不一样,而且我没看懂……)

通过Adadelta和随机梯度下降法进行训练,其中超参数为$\epsilon = 10^{-6}$,$\rho = 0.95$。每次更新时,从短语表中随机选出64个短语对。模型训练了大约3天。

实验结果

因为CSLM和RNN Encoder-Decoder共同使用能进一步提高表现,说明这两种方法对结果的贡献并不相同。

除此之外,它学习到的word embedding矩阵也是有意义的。

Word Embedding和词义

(不过考虑到这就是Word Embedding的根本用途,这件事听起来就没有那么令人兴奋了……)

附录:RNN Encoder-Decoder的详细描述

令$X = (\mathbf{x}_1, \mathbf{x}_2, ..., \mathbf{x}_N)$表示源短语,$Y = (\mathbf{y}_1, \mathbf{y}_2, ..., \mathbf{y}_M)$。每个短语都是一系列$K$维的one-hot向量。

Encoder

源短语的每个词都被embed成了500维:$e(\mathbf{x}_i) \in \mathbb{R}^{500}$。

encoder的隐状态由1000个隐藏单元组成,其中每一个单元在$t$时刻的状态由下式计算:

$$h_j^{\langle t \rangle} = z_j h_j^{\langle t-1 \rangle} + (1 - z_j) \tilde{h}_j^{\langle t \rangle}$$

其中

$$\tilde{h}_j^{\langle t \rangle} = \tanh([\mathbf{W}e(\mathbf{x}_t)]_j + [\mathbf{U}(\mathbf{r} \odot \mathbf{h}_{\langle t-1 \rangle})]_j)$$

$$z_j = \sigma([\mathbf{W}_z e(\mathbf{x}_t)]_j + [\mathbf{U}_z \mathbf{h}_{\langle t-1 \rangle}]_j)$$

$$r_j = \sigma([\mathbf{W}_r e(\mathbf{x}_t)]_j + [\mathbf{U}_r \mathbf{h}_{\langle t-1 \rangle}]_j)$$

其中$\sigma$是logistic sigmoid函数,$\odot$是元素对应乘积。上式中忽略了偏移项。初始隐状态$h_j^{\langle 0 \rangle} = 0$。

在隐状态计算完第$N$步之后,就可以得到源短语的表示$\mathbf{c}$:

$$\mathbf{c} = \tanh{\mathbf{V}\mathbf{h}^{\langle N \rangle}}$$

(但是$\mathbf{V}$矩阵是哪里来的?也是需要学习的吗?)

Decoder

decoder通过下式对隐状态进行初始化:

$$\mathbf{h'}^{\langle 0 \rangle} = \tanh(\mathbf{V'c})$$

(大概$\mathbf{V'}$矩阵也是一个参数吧。当然和Encoder的参数不一样)

decoder的隐藏单元在时刻$t$的隐状态通过下式计算:

$${h'}_j^{\langle t \rangle} = {z'}_j {h'}_j^{\langle t-1 \rangle} + (1 - {z'}_j) \tilde{h'}_j^{\langle t \rangle}$$

其中

$$\tilde{h'}_j^{\langle t \rangle} = \tanh([\mathbf{W'}e(\mathbf{y}_{t-1})]_j + r'_j [\mathbf{U'}\mathbf{h'}_{\langle t-1 \rangle} + \mathbf{Cc}]_j)$$

(我在上式的最后一项上加了个$j$。我觉得可能打错了,虽然更有可能是我看错了,不过也没有找到什么验证的方法。)

$${z'}_j = \sigma([\mathbf{W'}_z e(\mathbf{y}_{t-1})]_j + [\mathbf{U'}_z \mathbf{h'}_{\langle t-1 \rangle}]_j + [\mathbf{C}_z\mathbf{c}]_j)$$

$${r'}_j = \sigma([\mathbf{W'}_r e(\mathbf{y}_{t-1})]_j + [\mathbf{U'}_r \mathbf{h'}_{\langle t-1 \rangle}]_j + [\mathbf{C}_r\mathbf{c}]_j)$$

其中$e(\mathbf{y}_0)$是一个全零向量。类似于encoder中的情况,$e(\mathbf{y})$也是目标词的embedding。

decoder需要学习如何生成一个目标短语。在$t$时刻,decoder需要计算生成的词是第$j$个的概率:

$$p(y_{t,j} = 1 | \mathbf{y}_{t-1}, ..., \mathbf{y}_1, X) = \frac{\exp{(\mathbf{g}_j \mathbf{s}_{\langle t \rangle}})}{\sum_{j'=1}^K \exp{(\mathbf{g}_{j'} \mathbf{s}_{\langle t \rangle})}}$$

其中$\mathbf{s}_{\langle t \rangle}$的第$i$个元素是

$$\mathbf{s}_i^{\langle t \rangle} = \max{{{s'}_{2i-1}^{\langle t \rangle}, {s'}_{2i}^{\langle t \rangle}}}$$

$$\mathbf{s'}^{\langle t \rangle} = \mathbf{O}_h \mathbf{h'}^{\langle t \rangle} + \mathbf{O}_y \mathbf{y}_{t-1} + \mathbf{O}_c \mathbf{c}$$

简单来说,$\mathbf{s}_i^{\langle t \rangle}$就是所谓的maxout单元。

(虽然我目前还不知道maxout是什么,以及这个$\mathbf{g}$是怎么来的,以及这一堆到底是怎么算的……)

为了计算效率,我们使用两个矩阵的乘积作为输出权重矩阵$\mathbf{G}$:

$$\mathbf{G} = \mathbf{G}_l \mathbf{G}_r$$

其中$\mathbf{G}_l \in \mathrm{R}^{K \times 500}$,$\mathbf{G}_r \in \mathrm{R}^{500 \times 1000}$。

论文地址:https://www.aclweb.org/anthology/P02-1040.pdf

这篇文章大概是MT领域非常著名的一篇文章了,因为它提出了一种根据参考翻译为机器翻译质量打分的方法(BLEU值),直到现在还在被广泛使用。

基本思路

BLEU评价翻译水平的基本假设是这样的:机器翻译越接近人类翻译,机器翻译的质量就越高。因此,在这一前提下,需要量化机器翻译与人类翻译的相似程度。经过观察可以发现,一个较好的机器翻译和人工翻译中相同的词和短语比较多;因此可以通过比较机器翻译和人工翻译中相同n-gram的数量来评价一个机器翻译。因此令$p_n$表示改进的n-gram精度(modified n-gram precision):

$$p_n = \frac{\sum_{C \in {Candidates}} \sum_{n-gram \in C} Count_{clip}(n-gram)}{\sum_{C' \in {Candidates}} \sum_{n-gram' \in C'} Count(n-gram')}$$

其中$Count_{clip}(n-gram)$的意思是,对于某一个在机器翻译结果中出现的n-gram,它被统计的数量不超过该n-gram在某一个参考翻译中出现的总数量。这样可以防止出现机器翻译大量重复参考翻译中出现的某个词,结果却会得到较高分数的情况。

人类翻译和机器翻译的得分

此时可以看出,这一评分方法可以区分人类和机器翻译了,且n越大,得分的差异越大。

不同水平人类翻译和机器翻译的得分

此时可以看出,这一评分方法也可以在较细粒度上区分人类和机器翻译。

改进:组合多种n-gram的得分

可以看出,n-gram分数大致随n的增加指数衰减,所以对$p_n$的对数做加权平均是比较好的。实验得出,取$n \leq 4$时得到的评测结果最为接近。

改进:短句惩罚

很显然上面的做法已经惩罚了过长的句子和被使用太多次的词,但是并没有考虑到句子太短的情况。只考虑精度可能会使得短句得到非常高的分数。但是考虑召回率又可能会使得事情变得过于复杂。所以直接考虑机器翻译和参考翻译的长度。对于每个机器翻译得到的句子,在(可能有多个的)参考翻译中找到与它长度最为接近的句子,称其长度为最佳匹配长度(best match length)。然后计算出整体语料的机器翻译最佳匹配长度之和,称为$r$;令$c$是机器翻译结果的总长度,定义短句惩罚(brevity penalty)为

$$
\text{BP} =
\begin{cases}
1 & \text{if} \: c > r\\
e^{(1 - r/c)} & \text{if} \: c \leq r
\end{cases}
$$

将这个因子乘到BLEU分数上:

$$\text{BLEU} = \text{BP} \cdot \exp{(\sum_{n=1}^{N} w_n \log{p_n})}$$

$$\log{\text{BLEU}} = \min{(1 - \frac{r}{c}, 0)} + \sum_{n=1}^{N} w_n \log{p_n}$$

测试

在测试中,取$N = 4$,$w_n = 1/N$(也就是直接平均)。

作者首先回答了这样几个问题:

  • (不同机器/人类翻译)BLEU值的差异是可信的吗?
  • (不同机器/人类翻译)BLEU值的差异是稳定的吗?
  • BLEU值的方差是多少?

500个句子

作者找了500个句子,每个各有4个参考翻译,首先让机器/人类分别翻译500个句子,分别计算其BLEU值;然后把这500个句子分成20组,分组计算BLEU值,并计算出平均值和标准差,并对不同系统翻译的结果进行结对T检验。即使只随机留下每个句子的一个参考翻译,BLEU值的排序也没有改变。这说明BLEU值的差异是可信和稳定的,且方差不是很大。

之后作者比较了BLEU评测和人类评测(之前对人类评测也做了一个结对T检验,虽然我并不知道有什么用)的结果。

BLEU值和单语言评测者打分的比较

BLEU值和多语言评测者打分的比较

BLEU值和两种评测者的比较

可以看出,BLEU值和单语言评测者的打分比较相近,和多语言评测者的打分差别比较大。这可能是因为BLEU值只考虑了翻译结果的流利度等因素,不像多语言评测者那样,会考虑更多的语义方面的问题。

总结

这个评价方法主要考虑的是翻译结果和参考翻译之间的相似程度,用比较简单的方法得到了与人类评价相似的结果。不过我的问题是:

  1. 单纯用n-gram计数的比较是否过于简单,没有考虑参考翻译和机器翻译之间语义比较的问题?
  2. BLEU和单语言评测者比较接近大概是有原因的:这一评测方法完全依赖于参考翻译,完全没有管源句的结构之类的问题。不过我觉得只要能保证参考翻译是高质量的,这并不能说是一件坏事,这应该取决于MT的主要应用场景。