如何使用TensorFlow构建自己的谷歌神经机器翻译系统统

谷歌机器学习系统TensorFlow
转自 华尔街见闻
2007年11月,谷歌发布了开源手机操作系统Android,为八年后这一系统主导全球智能手机市场奠定了基石。如今谷歌希望再次得到开源赐予的力量,让人工智能崛起。
谷歌本周宣布,发布新的机器学习平台TensorFlow并将其开源,所有电脑用户都将能够利用这一世界最强大的机器学习平台进行研究。谷歌在其官方中写道:
几年前,你还没法利用谷歌应用进行语音输入,也不能通过谷歌翻译直接阅读俄语,更没法在谷歌图片中直接定位你的爱犬。我们的这些应用当时还不够智能。但是在短暂的时间之后,它们变得更加聪明,如今,凭借机器学习技术,你可以很轻松的完成上面的事情。
但是,尽管我们在机器学习领域取得了这些成果,我们认为还有空间可以做的更好。
所以,我们打造了一个全新的机器学习系统,我们称之为TensorFlow。TensorFlow比我们过去的系统更快、更智能也更加具有弹性,能够更简单地在新产品和新研究中加以采用。
我们亲身体验到TensorFlow的能力,认为它在谷歌之外可能会产生更大的影响。所以,我们今天决定,将TensorFlow开源。
我们希望这将促进机器学习社区,不管是学术研究人员、工程师还是业余爱好者,都能够通过直接在代码而非纸面上进行研究,从而更加快速的交流观点,最终让科技更好的服务所有人。
谷歌原有的深度学习系统DistBelief开发于2011年,它让谷歌能够针对数据中心构建大型神经网络,典型的应用包括提升谷歌应用中的语音识别能力,以及为谷歌搜索加入图片搜索功能。
不过DistBelief存在一些限制,较难配置,且和谷歌内部设施紧密结合,无法很好地分享研究代码,因而谷歌推出新一代的TensorFlow系统。
谷歌表示,已有超过50款谷歌产品采用了TensorFlow,将深度学习技术带给用户,包括谷歌图片应用中的脸部识别技术。如今谷歌将自身产品与服务的特色,以开源的形式贡献给了世界。
TensorFlow:人工智能界的Android
谷歌在博客中只是提到TensorFlow是机器学习系统,并未做过多解释。那么TensorFlow到底是什么?
简单来说,TensorFlow是一个文件库,研究人员和计算机科学家能够借助这个文件库打造分析图像和语音等数据的系统,计算机在此类系统的帮助下,将能够自行作出决定,从而变得更加智能。
这也是机器学习的基本原理,即计算机对输入的数据加以理解之后,利用这些数据作出合乎逻辑的决定,从而实现类似人脑的功能。
而在机器学习的基础之上,TensorFlow则更加复杂,能够非常精确、快速地消化和输出数据,可以用作打造人工智能工具的核心。
TensorFlow系统使用数据流图处理信息,在这个系统中,具有多个维度的数据在不同的数学计算体系中流转,这些复杂的数据就被称作“张量”(tensor),而这些数学体系中流转的则为“节点”(node)。数据从在不同节点之间流转,就能告诉整个系统不同数据之间的关系。“张量”(tensor)在节点图中流转(flow),也是TensorFlow命名的由来。
将TensorFlow开源,意味着不论是研究人员还是大学生,都有机会使用这一专业软件。不论是创业公司还是大到能和谷歌匹敌的企业,都能够像使用Android系统一样,根据自身需要使用TensorFlow,即便是在TensorFlow的基础上开发出与谷歌直接竞争的新工具。而谷歌得到的好处则是,在整个人工智能领域树立权威。
谷歌希望看到的理想结果
早在三个月前,斯坦福大学计算机教授Christopher
Manning和他的学生获得优先使用TensorFlow的机会。在使用仅仅数周之后,Manning就决定在自己的课程上使用这个系统。
除了开源属性上和Android一样,Manning认为TensorFlow还有点像Gmail。他称,尽管竞争者众多,但Gmail更加整洁好用。援引他的话表示:
以前不是没有高水平的深度学习资料库,但总体上,看那些资料库更像是三名学者加上一个大学毕业生的打造作品。
在其他深度学习资料库中,最出名的是Torch和Theano,它们分别由小型团队进行更新维护,与谷歌在机器学习领域投入的资源不可同日而语。
Manning表示,TensorFlow是谷歌对开源社区的巨大贡献,而谷歌自身也将间接受益于这个举动。他表示:
已经有一些公司在雇佣大量优秀人才参与人工智能开发,特别是深度学习。谷歌不是慈善机构,我相信他们在将这贡献出来之前就已经想到,大学将会出现很多这方面的博士研究生。
不过在TensorFlow的缔造者之一、谷歌工程师Jeff
Dean看来,机器学习社区对TensorFlow的采用率到底会有多高,还很难说。他表示:
尽管在谷歌看来,它用处很大,但真正的考验在于机器学习社区是否也这样看。打造这个工具的初衷是,机器学习社区的想法不仅仅停留在理论上,而是能够更加快速的实施。
我们希望能够推动机器学习领域研发的加速。
对于机器学习社区来说,这是谷歌送来的大礼。最理想的情况是,机器学习社区也能以同样的方式共享他们的研究成果。
对于开发人员来说,TensorFlow是一个相当完整的工具包,集成了大量工具以及Apache
2.0协议,能够很方便的商用。开发者既可以在电脑环境中进行编译,也可以将它部署到移动设备上。谷歌还提供了使用教程及文档,帮助开发者快速理解并使用这一平台。
Manning称,能够在移动设备上运行深度学习算法,将是TensorFlow和其他开源系统最大的区别。
对于现在就想尝鲜TensorFlow的开发者来说,谷歌也提供了一个可用版本。此外,它还内建了大量API接口,软件开发者能够很容易控制他们自己的TensorFlow模块。
谷歌如何打造这一系统?
为了打造TensorFlow,谷歌已经花费了三年时间。对于TensorFlow的称呼,谷歌希望外界称其为“机器智能”而非“人工智能”,它认为后者包含太多言外之意,谷歌想打造的是真正的“智能”,只不过载体是机器而已。
在谷歌内部,TensorFlow的核心模块已经使用了多年。谷歌工程师如果对人工神经网络感兴趣,都可以自由地对这个系统做出修改,在这种开放的组织结构下,约有100个团队对打造强大的机器学习技术做了贡献。
谷歌首席执行官Sundar Pichai在10月的业绩沟通会上表示:
我们希望在自身所有产品中使用机器学习技术,不管是搜索、广告、YouTube还是Play商店。
尽管现在还处在早期阶段,但是我们将会系统性地在所有这些产品中应用机器学习。
如今计算机程序解决问题的方式,大多是通过机械地与文件库中的字典进行比对,然后识别文档的意思。但是如果要像人类一样进行理解,计算机就需要将文档细分为不同的区块,对每一区块进行专门的理解。
人工智能领域先驱、谷歌工程师Geoff
Hinton称,“对于一份文档,谷歌希望弄懂其中的逻辑关系,这份文档想说什么,一个想法是如何与上一个想法衔接的。”“如果我们能开始这样做,你就能获得更好的搜索结果,因为这样一来计算机实际上是自己在读取文档并加以理解。”
至于为何谷歌现在还没有开始这样做,Hinton称,人工神经网络能力即便达到极限,也与人脑差距很远。目前最好的算法能够操纵数亿个变量,而人脑能够处理的则高达100万亿。
尽管如此,Hinton称他对人工智能研究的前景依然非常乐观,其中很大部分原因是思维载体(thought
vectors)研究日益盛行。通过将文档转化为思维载体,机器就能够理解并记住文档信息,从而通过逆向工程,用人脑理解事物的算法来学习。
此外,过去五年中物体和语音识别技术的进步,也是Hinton感到乐观的重要原因。以前这些极为复杂的技术如今都已变为现实,在标准测试中的识别错误率也大幅下滑。他表示:
它们正逐步向人类的水平靠近,虽然不是每个方面都是这样,但在物体识别等方面已经达到这一成就。几年前,计算领域人士会告诉你,很多年内都不可能达到这种水平。
但是不管计算机对人脑模仿的多好,如果普通人不知道如何加以利用,就什么都不是。这也正是谷歌希望解决的问题,让人工智能尽可能看起来简单。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。谷歌开放GNMT教程:如何使用TensorFlow构建自己的神经机器翻译系统选自谷歌
机器之心编译
参与:机器之心编辑部
近日,谷歌官方在 Github 开放了一份神经机器翻译教程,该教程从基本概念实现开始,首先搭建了一个简单的NMT模型,随后更进一步引进注意力机制和多层 LSTM 加强系统的性能,最后谷歌根据 GNMT 提供了更进一步改进的技巧和细节,这些技巧能令该NMT系统达到极其高的精度。机器之心对该教程进行简要的描述,跟详细和精确的内容请查看项目原网站。
  GitHub 链接:/tensorflow/nmt
