Sequencing——简单的序列到序列学习框架

这个月断断续续自己写了一个seq2seq代码,我也不确定这是否可以算是框架,就姑且定义为框架了。为什么要自己写呢,因为我觉得现有代码组织都写得太复杂,明明是很简单的原理,这样不利于实验室同门入门。我一共写了3700行代码,包括额外的numpy版本的sequencing_np (1000行)和tests (800行)。吸收各个大牛的实现(blocksseq2seq)的优点,个人认为我的实现已经非常清晰简单,贯彻整个项目的准则是“keep simple, stay na(t)ive.”

我以英中机器翻译为实例来介绍什么是sequence to sequence learning以及如何使用sequencing来训练自己的模型。可以参考Github的代码。为方便大家上手,我也准备了预处理过的数据,见百度云。这份数据包含14590228条平行句对,来源于UN数据集。有兴趣的同学可以根据这些数据训练自己的英文到中文的机器翻译模型。


数据准备

数据是必不可少的,我们可以自己爬,比如有道啊,句酷啊各种有双语例句的网站。大约500万就可以开始训练了。然后需要准备单词表,也就是需要把各个单词映射到一个整数id,否则接下去没法搞。对于英文,我们可以使用空格分隔的单词或者流行的BPE。为了简单起见,中文端我们就不分词了,直接以字作为单位,如“我、们、是、中、国、人”。这样词表小,效率高,也不怎么影响翻译效果。这些都准备完毕之后,只要产生平行句对来训练就行了。当然得考虑补零、效率等问题,这些我都写好了,详见build_inputs.py。只需调用如下,


编码器

目前只实现了双向RNN编码器,将来会实现CNNself-attention编码器。编码器是很简单的,见下图。

encoder
编码器展示

首先,我们需要通过代表单词的整数index将单词表示为向量,这都是通过一个Lookup Table(Embedding Table)实现的。说白了,就是把一个M×N的矩阵的第index行取出来,M为总的单词个数(可以试试32K),N为向量的大小,512足够了。

接着,就是通过双向RNN编码这些向量,来形成表示单词在句子中的意思。多层的编码器性能当然更好,训练也更久。


注意力机制

注意力机制是机器翻译必不可少的,可以说就是注意力机制的引入导致了机器翻译的变革。更难得的是注意力机制非常简单,具体来说就是给定查询query(通常是decoder RNN的输出),来匹配编码器的输出。写成代码如下,

当然,这个代码是不精确的,得考虑维度和batch。我们可以根据context翻译下一个词。比如翻译“I love summer”时,“我喜欢”已经翻译出来了,query就是当前解码器的状态,与编码器的输出比对,context就是表示“summer”的向量,据此很容易就能翻译出“夏天”。在sequencing里,可以很方便地调用,如下。


解码器

解码器可以算是最复杂的。因为要考虑反馈,还要使用注意力机制。不过,隐藏细节后很简单,如下,

具体实现不展开,可以见源代码。我也简单地画了一个图。feedback就是要把之前翻译的词反馈给解码器(feedback也包含一个Lookup Table,需要把词表示为向量,这里没有画出来),这里的解码器是一个RNN,起到语言模型的作用。

 

decoder
解码部分的简单展示

训练

光有模型不行,得有loss才行。如上图所示,每反馈一个单词,就会输出一个新的单词,直到输出结尾符。因此,第一个反馈的是开始符(BOS),然后可以产生logits(可以理解为概率),将logits与目标输出(“我”)对比得出loss。cross_entroy是最常用的loss。接着反馈“我”,输出logits与“喜”对比,得出下一个loss,以此类推,直至结束。这个过程,我们以dynamic_decode表示,这类似于seq2seq,但被我简化了,去掉了复杂的操作。

就像上面介绍的,我们定义loss的方式如下

有了loss就简单了,选个优化方法进行优化就行了。最常用的是Adam,也可以使用SGD。


