本吉奥的词嵌入,让被封印许久的RNN有了一丝解封的希望。原来RNN使用的是One-hot 向量,这种词汇表方式,让维度轻松突破50000维,整个RNN 的权重矩阵会变得巨大且难以训练。词嵌入将维度降至 128 或 256 维,使得在当时的计算条件下,训练如 LSTM这样的深层的循环结构变得在工程上可行。
RNN的诱惑如此的诱人,所以在本吉奥的词嵌入推出之后,包括本吉奥在内,大量的天才们开始尝试从各个方面对RNN进行优化。
1、基座模型和迁移学习的产生
托马斯·米科洛夫(Tomas Mikolov)就是其中的一个。
托马斯·米科洛夫(Tomas Mikolov)
他来自捷克,从读博期间,他就在研究RNNLM,试图对RNN进行优化。他在当时,观察到了一个现象:即使在复杂的 RNN 中,学出来的词向量也表现出了一定的线性关系。这个现在被经常用来解释什么是词向量的例子,就是他在当时发现的。我们还是来回顾一下这个耳熟能详的例子吧。
在 RNNLM 训练出来的词向量空间中,男人和国王会经常在权力的语境空间出现,在空间上:假设 “国王” 在坐标 (1, 5) , “男人” 在坐标 (1, 1)。在这个时候,从“男人”变成“国王”,只需要在这个坐标系里面向上移动四格。有趣的是,他发现“女人”和“女王”这两个词也会出现在权力的语境空间中,把“女人”这个词向上移动四格,会得到“女王”这个词。这个发现令米科洛夫很是兴奋,一个相对模糊的概念(成为王)在向量空间里面居然会被编码成固定的方向向量 (0, 4)。而且这种特征,在时态关系,国家与首都等很多关系中都存在。
这种关系,是RNN通过大量复杂的非线性运算得出的结论。但是很巧,结论表明这个特征是线性结构的,但是RNN并不知情,所以它还在用它原生的非线性公式在死慢死慢的计算。米科洛夫做出了一个大胆但极具价值的改进:“既然词向量的这种代数关系是线性的,那我是不是根本不需要那个复杂的、费时间的非线性隐藏层(Tanh/Sigmoid)?”事实证明他是对的。对于“学习词向量”这个特定任务来说,非线性层不仅是多余的,甚至是阻碍。去掉它之后,模型变成了纯粹的线性运算,速度提升了几个数量级,而且捕捉到的线性关系(类比关系)反而更纯粹了。
我们有必要从数学本质上思考一下这次变换。这次变换不仅仅是一次简单的效率优化,它背后思考范式的转变,甚至影响了整个行业。米科洛夫在本吉奥的框架的基础上,做了三件非常重要的事。
第一件事情是他把选择题改成了判断题。在本吉奥的网络里,网络回答的问题是:某个词A,和我这词表里的5万个词相似的概率都是多少呀?都给我算出来,我选个最大的。而米科洛夫的问题是:A和B这两个词很相似,你觉得对不对?这就让训练过程变得很容易,米科洛夫准备的负样本(本身就是错误的训练数据)就可以很少,随便找几个随机的词就可以了。选择负样本最大的要求,就是这些故意选来出错的样本,不能一不小心是正确的,这种一不小心造成的问题就是负样本的假阳性,这会导致模型会把本来正确的内容学习成错误的。
这就像你教小朋友数学题。你的教育方式是告诉他什么是正确的,然后再告诉他几个错误答案。
你告诉他正确的答案是1+1=2,这个就是正样本,然后你再随便从无穷的数字里面随便找两个作为错误答案。小朋友就能学会1+1=2这个知识点了。但是一不小心,你把1+1=王当作错误答案告诉小朋友了,可这个答案在另外一个知识点“学汉字”上可能是正确答案,这个负样本就会影响后续“学汉字”知识点的训练过程。这是训练时最需要避免的问题。米科洛夫所处理的文字领域,是个正确答案很稀疏的领域。换句话说,在这个领域里面,正确答案像彩票中奖一样,很稀少,所以米科洛夫才可以大胆的用随机负采样的方式随便找几个,而不用太担心运气不好抽到假阳性的案例。
从本吉奥的把所有的词都抽出来当作负样本,到米科洛夫的只选几个当作负样本,计算量就大幅度下降了。
第二件事,是米科洛夫的数学功底的体现。本吉奥的网络的最后,是一个softmax函数。这个函数很常见,字面意思就是软最大。理解它的作用就可以按字面理解,只要你知道它对应的那个Hard Max是啥就可以了。我们用一个具体的例子来介绍一下。
如果我们把猫,狗,桌子这三个词在本吉奥的网络里面跑,得出了三个原始分数:
猫:3.0 分,狗:1.0 分,桌子:-1.0 分。这时候,最大值都是猫。如果我们用Hard Max,我们得到的结果可能是:[1, 0, 0],因为猫最大,别的都可以忽略。但是在SoftMax里面,就可能会是[0.87, 0.11, 0.02]。这是因为SoftMax为了能更好的体现出这三者之间的连续关系,引入了e这个神奇的数字。
它会把原来的数字都变成 e 的次方 (e^x)。这样猫的值就变成了 e^{3.0} \approx 20.1 ,狗就变成了 e^{1.0} \approx 2.7 ,桌子就成为了 e^{-1.0} \approx 0.37 。再把这三个数加起来 ,再将总数作为分母求各自的占比,就成为了刚才看到的概率[0.87, 0.11, 0.02]。
这是神经网络里最常见的归一化操作,能很好的体现这些词的概率差异,而且又将这些差异压缩在0-1的区间内,每个数字不会显得过大,也不会过小。这种“一碗水端平”能照顾到尽量多的数字,是个非常好的方法,自从玻尔兹曼发明出来之后,在统计学和人工智能领域中被经常的使用。
但是这个SoftMax函数是个非常耗费算力的方法,特别是在求导上。乘法的导数很难算,特别是在反向传播这个要经常计算导数的机制下,SoftMax函数求导是个重要的优化点。所以米科洛夫引入了对数运算,对数运算的重要能力就是能把指数乘变成指数加,这样加法就可以独立求导了,
更重要的是,这次对数的引入,让米科洛夫发现了一些奇怪的特征,原来很烦人的指数运算能被对数运算抵消掉,他就利用这个特征开始做了第三件事。
第三件事情就是,把原来大家认为是配角的线性运算,放到了前台,彻底开除非线性处理。一直以来,非线性变换被认为是创造性的来源,所以在机械重复的线性变换后面,接个非线性来扭曲空间,增加创造力,是常规操作。但是米科洛夫发现,当对数和指数被相互抵销后,从数学上看词和词之间的关系这件事,其实就是线性的。向量之间的关系,最好的表达方式,难道不就是点积吗?
点积(Dot Product),在数学上也被称为数量积或内积,在人工智能领域,它可以应用为:它是衡量两个向量“相似度”的最简单标尺。关于点积怎么计算,我在此就不赘述了,更好理解点积的本质的,是它的几何视角。点积的几何公式是这样的:
这里面的|\mathbf{a}| 和 |\mathbf{b}|,是指向量的长度。\cos(\theta) 是两个向量夹角的余弦值。
当夹角为0的时候,余弦值为1,此时这两个向量的点积是最大的。在词构成的空间中,向量同一个方向等同于两个词是近似的。所以点积的大小,就能无缝的等同于两个词的相似程度了,相对点积值越大,这两个词就越相似。
所以,在单纯的词运算上,米科洛夫大胆的砍掉了计算缓慢的非线性变换,用线性的点积来进行替代,让百万级词需要跑几周的训练变成了百亿级词只需跑几个小时。
这个想法的萌芽是在微软实习期间出现的,当时RNN+非线性层的低效率让他痛苦至极。2012年,他加入了Google Brain团队。当时他的领导告诉他,他需要处理的词不是几百万个,而是Google News的1000亿个词。在这个巨大的任务压力下,他完成了上述对之前RNN的魔改,这个产品也被他很直接的命名为Word2Vec。
如果说本吉奥宣告了“把词变成了向量”是可行的,那么Word2Vec则是真正的提供了一个可用的方法。它让NLP真正的从原来的象牙塔上走下来,来到了人世间。一个普通学生,用一台单机,几个小时就能把维基百科跑一遍,得到一套高质量的词向量。
除此之外,它还导致了整个行业的认知革命。它不仅仅是发现了语义的代数结构,它还告诉行业,不仅仅是语言可以运算,图像,声音等也都可以运算。这种运算不是杨立昆式的波形信号叠加,而是真正的意义层面的运算。加减法不再只是一种数学方法,而真正成为了在现实具体的意义世界上的一种逻辑规则了。让我们再回顾一下能代表这次认知革命的公式:
King - Man + Woman = Queen
最重要的是,Word2Vec开启了“预训练 + 微调”的时代。辛顿虽然用DBN向行业展示了这一手法,但是玻尔兹曼机的成果是无法迭代的。Word2vec训练出来的模型,是可以保存成一个静态的文件的,这其实就是现代大模型训练中的基座模型的前身。后面人们的训练范式就变成了:“我们可以先在一个超大通用语料上学点东西,然后直接搬到特定的任务里去用”。
“通用预训练 + 下游任务”的迁移学习模式产生了。从那以后,搭建RNN模型的标准起手式就变成了:
加载 Word2Vec 权重。
接上 LSTM或轻量版GRU
接上 Softmax
然后无论是做训练,还是使用模型,只需要在Softmax这最后一层接上对应的步骤后,这个循环就建立完成了。这种标准化的流水线,直接促成了2014-2016 年 NLP 的大爆发。深度学习NLP的黄金时代来临了。
2、从词语到句子的战争
在Word2Vec搞定了词之后,Seq2Seq(Sequence-to-Sequence,序列到序列模型)的出现,标志着 NLP 从“处理词”的时代,正式跨越到了“处理句子”甚至“生成语言”的时代。Word2Vec 就像是给 AI 行业发了一本“新华字典”,AI 拿着这本字典,哪怕没见过这个词,查一下它的坐标,看看它的邻居是谁,大概就能猜出它是啥意思了。但是它只能告诉你“国王”和“王后”很像,但它无法理解“国王今天心情不好,所以他下令要把厨师关进大牢”这句话的因果逻辑。它只能看到一堆孤立的词向量散落在空间里。而Seq2Seq就是为了解决这个问题而出现的。
辛顿的弟子,当时在Google 的 伊尔亚·苏茨克维(Ilya Sutskever )和本吉奥团队的 赵京铉(Kyunghyun Cho )几乎同时提出了 Sequence-to-Sequence (Seq2Seq) 模型。两位深度学习的宗师辛顿和本吉奥,开始了一次非常重要的隔空对决。
伊尔亚·苏茨克维(Ilya Sutskever )
赵京铉(Kyunghyun Cho )
德米特里·巴赫达诺夫(Dzmitry Bahdanau)
很多人把这次学术撞车事件和当年牛顿和莱布尼兹的发明微积分的故事作了比较。如果说牛顿和莱布尼兹之争,是一场两败俱伤而导致江湖分裂的悲剧的话,那么这次学术撞车则是一场在对方的尾流中加速,最终一起冲过终点,开创了一个时代的皆大欢喜的喜剧。
伊尔亚加入Google,是因为AlexNet的成功。他和导师辛顿、师兄 Alex Krizhevsky创立的公司被Google收购,他得以加入了Google Brain。那时候的 Google Brain 就像是当年的曼哈顿计划实验室,人才密度极高。伊尔亚的办公室和米科洛夫离得不远,甚至还经常在同一个食堂吃饭。米科洛夫解决了“词”的问题,伊尔亚解决了“句”的问题。虽然他们在最著名的那两篇论文上没有互署名字,但他们在一个极其紧密的团队里。伊尔亚是Word2Vec 的第一批“超级用户”。
在Google,伊尔亚终于体验到了当地主家儿子的幸福感,面对海量的数据和算力,他开始思考一个问题:“深度神经网络(DNN)在图像分类上表现这么好,是因为图像不仅维度高,而且结构复杂。语言(Language)也是一种极其复杂的高维数据,为什么神经网络在翻译上却输给了传统的统计模型?”
当时的机器翻译(SMT)是一个由几十个独立模块拼凑起来的“怪兽”(分词、对齐、调序、语言模型...)。伊尔亚作为一个拥有“深度学习信仰”的人,他坚信:一定存在一个单一的、巨大的神经网络,能够直接把英文变成法文,中间不需要任何人工设计的模块。
伊尔亚的切入点非常数学化。他盯着机器翻译的本质看: 翻译不就是计算 P(Target | Source) 吗?即:给定源句子,生成目标句子的概率。他想到了 RNN,特别是 LSTM,在这种任务下非常的合适。如果用一个 LSTM 把源句子读一遍,不管是长是短,读完后,LSTM 内部的 Hidden State 就包含了这句话的全部意思。再用另一个 LSTM,根据刚才读到的意思,一个字一个字地把目标语言写出来。这样不就可以在完全不进行人工设计的情况下,端到端的完成了这个翻译的工作。
这个时候,从芬兰阿尔托大学博士毕业的赵京炫来到蒙特利尔大学做博士后。他并没有像伊尔亚一样,有一个工程上的需要消灭的假想敌,反而有着更强烈的对向量压缩的狂热。他和搭档德米特里·巴赫达诺夫(Dzmitry Bahdanau)始终相信,人类的任何一句思想(无论多复杂),都可以被无损地压缩成一个固定长度的数学向量。这在当时是个狂妄和离经叛道的想法,它认为语言的本质是可以被“数学化压缩”和“解压”的。
他们也和伊尔亚一样,想到了编码器和解码器的配合工作。伊尔亚的脑海中出现的第一个应用是“翻译”,可是在赵京炫脑海中,什么不是“翻译”呢?谁规定向量压缩和还原只能在不同语言之间进行呢?
两组殊途但同归的人马,几乎在同时开始了自己的项目,采用的也是非常类似的方式。当然,他们几乎也遇到了同样的问题。
第一个问题是:梯度消失与长句子问题
普通的 RNN 根本记不住长句子。如果输入一句话有 50 个词,读到最后,开头的词早就忘光了。如果连输入都记不住,怎么翻译?
伊尔亚的解法:深层 LSTM (Deep LSTM) 他没有用普通的 RNN,也没有用单层的 LSTM。刚进地主家,体会到无限算力爽度的他,极其暴力的堆叠了4层LSTM。至于为什么是4层,伊尔亚也不知道,纯粹是试验出来的。此时,他在AlexNet时期的硬件功底就完全的发挥了出来,他找了4 块 GPU,和当时做AlexNet时一样,手动管理GPU之间的数据同步,当 GPU-0 算完 t=1 的数据,立刻扔给 GPU-1。GPU-1 开始算第 2 层的 t=1,与此同时,GPU-0 不闲着,立刻开始算第 1 层的 t=2。就这样,把4块GPU连起来,组了一个四层的LSTM。
在训练过程中,面对数值上的问题,也体现出了伊尔亚大胆的一面,他近乎鲁莽的引入了梯度裁剪,用个简单的阈值避免梯度爆炸,用自己设计的初始化分布矩阵代替高斯分布初始化。除了他对数字有着天赋的直觉之外,Google在算力资源上的充沛,也给了他可以试错的空间,让他能有勇气去赌自己选择的正确性。
相反,另外一组苦守在苦寒之地蒙特利尔大学的赵京炫团队就不敢这么任性了。Mila 的学生们往往要排队共用几块显卡,所以赵京炫很早就意识到,他们根本玩不起LSTM。LSTM 有三个门(输入、遗忘、输出)和一个细胞状态,参数太多,显存占用太大,训练太慢。于是,赵京炫开始在大脑里对这个门控电路作精简。他把遗忘门和输入门合并成了“更新门”,去掉了细胞状态。GRU (Gated Recurrent Unit) 就这样诞生了。这不是为了数学上的美感,纯粹是为了“在有限的显存里能跑起来”。结果发现,这个“阉割版”的 LSTM 竟然跑得更快,效果还没掉!
两组人马,采用不同的方法,都在一定程度上解决了梯度消失问题。
第二个问题是:巨大的词汇量
伊尔亚的解法:工程暴力与简单的 Softmax 这就体现了 Google 的风格。Word2Vec 的负采样并不能完全照抄,因为米科洛夫的任务是表示,它只需要得到相对位置就可以,而伊尔亚所面临的问题是“生成”,他必须要得到“纯粹的概率准确性”,所以他坚持在 GPU 上实现了高效的 Full Softmax(全量计算)。他利用了 GPU 的并行能力,硬生生地把几十万分类的计算量扛了下来。这证明了:只要算力够强,很多算法上的技巧其实是不需要的。
Cho 的解法:Sébastien Jean(Cho 的合作者)在Word2Vec负采样的启发下,提出了一种基于重要性采样的方法,这种方法比负采样的二分类更加的精细,效果也更加的明显。这种解题思路,带有非常明显的本吉奥团队风格,是一种为了在有限算力下训练巨大词表模型而采用的一种“战术妥协”。我们在这里把这种方法表达成一种:“小心翼翼地偷懒”。
先看看问题是什么,在 Seq2Seq 模型中,每生成一个词,网络都要做一次Softmax运算来计算概率分布。和前文描述的一样,为了算出“猫”这个词的概率,你必须把词典里所有的词(比如 50 万个)的得分都算一遍,然后加起来做分母(归一化)。这意味着,每预测一个字,就要做 50 万次向量乘法。如果你要翻译一个长句子,训练几百万次,这个计算量是天文数字。本质上,这种完美主义思维的做法是:为了判断“猫”是不是正确答案,必须同时知道它和“桌子”、“飞机”、“分子生物学”等所有无关词汇的关系。
重要性采样的核心思考是:我们真的需要算出所有词的概率吗?我们偷点懒可不可以?米科洛夫告诉我们可以,但是他太偷懒了,直接把选择题改成计算题了。现在的考试任务告诉我们,修改题型是不可以的,但是可以去掉一些选项。
去掉一些选项的灵机一动,依然是来自思维层面的改变。这里的重要改变的灵感来自于统计学中的蒙特卡洛方法。蒙特卡洛是摩纳哥的一座著名城市,以赌博闻名于世。冯·诺依曼用这个赌城的名字为这种方法命名,可见其中充满了随机性和博弈感。
蒙特卡洛方法的本质可以概括为一句话: “利用随机试验的频率,来逼近数学上的概率(或积分值)。”理解蒙特卡洛方法的最直观的例子就是:如何计算圆周率 \pi?使用蒙特卡洛方法的解法是:
画图: 画一个边长为 2 的正方形(面积=4),里面内切一个半径为 1 的圆(面积=\pi)。
撒豆子(随机采样): 抓一大把豆子,随机均匀地撒在正方形里。
数数(统计频率):假设你撒了 N 颗豆子,数一下,落在圆圈里的豆子有 M 颗。
计算:概率理论告诉我们:豆子落在圆里的概率 \approx 圆面积 / 正方形面积,所以,M / N \approx \pi / 4。
蒙特卡洛方法是基于概率论中两个基石定理:大数定律和中心极限定理的严谨科学。所以在本吉奥团队眼中,它变成了重要性采样。实际上,我们没有必要计算所有词的概率,只要随机抽100个词算一下平均值,然后根据采样概率加权修正。只要抽样是科学的,这个估计值在数学期望上就等于真实值。这里的抽样就等同于“偷懒”,而这里的加权,就是所谓的“小心翼翼”。因为我们只算了一部分词,算出来的概率肯定是不准的(分母偏小)。重要性采样的数学公式里有一个权重项,专门用来修正这个偏差,告诉模型:“虽然我只给你看了这几个词,但你要知道外面还有很多人,所以你要按这个比例把梯度放大一点。”
正是这种“抓大放小”的统计学智慧,让本吉奥团队在没有 Google 那种超级算力的情况下,依然训练出了能处理几十万词汇量的翻译模型,让学术界在单卡 GPU 上也能训练词汇量巨大的翻译模型。
这两个不同的团队,各自用自己擅长的方式,解决着NLP领域上的重要问题。辛顿和本吉奥仿佛在通过自己的弟子,进行着隔空对决,争夺人工智能领域上那最璀璨的皇冠上的明珠。当时,他们谁也没想到,他们的这场世纪之战,将会引发多么大的一场革命。
伊尔亚和赵京炫们,即将遇到的第三个问题是长距离依赖问题,这个问题是困扰着整个RNN谱系的经典问题。谁也不知道,这次他们的解决方案,改变了整个世界的走向。从此,人工智能历史上最重要的机制,开始站在了历史舞台上。