机器翻译,即跨语言间的自动翻译,是机器学习社区最活跃的研究领域。在机器翻译的众多方法中,序列到序列(sequence-to-sequence,seq2seq)模型 [1, 2] 近期获得巨大成功。由于其可以使用深度神经网络获取句义,该模型成为谷歌翻译等多数商业翻译系统事实上的标准模型。但是,尽管有关 OpenNMT 或 tf-seq2seq 等 seq2seq 模型的资料已经非常丰富,但能够指导人们快速构建高质量翻译系统的知识和技能仍然略显不足。
今天,我们很高兴能够发布最新的 TensorFlow 神经机器翻译教程,帮助读者全面了解 seq2seq 模型,并介绍如何从头开始构建有竞争力的翻译模型。该教程尽可能简单地呈现该过程,教程首先介绍神经机器翻译的背景知识,并讲述构建 vanilla 系统的具体代码。然后介绍注意力机制 [3, 4] 这一帮助 NMT 系统处理长句的重要工具。最后,本教程将讲解如何复制谷歌 NMT(GNMT)系统 [5] 的关键特征,以实现在多个 GPU 上训练模型。
本教程包括具体的基准测试结果,用户可自行复制。我们的模型提供强大的开源基准,其性能不亚于 GNMT 的结果 [5]。我们在 WMT 2014 的英语转德语翻译任务中取得了 BLEU 得分 24.4 的成绩。
本教程还包括其他的基准测试结果(英语转越南语、德语转英语)。
另外,本教程将开放全动态的 seq2seq API(随 TensorFlow 1.2 发布),该 API 使 seq2seq 模型的构建过程干净、简单、易读:
使用 tf.contrib.data 中最新输入的管道对动态调整的输入序列进行预处理。
使用批量填充和序列长度 bucketing,提高训练速度和推理速度。
使用通用结构和训练时间表训练 seq2seq 模型,包括多种注意力机制和固定抽样。
使用 in-graph 集束搜索在 seq2seq 模型中进行推理。
优化 seq2seq 模型,以实现在多 GPU 设置中的模型训练。
下文我们将简要地介绍该 Github 教程项目。
序列到序列(seq2seq)模型(Sutskever et al., 2014, Cho et al., 2014)在机器翻译、语音识别和文本摘要等任务上取得了巨大的成功。本教程致力于帮助读者全面掌握 seq2seq 模型,并且展示了如何从头开始构建一个强大的 seq2seq 模型。我们该教程会注重神经机器翻译(NMT)任务,神经机器翻译是 seq2seq 模型很好的试验台,并且已经获得了广泛的成功。我们使用的代码是极其轻量、高质量、可投入生产并且结合了最新研究思路的实现。我们通过以下方式实现这一目标:
使用最新的解码器/attention wrapper API、TensorFlow 1.2 数据迭代器。
结合了我们在构建循环型和 seq2seq 型模型的专业知识。
提供了可构建最好 NMT 模型的技巧,同时还复制了谷歌的 NMT(GNMT)系统。
我们相信提供所有人都很容易复制的基准是非常重要的。因此,我们基于以下公开的数据集提供了全部的试验结果和预训练模型:
小规模数据集:TED 演讲的英语-越南语平行语料库(133K 个句子对),该数据集由 IWSLT Evaluation Campaign 提供。
大规模数据集:德语-英语平行语料库(4.5M 个句子对),该数据集由 WMT Evaluation Campaign 提供。
我们首先需要了解用于 NMT 任务的 seq2seq 模型的基本知识,并需要理解如何构建和训练一个 vanilla NMT 模型。第二部分将更进一步详细地解释如何构建带注意力机制的强大神经机器翻译模型。然后我们会讨论构建更好神经机器翻译模型(翻译速度和质量)可能的技巧,例如 TensorFlow 最好的实践方法(batching, bucketing)、双向循环神经网络和集束搜索等。
关于神经机器翻译
以词组为基础的传统翻译系统将源语言句子拆分成多个词块,然后进行词对词的翻译。这使得翻译输出结果流畅性大打折扣,远远不如人类译文。我们会通读整个源语言句子、了解句子含义,然后输出翻译结果。神经机器翻译(NMT)竟然可以模仿人类的翻译过程!
  图 1. 编码器-解码器结构——神经机器翻译的通用方法实例。编码器将源语言句子转换成「意义」向量,然后通过解码器输出翻译结果。