推断

Greedy推断和Beam推断都行。不得不提batched beam飞快,60s解码2000句。详见代码,因为不重要,所以这里不展开。


性能

按默认设定(1层1024的编码器,1层1024的解码器), 经测试,每天能训练3千万平行句对。飞快!结果也不错。batched beam更快,60s解码2000句,同样的训练集和参数,效率和效果貌似比seq2seq好一点,有条件的同学可以自行验证。


只依赖numpy的版本,Sequencing_np

这个厉害了,很有意思。我写了一个相互对应的版本,实现了LSTM等基本单元,也实现了整个sequencing的模型,但只依赖numpy。既可以作为测试,也非常有趣。但不能训练是肯定的,我们需要把训练好的模型传给sequencing_np。原理都是一样的,优点是我们可以print!debug方便很多,更装b的是,可以直接在Android进行翻译!我真是机智。

android
在Android上的机器翻译(模型都在Android上)

 

写得比较仓促,不清楚的地方还请留言指出。

翻译心得

已经8个多月没有更新博客,我去干嘛了?实不相瞒,我去翻译了,就是那本《Deep Learning》,800多页不是开玩笑的,虽然不是我一个人翻,但也是够呛的。现在书出版了,我就来讲讲翻译心得。我首先要强调一下,同样也是老师的教诲:“翻译没什么了不起的,写出来的人才了不起。我们不能到处吹说我们翻译了书多厉害。”不用老师说,我们都知道翻译非文学类书籍没啥了不起的,我们甚至不想出现在纸质版的译者名单里。但老师说,“出现你的名字,并不是荣誉,更是代表了责任。”我们一想,冷汗直冒,将来翻译出了偏差,我们可是要负责任的!所以最后的译者顺序也是按翻译量来排的。这导致我现在每天都很惊悚,生怕哪里出了大问题。可是媒体和出版社没有听我们的建议,大肆宣扬“北大张志华审校”、“AI圣经”,我真的很无语。


接受任务

2016年7月,老师问我们有没有兴趣翻译deep learning这本书。一开始我们是拒绝的,一是因为翻译本身吃力不讨好,肯定会有人喷。当然喷也是有道理的,翻译成中文有洋味,读起来总会觉得哪里不对。 二是因为这本书是目前热门领域的权威书籍,以我们的能力很难翻译得足够好。我们都不是专家,数学水平可能足够了,但是深度学习的造诣并没有,深度学习更需要实践啊。但翻译过程也是学习的过程,翻译成中文也能帮助更多的同学更轻松得入门,于是我们诚惶诚恐,舍我其谁得接受了这一重任。在翻译过程中,我们时刻提醒自己,我们是译者,不是作者。因此,采取直译还是意译是我们遇到的第一个问题。学长看了我们直译的样章(逐句对应),觉得这样不行,读起来费劲。他花了非常久的时间,翻译了一页。我们读了一下,虽然通顺一点,但意译太严重,很多词被省略了。我们觉得这样对不住原书,我们决定要最大程度地保留原书语句,这样可以避免我们没有真正理解作者的意思而导致的翻译错误。我们非常刻板,比如原书中的recurrent network,我们绝不会翻译成循环神经网络,反之亦然。在这样的标准下,我们把800多页的英文版翻成了700多页的中文版(后经过出版社排版后,缩减到500多页),当时我们全懵了。当然,这种要求带来的不良后果就是语句会比较生硬一点,读起来累一点,但我们认为这是值得的。


问题与经验

