有问题联系公众号:寻沂
前段在公司做YouTube Dnn模型的复现,然后想在YouTube DNN(Deep Neural Network)里面加一下魔幻的搭配,就去了解了一下Attention。
可是,很多事情要更详细的了解难免追根溯源。
最后回溯到Seq2Seq模型,本篇主要介绍一下Seq2Seq相关的一些内容,为后面的Attention机制的了解做一下铺垫。
一般我在了解一个新概念之前会先找一个稍微正经一点的资料,不要被中文资料把自己带跑偏了。一般用的是维基百科。
什么是Seq2Seq模型
维基百科里面关于Seq2Seq的介绍:
Seq2seq is a family of machine learning approaches used for language processing. Applications include language translation, image captioning, conversational models and text summarization.
Seq2seq是机器学习里用于自然语言处理的一个算法簇,主要应用于语言翻译,图像字幕,会话模型和文本摘要提取。
Seq2Seq模型起初是谷歌发明用于做机器翻译的算法。
此外,在2019年12月Facebook在<<Deep learning for symbolic mathematics>>中提出了用Seq2Seq求解符号数学问题,包括函数微分,一阶常微分方程,二阶常微分方程等复杂问题。
不明觉厉。 小朋友,你是否有很多问号???
目前主流的Seq2Seq模型包括:
- RNN(Recurrent Neural Network,循环神经网络)
- LSTM(Long Short-Term Memory, 长短期记忆网络)
- GRU(Gated recurrent unit)
Seq2Seq 模型的输入是一系列的单词,输出是被翻译过后的另外一个系列的单词。
在Seq2seq模型中主要分为两个部分:
-
编码阶段: 在编码阶段,Seq2seq模型的编码器(Encoder)将输入的序列(比如一个中文句子)编码为一个隐藏层向量。
-
解码阶段: 在解码阶段,Seq2seq模型的解码器(Decoder)将隐藏层的向量解码为输出序列(比如一个英文句子)。
Seq2Seq中的RNN
接下来,我们以RNN为例,进一步了解Seq2Seq模型的内部结构。
在上面的图中,为了进一步解析了RNN的具体结构,将图1中的黑盒进一步透明化。
上图中的RNN cell
表示RNN模型中的一个神经元细胞。
每一个神经元细胞的输入包括两个部分input
和hidden state #0
。
输出同样的包括两个部分output
和hidden state #2
对于RNN而言,每一个神经元的输入hidden #t
,是上一个神经元t-1的输出。
举一个简单的例子:
在RNN模型中我们以:
今天你被绿了。
作为输入得到的输出为:
Your wife cheated on you today.
那么对于RNN的神经元细胞而言对应的六次输入输出分别为:
输入1: 今
hidden state #0
输出1: Your
hidden state #1
输入2: 天
hidden state #1
输出2: wife
hidden state #2
输入3: 你
hidden state #2
输出3: cheated
hidden state #3
…依此类推。
上述的例子并不表示实际情况(实际情况是你连对象都没有),只是为了表示hidden state #t
和 hidden state #t-1
之间的关系。
很明显的,在RNN中以上一个神经元的输出hidden state #t-1
作为下一个神经元的输入主要是为了捕获上下文之间的语意关系。
而hidden state #t-1
和 hidden state #t
所记录的关系的作用有点像我们小学作业里面填写单位。
小明身高1.75 __ (米,厘米,毫米,千米)
小王的爸爸是一 ___ 出租车司机(个,头,匹)
在RNN模型中通过hidden state的向下传播记录了词汇之间的序列关系,从而让我们记住了需要填写哪一个词汇,或者说哪一个词汇更符合现在的语境。
Seq2Seq模型上所做的优化
在Seq2Seq模型的基础之上,后来的研究人员为了进一步提升模型的效果有了其他的一些研究和优化。
主要的优化操作包括:
- Attention
Attention 翻译过来的中文名叫做注意力机制。所谓的注意力机制就是神经网络需要处理大量的序列信息的时候,通过Attention机制达到关注重要信息的目的。
我们还是以上面这个例子为例:你今天被绿了。
如果现在输入变成:
你今天下午加班的时候正在看一篇<<什么是Seq2Seq模型>>的微信公众号文章。然后,你的老婆给你打了一个电话:说她感冒了正在医院。你说:你很忙没有空接她的电话。就挂掉了。然后她打电话找了她的前任,于是你被绿了。
当我们输入一个很长的序列的时候,关注的点不可能是全部的信息,或者关注的信息所有偏重。
这个时候通过Attention机制挑选出一些重要的信息进行加权作为输入。
这样做可以直观理解的优势有两个:
(1) 通过Attention方式挑选重点信息作为输入,减少了复杂模型的计算量。
(2) 通过Attention方式将信息压缩,在处理长序列的时候能够记住更多的信息。
这个过程是不是有点像我们小学的时候的缩写句子?
- Beam Search
聊到Beam search,我第一时间想到的阿里的TDM(Tree-based Deep Model)。
虽然,对TDM的具体原理我不是很理解,但是第一次听到Beam search的时候是在阿里的关于TDM的一次分享会上。
Beam Search 具体是指:
在当前级别的状态下计算所有可能性,并按照递增顺序对他们进行排序,但只保留一定数量的可能结果(依据Beam Width决定数量),接着根据这些可能结果进行扩展,迭代以上的动作直到搜索结束并返回最佳解(具有最高概率的那个).
我知道看完上面这段话的时候你也不知道Beam search是在干嘛的,但是没有关系。
虽然我们做事情要认真一些,但是很多很多事情点到为止。这一次搞不懂的俺们下次再搞懂。今天的重点是了解一下Seq2Seq模型。
- Bucketing
Bucketing(装桶)和Padding(填充)主要是为了处理不同长度的句子。我是这么理解的。
在处理翻译问题的时候。如果输入输出Seq的长度不同。假如,输入的Seq长度为 L 1 L1 L1 输出的Seq 长度为 L 2 L2 L2
还是上面的例子为例,如果输入是:
你今天被你老婆的前任绿了。
输出假设还是原来的样子:
Your wife cheated on you today.
那么对应的输入和输出的Seq序列长度不等(当然实际上中文是要分词的)。
这个是时候,我们需要训练一个 L 1 L1 L1长度的Seq 到 L 2 L2 L2 长度的Seq模型。
如果输入有 n n n 种长度,输出有 m m m 种长度那么我们理论上需要设计最大到 n × m n\times m n×m 种可能组合的子图。
很显然,这样在实际的训练过程中是不太可能的。
这个时候我们通过padding的方式,对输入序列或者输出序列做固定字段的填充来达到序列长度相同的效果。
举个例子。一共有5组Seq2Seq的输入输出对,对应的输入长度 L 1 L1 L1 和输出长度 L 2 L2 L2 分别如下。
输入长度 L 1 L1 L1 | 输出长度L2 |
---|---|
10 | 20 |
9 | 17 |
2 | 3 |
20 | 60 |
25 | 52 |
这个时候如果不采用padding的方式,对应就有5种对应序列长度输入输出的子图。
为了减少子图的数量,我们采用Padding的方式,统一输入输出的长度。
对输入我们统一Padding达到的长度为25,对输出我们统一padding达到的长度为60。
这种情况下,只需要训练一个Seq2Seq的子图。
OK, 这个时候出来了另外一个问题。
对于对三条数据,输入的长度为2,输出的长度为3。如果采用Padding的方式。那么会存在大量的无效输入从而产生大量的低效计算。
我摸着秃掉的头想一想,我还不如多训练一个子图来得实在呢。
这个时候Bucketing应运而生,具体思路应该是这个样子。
[1] 首先,我们确定了Padding这种思想的有效性。
[2] 其次,我们对全局使用同一个长度的Padding是否能够带来效率的提升持怀疑态度。或者是否有其他方式能够使得效率更高存在保留意见。
[3] 最后,我们提出了一种新的方法,以少量的Bucketing和少量的Padding进行折中处理,使得效率最大化。
这个时候对于上述例子,我们可以对所有的输入输出对分成两个桶。
这时候我们需要训练两个子图,但是同样的获取了两种Padding的方式。例如我们的分桶为{[10, 20],[20, 60]}
那么对应上述的五个例子,Padding之后的输入就是:
Padding 后长度 L 1 L1 L1 | Padding 后长度L2 |
---|---|
10 | 20 |
10 | 20 |
10 | 20 |
20 | 60 |
20 | 60 |
如果到这里,大家还没有理解Padding和Bucketing结合使用的作用呢!
我就再勉为其难地再举一个例子。
假设,你家有开了一个伐木场。你是场里的光头强。
你砍掉的木头要从伐木场运送到家具厂,但是木头的长度不一样(前提是不能锯成一样的长度。)
这种时候你要去租车公司租车。每辆车10000块,但是每种车跑一趟耗油量不同,大车可能耗油300块,中车150块,小车100块,婴儿车50块钱一趟等等还有其他车。
这个时候为了把木材运完,你选择租用哪几种类型的就是选用了哪几种Bucketing,当你使用一个能装大木材的汽车装一个小木材,就相当于使用了Padding操作。
每一辆车相当于一个Seq2Seq的子图。每一次运送相当于一次计算。Bucketing和Padding结合的目的是为了花最少的钱把木材运完。
这里的钱就表示我们的算力。
最后
以上为了说明所举出的例子么有任何恶意。
只是希望提醒的是,所有的加班和技术的使用以及学习是为了更好地生活,而不是成为一个更好的工具人。
所以,工作之外应该还有很多人需要去陪伴和守护。
同样,技术只是手段,我们可以热爱技术但是也可以有更多和更好的其他目的。
论语里面说:君子不器。
最后,如果可以我希望通过技术解放自己,解放一批人。
当有一天我们每一个人都可以真正遵从内心的喜好去生活的时候。当我们每一个人的天赋可以充分的被释放并且得以彰显的时候。
那个时候是真正的——君子不器。