具体来说,神经机器翻译系统首先使用编码器读取源语言句子,构建一个「思想」向量,即代表句义的一串数字;然后使用解码器处理该容器,并输出翻译结果,如图 1 所示。这就是我们通常所说的编码器-解码器结构。神经机器翻译用这种方法解决以词组为基础的传统翻译系统遇到的翻译问题:神经机器翻译能够捕捉语言中的长距离依赖结构,如词性一致、句法结构等,然后输出流利度更高的翻译结果,正如谷歌神经机器翻译系统已经做到的那样。
NMT 模型在具体的结构中会发生变化。对于序列数据而言,最好的选择是循环神经网络(RNN),这也被大多数 NMT 模型采用。通常情况下,编码器和解码器都可使用循环神经网络。但是,循环神经网络模型在下列情况下发生变化:(a)方向性(directionality),单向或双向;(b)深度,单层或多层;(c)类型,通常是 vanilla RNN、长短期记忆(Long Short-term Memory,LSTM),或门控循环单元(gated recurrent unit,GRU)。
感兴趣的读者可打开该网址(https://colah.github.io/posts/2015-08-Understanding-LSTMs/),获取 RNN 和 LSTM 的更多信息。
本教程中,我们将以单向的深度多层 RNN(deep multi-layer RNN)为例,它使用 LSTM 作为循环单元。模型实例如图 2 所示。我们在该实例中构建了一个模型,将源语言句子「I am a student」翻译成目标语言「Je suis &tudiant」。该 NMT 模型包括两个循环神经网络:编码器 RNN,在不预测的情况下将输入的源语言单词进行编码;解码器,在预测下一个单词的条件下处理目标句子。
若想参考更多信息,请查看 Luong(2016)(/lmthang/thesis)。
  图 2. 神经机器翻译——一个深度循环结构实例:将源语言句子「I am a student」翻译成目标语言句子「Je suis &tudiant」。此处,「&s&」代表解码过程开始,「&/s&」代表解码过程结束。
安装该教程
为了安装该教程,我们需要先安装 TensorFlow。本教程需要最新的 TensorFlow 教程(目前为 1.2.1 版本)。为了安装 TensorFlow,请按照以下安装指导:https://www.tensorflow.org/install/。
在安装 TensorFlow 之后,我们需要运行以下命令安装本教程的源代码:
  git clone /tensorflow/nmt/
训练-如何构建我们第一个 NMT 系统
我们首先需要了解构建一个 NMT 模型具体代码的核心,我们会在图 2 中更详细地讲解。我们后面会介绍数据准备和全部的代码,这一部分是指 model.py 文件。
在网络的底层,编码器和解码器 RNN 接收到以下输入:首先是原句子,然后是从编码到解码模式的过渡边界符号「&s&」,最后是目标语句。对于训练来说,我们将为系统提供以下张量,它们是以时间为主(time-major)的格式,并包括了单词索引:
encoder_inputs [max_encoder_time, batch_size]:源输入词。
decoder_inputs [max_decoder_time, batch_size]:目标输入词。
decoder_outputs [max_decoder_time, batch_size]:目标输出词,这些是 decoder_inputs 按一个时间步向左移动,并且在右边有句子结束符。
为了更高的效率,我们一次用多个句子(batch_size)进行训练。测试略有不同,我们会在后面讨论。
给定单词的分类属性,模型首先必须查找词来源和目标嵌入以检索相应的词表征。为了令该嵌入层能够运行,我们首先需要为每一种语言选定一个词汇表。通常,选定词汇表大小 V,那么频率最高的 V 个词将视为唯一的。而所有其他的词将转换并打上「unknown」标志,因此所有的词将有相同的嵌入。我们通常在训练期间嵌入权重,并且每种语言都有一套。
  # Embedding
  embedding_encoder = variable_scope.get_variable(
  &embedding_encoder&, [src_vocab_size, embedding_size], ...)# Look up embedding:# encoder_inputs: [max_time, batch_size]# encoder_emp_inp: [max_time, batch_size, embedding_size]
  encoder_emb_inp = embedding_ops.embedding_lookup(
  embedding_encoder, encoder_inputs)
我们同样可以构建 embedding_decoder 和 decoder_emb_inp。注意我们可以选择预训练的词表征如 word2vec 或 Glove vectors 初始化嵌入权重。通常给定大量的训练数据,我们能从头学习这些嵌入权重。
一旦可以检索到,词嵌入就能作为输入馈送到主神经网络中。该网络有两个多层循环神经网络组成,一个是原语言的编码器,另一个是目标语言的解码器。这两个 RNN 原则上可以共享相同的权重,然而在实践中,我们通常使用两组不同的循环神经网络参数(这些模型在拟合大型训练数据集上做得更好)。解码器 RNN 使用零向量作为它的初始状态,并且可以使用如下代码构建:
  # Build RNN cell
  encoder_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units)
  # Run Dynamic RNN# encoder_outpus: [max_time, batch_size, num_units]# encoder_state: [batch_size, num_units]
  encoder_outputs, encoder_state = tf.nn.dynamic_rnn(
  encoder_cell, encoder_emb_inp,
  sequence_length=source_seqence_length, time_major=True)