翻译过程也遇到很多问题,比如名词对应问题。对名词的翻译前后得统一,多名译者的翻译也得统一。刚开始我们采用简单的命令替换,后来名词越来越多,我们及时采用latex中的gls包,大大减少了前后不统一的问题。再比如,项目组织问题。我们需要记录整个翻译过程,谁引入了错误、怎么引入的错误,以便吸取教训,更好地修正问题。得益于Git,我们可以流畅得进行翻译,并避免译者之间的冲突。公式也是比较麻烦的问题,我们都是照着原书,手打出来的,因此可能存在某种程度的不一致问题,如括号大小不对,当然公式内容都经过了检验。还有就是译者的语言风格不一致,这个没有办法,我们只能相互校对修改,融合各自的语言风格,最后再通过某一位译者进一步统一语言风格。我是进一步统一语言风格的译者。从小到大,语文和英语从来都是拖后腿的,让我来做这事真是尴尬啊。

在解决问题的同时,我们也归纳总结了一些翻译经验:

  1. 一定要使用latex,方便记录追踪。排版质量更不用说,绝对专业。Markdown还是不太适合。
  2. 翻译开始就要准备中英对照词表,可以使用latex中的gls包,否则之后会引起很多不统一的问题。不可能一下子把所有名词一下子都统计完,需要在翻译过程中逐一添加。只要有一位译者已经添加,我们就使用已经添加的名词。具体翻译成什么,随时都可以商量。翻译完成时,我们总共使用了886个中英对照名词,详见terminology.tex
  3. 数学符号也最好在翻译前事先统一,否则会导致很多错误。见math_symbol.tex。当然也可以一边翻译一边补充。
  4. 遇到原书错误的地方,一定要做好标记,方便之后讨论反馈。
  5. 使用Git跟踪翻译进度,既可以解决译者之间的更新冲突,也可以相互监督翻译进度,还不怕文件丢失。刚开始我们是放在Bitbucket上,后来迁移到GitHub。
  6. 基础的翻译人员不能太多,否则翻译风格太不一致,读起来不适应。我们一共4位译者,风格已经有点问题了,我觉得2-3位是最好的。
  7. 没有必要第一遍就翻得很好。翻译完全可以像梯度下降一样,慢慢迭代更新。翻译过程也是积累经验的过程,同样的翻译质量,第一遍就翻译很好可能需要花上2倍时间。就像牛顿法,虽然每步下降快,但每步花的时间太多了。这是方法论问题了,每个人看法都不相同,我觉得多次迭代更好。
  8. 不要瞧不起机器翻译,有时机器翻译比人翻得更好。我本身也是搞机器翻译的,有时候机器翻译的结果真的是惊艳!
  9. 翻译完成后,应该邀请非专业人士来阅读,他们更可能指出翻得不清楚的地方。有条件的话,要让女生读一读译文,不得不承认女生的语感比男生好很多。不吹不黑,女生校对之后,读起来好多了。
  10. 出版前事先与出版社签协议,不要大肆鼓吹,比如“AI圣经”,搞得我们很尴尬。也不要宣扬审校者、译者,我们负不起责任。我们更愿意读者先读电子版PDF,然后决定是否购买纸质版,而不是看到“AI圣经”、“北大”等一系列吸引眼球的词而买书。将来出版社是赚到钱了,挨骂的可是译者!

公开于GitHub

全书成稿之后,我们将其公开于GitHub,并公开3万行latex源代码。主要有几个考虑,首先就是我们的水平难以准确翻译原书,需要广大读者帮助修改校对。当然这也是在减轻责任。如果读者不花钱看了电子版PDF,还花钱去买纸质版,将来导致了读者的损失,我们的责任就没那么大了。我们真是机智!另外就是,英文版也是开放PDF下载的,我们没有任何理由把中文版藏起来。公开的结果也如预期,近80位读者对我们的翻译提供了很好的建议,详细可以见中文版的致谢。他们提出的建议都记录在GitHub上,特别是校对阶段的工作,我们都进行了整理,与源代码一起保存在GitHub上。遗憾的是,一些章节,如第15、16、20章,没有经过经验人士的校对,因此存在的错误可能会多一点。译者和读者之间也是存在意见分歧的,比如“representation”应该翻译成“表征”还是“表示”。“Representation”翻译成“表示”我们是经过仔细斟酌的,而读者也提出了翻成“表征”的理由,直到后期我们意见还是没有统一。后来那位读者自己找到了权威人士给出的说明,才同意翻译成“表示”。多亏了如此认真的读者,我们才能有目前的准确度。因此,我们将以所有贡献者的名义把稿费全部捐出,以示感谢。“开源、开放”是技术创新的一个重要驱动,希望我们开的是个好头。