注意语句有不同的长度以避免浪费计算力,因此我们会通过 source_seqence_length 告诉 dynamic_rnn 精确的句子长度。因为我们的输入是以时间为主(time major)的,我们需要设定 time_major=True。现在我们暂时只需要构建单层 LSTM、encoder_cell。我们后面会详细描述怎样构建多层 LSTM、添加 dropout 并使用注意力机制。
decoder 也需要访问源信息,一种简单的方式是用编码器最后的隐藏态 encoder_state 对其进行初始化。在图 2 中,我们将源词「student」中的隐藏态传递到了解码器。
  # Build RNN cell
  decoder_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units)# Helper
  helper = tf.contrib.seq2seq.TrainingHelper(
  decoder_emb_inp, decoder_lengths, time_major=True)# Decoder
  decoder = tf.contrib.seq2seq.BasicDecoder(
  decoder_cell, helper, encoder_state,
  output_layer=projection_layer)# Dynamic decoding
  outputs, _ = tf.contrib.seq2seq.dynamic_decode(decoder, ...)
  logits = outputs.rnn_output
此处代码的核心是 BasicDecoder、获取 decoder_cell(类似于 encoder_cell) 的 decoder、helper 以及之前作为输入的 encoder_state。
通过分离 decoders 和 helpers,我们能重复使用不同的代码库,例如 TrainingHelper 可由 GreedyEmbeddingHelper 进行替换,来做贪婪解码。
最后,我们从未提到过的 projection_layer 是一个密集矩阵,将顶部的隐藏态转变为维度 V 的逻辑向量。我们在图 2 的上部展示了此过程。
  projection_layer = layers_core.Dense(
  tgt_vocab_size, use_bias=False)
给出以上的 logits,可计算训练损失:
  crossent = tf.nn.sparse_softmax_cross_entropy_with_logits(
  labels=decoder_outputs, logits=logits)
  train_loss = (tf.reduce_sum(crossent * target_weights) /
  batch_size)
以上代码中,target_weights 是一个与 decoder_outputs 大小一样的 0-1 矩阵。该矩阵将目标序列长度以外的其他位置填充为标量值 0。
我们需要指出来的是,训练损失可以由 batch_size 分割,因此我们的超参数 batch_size 是「不变量」。也有些人将训练损失按照 batch_size * num_time_steps 分割,这样可以减少短句所造成的误差。更巧妙的,我们的超参数(应用于前面的方法)不能用于后面的方法。例如,如果两种方法都是用学习率为 1.0 的随机梯度下降,后面的方法将更有效地利用一个较小的学习率,即 1 / num_time_steps。
5.梯度计算和优化
现在是时候定义我们的 NMT 模型的前向传播了。计算反向传播只需要写几行代码:
  # Calculate and clip gradients
  parameters = tf.trainable_variables()
  gradients = tf.gradients(train_loss, params)
  clipped_gradients, _ = tf.clip_by_global_norm(
  gradients, max_gradient_norm)
训练 RNN 的一个重要步骤是梯度截断(gradient clipping)。这里,我们使用全局范数进行截断操作。最大值 max_gradient_norm 通常设置为 5 或 1。最后一步是选择优化器。Adam 优化器是最常见的选择。我们还要选择一个学习率,learning_rate 的值通常在 0.0001 和 0.001 之间,且可设置为随着训练进程逐渐减小。
  # Optimization
  optimizer = tf.train.AdamOptimizer(learning_rate)
  update_step = optimizer.apply_gradients(
  zip(clipped_gradients, params))
在我们的实验中,我们使用标准的随机梯度下降(tf.train.GradientDescentOptimizer),并采用了递减的学习率方案,因此也就有更好的性能。
开始训练 NMT 模型
让我们开始训练第一个 NMT 模型,将越南语翻译为英语。代码的入口是** **nmt.py。
我们将使用小规模的 Ted 演讲并行语料库(133k 的训练样本)进行训练。所有的数据都可从以下链接找到:https://nlp.stanford.edu/projects/nmt/。
我们将使用 tst2012 作为开发数据集,tst 2013 作为测试数据集。运行以下命令行下载数据训练 NMT 模型:
  nmt/s/download_iwslt15.sh /tmp/nmt_data
运行以下命令行开始训练:
  mkdir /tmp/nmt_model
  python -m nmt.nmt
  --src=vi --tgt=en
  --vocab_prefix=/tmp/nmt_data/vocab
  --train_prefix=/tmp/nmt_data/train
  --dev_prefix=/tmp/nmt_data/tst2012
  --test_prefix=/tmp/nmt_data/tst2013
  --out_dir=/tmp/nmt_model
  --num_train_steps=12000
  --steps_per_stats=100
  --num_layers=2
  --num_units=128
  --dropout=0.2
  --metrics=bleu