再次强调一下,我们只是译者,不是作者。就像某广告语——“我们不生产水,我们只是大自然的搬运工”。如果读者觉得中文版内容很好,那是作者领域水平高才能写出如此高水平的书籍,而我们只是帮忙传达一下。如果读者觉得中文版读起来很困难,那很可能是我们译者水平不足,未能良好地传达作者的意思,希望读者多多批评。在此,我们也得感谢作者给我们的翻译工作提供的帮助。他们把所有图片和引用文件都发给我们,极大地减轻了我们的工作量。没有他们的支持,我们也不会这么快给出翻译。


出版社搞事

除了鼓吹“AI圣经”这些虚的东西以外,出版社也没有做好他们该做的事。比如排版后的latex不给我们统一,按他们的说法是不想引起混乱。这样导致的结果是我们根本不知道出版社的版本,只有我们单方面给他们堪误。但他们不一定记得改,比如第二章12=2×3×3我们提交堪误,出版社并没有改。这种情况就算了,我们责任更大。比较无语的是,他们还会引入额外的错误,比如数学符号那里,把“伪逆”打成“伪造”。。。我只想说,可不可以稍微专业一点。。当然这是出版社的业务问题以及与我们的价值观不同的问题,其他方面出版社还是非常给力的。比如人民邮电出版社的异步社区会提供很多书的PDF,也会与读者互动,还会送译者电子书。对我们译者也很好,我们有什么要求基本都满足了。“AI圣经”是我们之前没有想到他们会这么吹,算我们的责任。

总之,人民邮电出版社还是非常棒的,合作顺利愉快!张编辑王编辑都平易近人,我都跟王编辑吵了不知道多少回了,也不影响合作。


关于评论

有问题上GitHub,我们非常乐意接受批评和建议,忠言逆耳利于行,如这个评论的中一部分

“看到国外亚马逊的评论大都叫好,就找来看看。这本书对于基础知识的介绍并不明晰,用的数学符号、变量也有些随意,有些符号和变量只有在第一次出现的时候介绍一次,后面就再也不会解释,因此对于跳着看的同学,得整本书翻来覆去找某些变量和符号的含义(致谢后面的数学符号说明根本不全)。如果忘了概率相关概念,还是用其他书补一下比较好。我特别想知道有了池化层之后,反向传播算法是怎样的,可书中没有提到,令我很失望,全连接的情况大家都懂的,我也不需要知道。此书有些被过于吹捧了,对高手来讲,残差网络完全没有涉及,对抗生成网络介绍的太简略了。翻译的让人很难看懂,英文版其实也就那么回事。”

有理有据,专业评论!

但我们不欢迎喷子,如这个评论,我当然承认翻译得不好,但喷之前好歹举几个例子,我们还可以用来修改,否则说一百遍都毫无意义啊。

“翻译太烂 翻译太烂 翻译太烂
重要的话说三遍。
建议阅读原版。
翻译对不住纸张的质量。”

对于这个读者,我只想说,5rua5LuW5aaI55qE77yM5。我觉得书籍应该支持退货,希望他能退货,如果他能看到,我可以原价收购他买的书。我觉得他如果看了电子版就不会买了,罪过,浪费了他买房的钱。


能说的心得都说了,不能说的也说了,还有些蕴含在latex源代码里。有兴趣的可以围观latex源代码。希望买了书的同学能好好学习,也希望看了电子版的同学有所收获!