以上命令行训练一个 2 层的 LSTM seq2seq 模型,带有 128-dim 的隐藏单元和 12 个 epochs 的嵌入。我们使用 0.2(或然率为 0.8)的 dropout 值。如果没误差,在我们训练中随着降低混淆度,我们应该能看到类似于以下的 logs。
  # First evaluation, global step 0
  eval dev: perplexity 17193.66
  eval test: perplexity 17193.27
  # Start epoch 0, step 0, lr 1, Tue Apr 25 23:17:41 2017
  sample train data:
  src_reverse: &/s& &/s& ?i?u ?& , d? nhi&n , l& c&u chuy?n tr&ch ra t? h?c thuy?t c?a Karl Marx .
  ref: That , of course , was the &unk& distilled from the theories of Karl Marx . &/s& &/s& &/s&
  epoch 0 step 100 lr 1 step-time 0.89s wps 5.78K ppl 1568.62 bleu 0.00
  epoch 0 step 200 lr 1 step-time 0.94s wps 5.91K ppl 524.11 bleu 0.00
  epoch 0 step 300 lr 1 step-time 0.96s wps 5.80K ppl 340.05 bleu 0.00
  epoch 0 step 400 lr 1 step-time 1.02s wps 6.06K ppl 277.61 bleu 0.00
  epoch 0 step 500 lr 1 step-time 0.95s wps 5.89K ppl 205.85 bleu 0.00
更多细节,请查看:train.py。
我们可以使用 Tensorboard 在训练过程中查看模型的总结:
  tensorboard --port 22222 --logdir /tmp/nmt_model/
通过以下简单的变化,就能逆向完成英语到越南语的翻译。
  --src=en --tgt=vi
推理——如何生成翻译
当你训练你的 NMT 模型时(并且一旦你已经训练了模型),可以在给定之前不可见的源语句的情况下获得翻译。这一过程被称作推理。训练与推理之间有一个明确的区分(测试):在推理时,我们只访问源语句,即 encoder_inputs。解码的方式有很多种,包括 greedy 解码、采样解码和束搜索解码(beam-search)。下面我们讨论一下 greedy 解码策略。
其想法简单,我们将在图 3 中作说明:
在训练获取 encoder_state 的过程中,我们依然以相同方式编码源语句,并且 encoder_state 用于初始化解码器。
一旦解码器接收到开始符 &s&(在我们的代码中指 tgt_sos_id),就开始解码处理(翻译)。
最大的单词,其 id 与最大的 logit 值相关联,正如被发出的词(这是 greedy 行为)。例如在图 3 中,单词 moi 在第一个解码步中具有最高的翻译概率。接着我们把这一单词作为输入馈送至下一个时间步。
这一过程会持续到这句话的终止符「&/s&」,然后输出(在我们的代码中是 tgt_eos_id)。
  图 3. Greedy 解码——一个实例:已训练的 NMT 模型如何使用 greedy 搜索为源语句 Je suis &tudiant 生成翻译。
推理与训练的区别在于步骤 3。推理不总是馈送作为输入的正确目标词,而是使用被模型预测的单词。下面是实现 greedy 解码的代码。它与训练解码器非常相似。
  # Helper
  helper = tf.contrib.seq2seq.GreedyEmbeddingHelper(
  embedding_decoder,
  tf.fill([batch_size], tgt_sos_id), tgt_eos_id)
  # Decoder
  decoder = tf.contrib.seq2seq.BasicDecoder(
  decoder_cell, helper, encoder_state,
  output_layer=projection_layer)# Dynamic decoding
  outputs, _ = tf.contrib.seq2seq.dynamic_decode(
  decoder, maximum_iterations=maximum_iterations)
  translations = outputs.sample_id
我们在本文中使用了 GreedyEmbeddingHelper 而不是 TrainingHelper。由于无法提前知道目标语句的长度,我们使用 maximum_iterations 限制翻译的长度。一个启发是解码最多两倍的源语句长度。
  maximum_iterations = tf.round(tf.reduce_max(source_sequence_length) * 2)
我们已经训练了一个模型,现在可以创建一个推理文件并翻译一些语句:
  cat & /tmp/my_infer_file.vi# (copy and paste some sentences from /tmp/nmt_data/tst2013.vi)
  python -m nmt.nmt
  --model_dir=/tmp/nmt_model
  --inference_input_file=/tmp/my_infer_file.vi
  --inference_output_file=/tmp/nmt_model/output_infer
  cat /tmp/nmt_model/output_infer # To view the inference as output
注意上述指令也可在模型被训练时运行,只要存在一个训练检查点。详见 inference.py。
在训练了一些最基本的序列到序列模型之后,我们现在更进一步。为了打造当前最优的神经机器翻译系统,我们需要更多的秘诀:注意力机制。该机制由 Bahdanau 等人在 2015 年首次提出(https://arxiv.org/abs/),稍后 Luong 等人和其他人完善了它,其核心思想是当我们翻译时通过「注意」相关的源内容,建立直接的短连接。注意力机制的一个很好副产品是源语句和目标语句之间的一个易于可视化的对齐矩阵(如图 4 所示)。
  图 4. 注意力可视化——源语句与目标语句之间对齐的实例。图片来自 2015 年 Bahdanau 等人的论文。
请记住在 vanilla 序列到序列模型中,当开始编码处理时,我们把最后的源状态从编码器传递到解码器。这对短、中长度的语句效果很好;对于长句子,单一固定大小的隐状态成为了信息瓶颈。注意力机制没有摈弃源 RNN 中计算的所有隐状态,而是提出了允许解码器窥探它们的方法(把它们看作是源信息的动态存储)。如此,注意力机制提升了长句的翻译质量。现在,注意力机制实至名归,已成功应用于其他诸多任务(比如语音识别)。
注意力机制背景
我们现在描述一下注意力机制的实例(Luong et al., 2015),它已经被应用到几个最新型的系统当中了,包括开源工具,比如 OpenNMT(http://opennmt.net/about/)和此教程中的 TF seq2seq API。我们还将会提供注意力机制相关变体的内容。
  图 5. 注意力机制——基于注意力的 NMT 系统(Luong et al., 2015 中有具体描述)。我们重点详解注意力计算过程中的第一步。为了更加清晰,我们没有展示图(2)中的嵌入层和投影层。
如图 5 所示,注意力计算发生在解码步骤中的每一步。它包含下列步骤:
当前目标隐蔽状态和所有源状态(source state)进行比较,以导出权重(weight),见图 4。
基于注意力权重,我们计算了一个背景向量(context vector),作为源状态的平均权值。
将背景向量与当前目标隐蔽态进行结合以生成最终的注意力向量。
此注意力向量将作为下一时序步骤的输入。前三个步骤可以由下列公式总结:
这里,函数 score 用于将目标隐蔽状态 ht 和每一个源状态 hs 进行比较,结果会被标准化成生成式注意力权重(一个源位置的分布)。其实有很多种关于评分函数(scoring function)的选择;比较流行的评分函数包括公式(4)中给出的乘法与加法形式。一旦被计算,注意力向量 at 就会用于推导 softmax logit 和损失。这与 vanilla seq2seq 模型顶层的目标隐蔽态相似。函数 f 也可以利用其它形式。
  注意力机制的多种实现方法可由以下链接获得:/tensorflow/tensorflow/blob/master/tensorflow/contrib/seq2seq/python/ops/attention_wrapper.py。
注意力机制中有什么相关注意事项呢?
上述公式表明注意力机制有很多种变体。这些变体依赖于评分函数(scoring function)和注意力函数(attention function)的形式,也依赖于前一状态 ht-1,而不依赖于开始建议的评分函数 ht(Bahdanau et al., 2015)。实际上我们发现的只有一些选择上的注意事项。一,注意力的基本形式,例如,目标和源之间的直接联系需要被呈现。二,把注意力向量输入给下一时间步骤,以把之前的注意力决策告知给网络(Luong et al., 2015)。最后,评分函数的选择经常可以造成不同的性能表现。
Attention Wrapper API
在我们的 Attention Wrapper API 的实现中,借鉴了 Weston et al., 2015 在 onmemory network 工作中的术语。相比于拥有可读、可写的记忆,此教程中的 attention 机制仅是可读的记忆。特别是对隐藏态(或者隐藏态的变体,例如 $$Woverline{h}_s$$ in Luong's scoring style or $$W_2overline{h}_s$$ ) 的设定,被认为是「记忆」。在每个时间步下,我们使用现有的目标隐藏态作为「query」决定读取哪一部分记忆。通常情况下,query 需要与单个记忆条相对应的 keys 进行对比。在上面对注意机制的演示中,我们偶然使用一套源隐藏态(或者其变体,例如$$W_1h_t$$)作为「key」。你们可以从这种记忆网络术语中获取灵感,找到其他形式的 attention。
由于 attention wrapper,就不再需要扩展我们带有 attention 的 vanilla seq2seq 代码。这部分文件为 attention_model.py。
首先,我们需要定义一种注意机制,例如采用 Luong et al., 2015 的研究。
  # attention_states: [batch_size, max_time, num_units]
  attention_states = tf.transpose(encoder_outputs, [1, 0, 2])
  # Create an attention mechanism
  attention_mechanism = tf.contrib.seq2seq.LuongAttention(
  num_units, attention_states,
  memory_sequence_length=source_sequence_length)
在之前的 Encoder 部分,encoder_outputs 是一套顶层的掩藏态源,形式为 [max_time, batch_size, num_units](因为我们使用 dynamic_rnn with time_major 设定)。在注意机制上,我们需要保证通过的「memory」是批次为主的,所以需要调换 attention_states。我们通过 source_sequence_length 保证注意机制的权重有适当的规范化(只在 non-padding 的位置)。定义完注意机制之后,我们使用 AttentionWrapper 来包裹解码单元。
  decoder_cell = tf.contrib.seq2seq.AttentionWrapper(
  decoder_cell, attention_mechanism,
  attention_layer_size=num_units)
剩下的代码基本和编码器一转样 (/tensorflow/nmt#decoder)!
上手—打造一个基于注意力的 NMT 模型
为了使注意力发挥作用,我们需要用到 luong、scaled_luong、bahdanau 或 normed_bahdanau 其中的一个作为训练期间注意力标志(attention flag)的值。该标志指定了我们将要使用的注意力机制。除此之外,我们需要为注意力模型创建一个新目录,因此无需重新使用之前训练的基本 NMT 模型。
运行以下指令开始训练:
  mkdir /tmp/nmt_attention_model
  python -m nmt.nmt
  --attention=scaled_luong
  --src=vi --tgt=en
  --vocab_prefix=/tmp/nmt_data/vocab
  --train_prefix=/tmp/nmt_data/train
  --dev_prefix=/tmp/nmt_data/tst2012
  --test_prefix=/tmp/nmt_data/tst2013
  --out_dir=/tmp/nmt_attention_model
  --num_train_steps=12000
  --steps_per_stats=100
  --num_layers=2
  --num_units=128
  --dropout=0.2
  --metrics=bleu
训练之后,我们可以使用带有新 model_dir 的相同推理指令进行推理:
  python -m nmt.nmt
  --model_dir=/tmp/nmt_attention_model
  --inference_input_file=/tmp/my_infer_file.vi
  --inference_output_file=/tmp/nmt_attention_model/output_infer
IWSLT 英语-越南语
训练:133k 的样本,dev=tst2012,test=tst2013
  训练速度:在英伟达 K40m 上是 0.37s 的时间步、15.3k 的 wps,在 Titan X 上是 0.17 s 的时间步,32.2k 的 wps.。
WMT 德语-英语
训练:4.5M 的样本量,dev=newstest2013,test=newtest2015
  训练速度:在英伟达 K40m 上是 2.1s 的时间步,3.4k 的 wps,在英伟达 Titan X 上是 0.7s 的时间步,8.7k 的 wps。
为了查看 GNMT 注意的加速度,我们只在 K40m 上做了基准测试:
WMT 英语-德语 全对比
第二行是我们 GNMT 注意模型:模型 1(4 层),模型 2(8 层)。
若想深入了解神经机器翻译和序列-序列模型,我们非常推荐以下资源:
Neural Machine Translation and Sequence-to-sequence Models: A Tutorial:https://arxiv.org/abs/
Neural Machine Translation - Tutorial ACL 2016:/site/acl16nmt/
Thang Luong's Thesis on Neural Machine Translation:/lmthang/thesis
用于构建 seq2seq 模型的工具很多:
Stanford NMT https://nlp.stanford.edu/projects/nmt/ [Matlab]
tf-seq2seq /google/seq2seq [TensorFlow]
Nemantus /rsennrich/nematus [Theano]
OpenNMT http://opennmt.net/ [Torch]
  [1] Sequence to sequence learning with neural networks (https://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf), Ilya Sutskever, Oriol Vinyals, and Quoc V. Le. NIPS, 2014.
  [2] Learning phrase representations using RNN encoder-decoder for statistical machine translation (http://aclweb.org/anthology/D/D14/D14-1179.pdf), Kyunghyun Cho, Bart Van Merrienboer, Caglar Gulcehre, Dzmitry Bahdanau, Fethi Bougares, Holger Schwenk, and Yoshua Bengio. EMNLP 2014.
  [3] Neural machine translation by jointly learning to align and translate (https://arxiv.org/pdf/.pdf), Dzmitry Bahdanau, Kyunghyun Cho, and Yoshua Bengio. ICLR, 2015.
  [4] Effective approaches to attention-based neural machine translation (https://arxiv.org/pdf/.pdf), Minh-Thang Luong, Hieu Pham, and Christopher D Manning. EMNLP, 2015.
  [5] Google‘s Neural Machine Translation System: Bridging the Gap between Human and Machine Translation (http://arxiv.org/abs/),2016.
本文为机器之心编译,转载请联系本公众号获得授权。
  ?------------------------------------------------
加入机器之心(全职记者/实习生):
投稿或寻求报道:
广告&商务合作:声明:本文由入驻搜狐公众平台的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。阅读()}

我要回帖

更多关于 神经机器翻译 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信