本系列文章是吴恩达深度学习攻城狮系列课程的笔记,分为五部分。
这一章主要将了循环神经网络。
我的笔记不同于一般的笔记,我的笔记更加凝练,除了结论以及公式,更多的是对知识的理解,结合课程可以加速理解,省去很多时间,但是请注意,笔记不能替代课程,应该结合使用。
结构化机器学习项目,我建议放在最后看。
首先学这一节对你后面的学习没有影响,我就是跳过去学的。而且他更多的讲的是策略,尤其是举了很多后面的例子,你听了不仅不太好懂,而且没啥意思,所以我建议放在最后看。
神经网络与深度学习(Neural Networks and Deep Learning)
改善深层神经网络:超参数调整,正则化,最优化(Hyperparameter Tuning)
卷积神经网络(Convolutional Neural Networks)
序列模型与循环神经网络(Sequence Models)
结构化机器学习项目(Structuring Machine Learning Projects)
输入和输出都可能是序列,而且输入和输出的序列长度并不一定能保证一致,甚至输入内部的长度也不能保证一致。
到现在,已经构建了x,一个维度可变的矩阵,到y,维度可变的矩阵,如何建立映射就是模型的事情了。
如果用传统神经网络实现模型,会面临两个问题:
循环神经网络的思路就是,在输入层到输出层之间弄一个隐藏层,这一个隐藏层可以适应不通长度的输入。
对一个样本的计算过程是:
双下标可以这么理解,第一个下标是目标,第二个下标是要利用的(要乘的)变量类型
之所以叫循环,是因为全体过程走下来,对于一个样本的每一次循环来说,用的参数都是一个参数,只不过在递归的,依次地对样本的每个词元做处理。
从这个过程来看,每一个a和前面所有的样本有关,也就是说有时序特性。缺点在于无法学习反向的联系,后面会优化。
重写一下公式:
bp through time环节:
损失函数:对每一个 y < t > y^{
这样,如果把损失函数降到很低,那么总和低,每一个词元预测的正确率就都会很高。
至于具体怎么求导,就是框架的事儿了。(其实我很好奇,但是现在先还不管),知道损失函数就足够了。
RNN变体用于各种序列任务中。
多对多的叫many-to-many,是最经典的RNN,通常用于命名实体识别这种。
多对一的叫many-to-one,这种只在最后一个有输出。
一对一的,就是前面经典的神经网络
one-to-many。这个就是送进去第一个x,然后别x的可以用前一步输出的y替代,或者就不需要再送进来了,感觉就是个马尔科夫。
many-to-many有特殊变体,比如机器翻译中,两个序列的长度就不同,又比如有的输入不是序列,有的输出不是序列。
这个要用encoder和decoder,前面是一个多对一的,不输出,但是会把整个句子变成一个a,相当于编码,然后送到decoder里,相当于一对多,再解码。
还有双向RNN,相当于一个从前到后的+一个从后到前的RNN,然后y通过两个隐变量计算。
这一节比较难理解,我重点解释。
语言模型:计算一个给定句子的概率。
至于概率怎么算的,你可以记住这句话,从本质来说,是计算一系列soft-max向量,基于这些向量可以得出给定句子的概率。具体细节后面慢慢说。
语料库:首先要有一个corpus,应该是语料库,语料库里有一大堆句子,每一个句子可以理解为一个样本。
标记化tokenize:然后运用已有的vocabulary,将语料库中的每一个样本,转化为one-hot相量的矩阵,比如 y < 1 > , y < 2 > , y < 3 > y^{<1>},y^{<2>},y^{<3>} y<1>,y<2>,y<3>
最后就是训练参数。
这里给的例子看起来比较迷惑,和前面的many-to-many很不一样,因为最开始的任务是词性分类任务,T个输入就有T个输出,对一个输入就要预测其词性。而这个任务是单步预测,预测第一个不需要任何条件,预测第二个需要第一个作为输入以此类推,令y落后一步与x,因为要落后,所以 x < 1 > = 0 , x < t > = y < t − 1 > x^{<1>}=0,x^{
我们再逐个解释一下 y ^ \hat{y} y^的含义。
y ^ < 1 > = [ P ( a ) P ( c a t ) ⋮ P ( Z u l u ) ] \hat{y}^{<1>}=\begin{bmatrix} P(a)\\ P(cat) \\ \vdots \\ P(Zulu) \end{bmatrix} y^<1>=⎣ ⎡P(a)P(cat)⋮P(Zulu)⎦ ⎤
y ^ < 2 > = [ P ( a ∣ c a t ) P ( c a t ∣ c a t ) ⋮ P ( Z u l u ∣ c a t ) ] \hat{y}^{<2>}=\begin{bmatrix} P(a|cat)\\ P(cat|cat) \\ \vdots \\ P(Zulu|cat) \end{bmatrix} y^<2>=⎣ ⎡P(a∣cat)P(cat∣cat)⋮P(Zulu∣cat)⎦ ⎤
y ^ < 3 > = [ P ( a ∣ c a t , a v e r a g e ) P ( c a t ∣ c a t , a v e r a g e ) ⋮ P ( Z u l u ∣ c a t , a v e r a g e ) ] \hat{y}^{<3>}=\begin{bmatrix} P(a|cat,average)\\ P(cat|cat,average) \\ \vdots \\ P(Zulu|cat,average) \end{bmatrix} y^<3>=⎣ ⎡P(a∣cat,average)P(cat∣cat,average)⋮P(Zulu∣cat,average)⎦ ⎤
首先明白,输出的是一个soft-max向量,代表着10000个词的概率。因为预测第一个词没有给出任何条件,所以就直接预测,至于预测如何,第一个是随机的。但是从第二个开始就不一样了,就变成条件概率了,至于条件,就是 y < t − 1 > y^{
最后就是损失函数定义,还是如前面所说的交叉熵。
以上只是训练的过程,正因为是巡练,所以 x < t > = y < t − 1 > x^{
请注意,后半截的预测并不是结果,只是给出soft-max向量,很多时候,并不一定采用概率最大的那个词元作为预测结果。
在你明白预测相量的本质就是soft-max向量以后,我们回归最开始的定义:语言模型可以给出一个语句的概率,那这个概率是怎么算的?
计算过程:给定一系列y,丢进去语言模型,可以得到一系列 y ^ \hat{y} y^,然后 P ( y < 1 > , y < 2 > , y < 3 > ) = P ( y < 1 > ) P ( y < 2 > ∣ y < 1 > ) P ( y < 3 > ∣ y < 1 > y < 2 > ) P(y^{<1>},y^{<2>},y^{<3>})=P(y^{<1>})P(y^{<2>}|y^{<1>})P(y^{<3>}|y^{<1>}y^{<2>}) P(y<1>,y<2>,y<3>)=P(y<1>)P(y<2>∣y<1>)P(y<3>∣y<1>y<2>),至于这三个条件概率,就从对应的 y ^ < t > \hat{y}^{
到这里你也会发现,其实语言模型不只是能计算概率,也可以进行预测,但究其根本,都是概率的计算。
已经训练好了,怎么用呢?所谓的用,就是生成一个序列,可以理解为根据模型本身就代表一种分布,我们给输入,就可以对分布进行采样,得到输出。
采样原则就是根据输出的y-hat里面的概率,随机选择一个作为采样结果词元,而并不一定是直接用概率最大的那个。
理论上,如果你不给输入,也就是直接从头预测,可能每次的结果都基本相同,因为这是个马尔科夫过程。
如果要改变结果,你就需要给一些输入,即使只是第一个输入,也会极大地改变结果,输入越多,预测越准。即使是这样,普通的NLP生成的结果也有一种胡言乱语的感觉,尤其是用char作为词元的模型。
有一处不合理的就是,就是无论你输入什么,都不会改变第一个输出的概率分布。
梯度下降的原理至今没搞清楚,一方面大致是越靠前的层,就越不容易被bp调节,另一方面就是前面的信息向后传递的过程中损失了很多,所以中间隔得越长,就越学不到长期依赖。
梯度爆炸虽然也会出现,但是很明显,可以迅速处理。比如使用gradient clip,当发现有溢出,就进行缩放。
目前有GRU和LSTM两种方式改进,改进后,隐藏层对外的接口表现不变,只不过内部增加了新的变量和转化。
Cho, Kyunghyun, et al. “On the properties of neural machine translation: Encoder-decoder approaches.” arXiv preprint arXiv:1409.1259 (2014).
Chung, Junyoung, et al. “Empirical evaluation of gated recurrent neural networks on sequence modeling.” arXiv preprint arXiv:1412.3555 (2014).
思想:
既然单靠隐变量无法记忆较远的信息,那么干脆就创建一个记忆变量,储存较远的信息,又因为较远的信息不多,所以创建一个c变量(可以是向量)也还合理。
c变量通过门变量(也可以是向量)的控制,来确定是要采用新的c值还是保持原状。假设c保持原状,那么就代表一种记忆,也意味着隐变量只受到当前步的微小影响。如果用新的c值,那么就代表更新记忆,舍弃陈旧的记忆。
那么问题来了,看起来c和a是独立的,如何通过c影响输出呢?
那就是用这个c来替代a。
公式:
Hochreiter, Sepp, and Jürgen Schmidhuber. “Long short-term memory.” Neural computation 9.8 (1997): 1735-1780.
这篇论文比较难,深入的讲解了gradient vanishing的原理。
公式:
我个人觉得LSTM更加合理,首先是a和输入共同转化为门,tilde-c,进一步变成c,最后变成a,一个循环走下来,实际上所有的量本质上还是由a,x决定的,这和经典RNN的本质是相同的。
同时,形式上看c和a几乎是平行的,c用来储存记忆,而是否储存记忆,是由a和x决定的,而a代表着曾经的信息,这个因果决定关系很合理,即通过从开始到现在的所有信息决定更新和遗忘的比例,进而影响a。
LSTM和GRU对比:
说实话,相比于GRU,我更喜欢LSTM,并且LSTM更早提出,更加直观,更加灵活,但是灵活的代价就是成本高,因为有三个门。
GRU只有两个门,所以成本更低,结构简单,很多人逐渐开始测试这种方式。
Van der Maaten L, Hinton G. Visualizing data using t-SNE[J]. Journal of machine learning research, 2008, 9(11).
平常我们写句子的时候,同义词总是可以互相替换,但是在基于频率的one-hot编码下,即使是同义词,也可能相距甚远,不能相互替换。
这个时候,就需要一种更好的编码方式,试想能否采用多种特征去描述一个词,构成一个特征向量,近义词的特征向量比较相似,这样就可以互相替换。
这就是词嵌入的理念,向量之间的相似性类似于数值的相似性,其实在最开始的线性网络中,数值的相似性就已经是隐含的了,只要输入的数值接近,结果就会接近。
之所以叫词嵌入,是因为可以将n维的特征向量放到一个n维空间里,每一个向量对应于一个点,相当于把一个点嵌入空间中。
理论上,相似的向量总是会聚在一起,就像聚类一样。词嵌入好处很多,比如信息储存量很大,比如存10000类,只需要300维的向量,相比起来,one-hot就得10000维,这样的话,词嵌入就可以有巨大的词汇量。而且,这种词嵌入是有扩展性的,新进来的类别不会影响维度,所以可以不断扩充。
为了直观查看词嵌入的效果,需要可视化,但是n维空间无法可视化,所以需要降维,这种降维算法就叫做t-SNE,作者是大名鼎鼎的Hinton。
二维化以后,就可以直观地看出词嵌入的分布了。
词嵌入是NLP领域中很重要的概念,但是思想却很朴实,所以开创性的成就不一定复杂。
词嵌入模型只是一个编码模型,和训练模型是解耦的,所以获取词嵌入模型有两种方式:
用已经预训练好的词嵌入模型,迁移到另一个小任务中去训练。这一个训练过程,相当于在已经构建好的空间中,再次嵌入一些新的向量。
为什么是小任务呢?因为新样本的训练无疑会影响原来的向量空间,样本太多就会破坏掉原来的模型,这就和重新训练一个没太大区别了。
最后就是选择性的微调一下。
词嵌入可以用于找同义词,比如男人对女人,我就可以通过国王对应到王后。
设三个embedding后的向量 e m a n , e w o m a n , e k i n g , e q u e e n e_{man},e_{woman},e_{king},e_{queen} eman,ewoman,eking,equeen
从向量角度理解, e m a n − e w o m a n ≈ e k i n g − e q u e e n e_{man}-e_{woman}\approx e_{king}-e_{queen} eman−ewoman≈eking−equeen
假设我们要找出这个 e q u e e n e_{queen} equeen,我们就需要找到满足这个条件的变量: arg max s i m ( e w , e k i n g − e m a n + e w o m a n ) \argmax sim(e_{w},e_{king}-e_{man}+e_{woman}) argmaxsim(ew,eking−eman+ewoman)
s i m ( u , v ) = u T v ∣ ∣ u ∣ ∣ 2 ∣ ∣ v ∣ ∣ 2 sim(u,v)=\dfrac{u^Tv}{||u||_2||v||_2} sim(u,v)=∣∣u∣∣2∣∣v∣∣2uTv
这个sim函数就叫cosine similarity,用于衡量向量相似性,当向量同向,sim=1,垂直就是sim=0,相反就是-1。
另一种计算方式是计算不相似性,这个就是经典的欧氏距离。
通过这种方式,就可以实现基于embedding的类比推理。
词嵌入矩阵 E = [ e 1 , e 2 , ⋯ , e n ] E=[e_1,e_2,\cdots,e_n] E=[e1,e2,⋯,en]
里面的每一列都是embedding后的向量。
如何从词嵌入矩阵中提取一个向量呢,有 E ⋅ o j = e j E\cdot o_j=e_j E⋅oj=ej,因为one-hot的特殊性,故有上面的公式,但是实际要取一个,直接用one-hot中值为1的索引对E切片就好了。
Bengio, Yoshua, Réjean Ducharme, and Pascal Vincent. “A neural probabilistic language model.” Advances in neural information processing systems 13 (2000).
建立一个语言模型可以用于学习词嵌入。
思路就是在第一层就用embedding层,之后加入语言模型,感觉有点卷积层的意思了,卷积层就是先提取特征,而我认为embedding就是词元的特征。
由于将E矩阵也在bp的范围内,所以E矩阵会朝着最大化提取信息的方向训练,最终目的是让准确率提高。
另一种理解方式,假设我们给出orange juice,apple juice,purple juice,三个水果都预测出一个juice,为了得到同一个结果,bp训练强迫E矩阵对三种水果形成相近的embeddings。
这一过程听起来比较玄学,效果和原理有待考证。
因为这里没有用到RNN,所以我们可以用多种方式选择参考的输入数据
Mikolov, Tomas, et al. “Efficient estimation of word representations in vector space.” arXiv preprint arXiv:1301.3781 (2013).
Word2Vec是一种学习词嵌入的算法。
(context,target)配对,作为监督学习。
通过中心词排推断上下文一定窗口内的单词。这个听起来就很难,但是我们也不是要去解决这个问题,而是要顺带学了词嵌入
Mikolov, Tomas, et al. “Distributed representations of words and phrases and their compositionality.” Advances in neural information processing systems 26 (2013).
首先构造样本,样本由1+k个样本组成:
规定问题:训练一个分类器,辨别context和word是正采样获得的还是负采样获得的
简化后的问题公式就变成了: P ( y = 1 ∣ c , t ) = σ ( θ t T e c ) P(y=1|c,t)=\sigma(\theta_t^Te_c) P(y=1∣c,t)=σ(θtTec),对一个context,我们理论上需要训练n个target二元分类器。
实际上,因为我们只采样了1+k个样本,所以只需要针对这1+k个分类器训练就可以。
直观理解训练原理:
通过上下文推断中心词。和skip-gram基本是相反的。
Pennington J, Socher R, Manning C D. Glove: Global vectors for word representation[C]//Proceedings of the 2014 conference on empirical methods in natural language processing (EMNLP). 2014: 1532-1543.
GloVe通过算法计算出单词之间的关联度,然后根据关联度进行embedding。
设 x i j = x c t = t a r g e t 出现在 c o n t e n t 附近的次数 x_{ij}=x_{ct}=target出现在content附近的次数 xij=xct=target出现在content附近的次数
如果窗口是对称的,比如左右5个单词的范围,那么很明显 x i j = x j i x_{ij}=x_{ji} xij=xji
训练算法: m i n ∑ i = 1 10000 ∑ j = 1 10000 ( θ i T e j − l o g X i j ) 2 min\sum_{i=1}^{10000}\sum_{j=1}^{10000}(\theta_i^Te_j-logX_{ij})^2 min∑i=110000∑j=110000(θiTej−logXij)2
训练的最终目的本质上还是soft-max,如果ij的关联大,则logX就大,要将算法训练到最小,那么 θ i T e j \theta_i^Te_j θiTej就要尽量大(匹配logX),思考一下soft-max里面的公式,这个就决定了该分类概率的大小。
换言之,这个模型和soft-max的本质一样,X越大,对应于soft-max中概率就越大。
现在有一个问题如果X=0,那么log是无限小的,所以需要调节一下,不要让结果太小,同时,有很多像the,of之类出现频率太高的词也不应该让结果太大,所以就要加一个系数
m i n ∑ i = 1 10000 ∑ j = 1 10000 f ( X i j ) ( θ i T e j − l o g X i j ) 2 min\sum_{i=1}^{10000}\sum_{j=1}^{10000}f(X_{ij})(\theta_i^Te_j-logX_{ij})^2 min∑i=110000∑j=110000f(Xij)(θiTej−logXij)2
当X=0,f(X)=0,其他情况根据算法具体而定,总之是一项启发性的东西。
最后增加的这两项,目前意义不明
m i n ∑ i = 1 10000 ∑ j = 1 10000 f ( X i j ) ( θ i T e j + b i + b j ′ − l o g X i j ) 2 min\sum_{i=1}^{10000}\sum_{j=1}^{10000}f(X_{ij})(\theta_i^Te_j+b_i+b'_j-logX_{ij})^2 min∑i=110000∑j=110000f(Xij)(θiTej+bi+bj′−logXij)2
最后的最后, e w f i n a l = e w + θ w 2 e_w^{final}=\dfrac{e_w+\theta_w}{2} ewfinal=2ew+θw,之所以采取平均,是因为这个和soft-max还是有不同,这里的 θ , e \theta,e θ,e起到的作用类似,有对称性,所以求平均。
这属于nlp的一个综合应用。
o n e − h o t → e m b e d d i n g s l a y e r → e → R N N l a y e r → s o f t − m a x l a y e r → r e s u l t one-hot\rightarrow embeddings \ layer \rightarrow e \rightarrow RNN \ layer \rightarrow soft-max \ layer \rightarrow result one−hot→embeddings layer→e→RNN layer→soft−max layer→result
embeddings的E矩阵从另一个地方来,总之是训练好的嵌入矩阵。
然后送进RNN模型,到达模型底部后,利用最后一个隐变量,进行soft-max分类,得到结果。
其实机器学习比较诚实,喂给什么,就只会什么,就一定会什么。
如果喂不好的东西,比如涉及到各种歧视的语句,那么输出就不太好,所以要除偏。
多对多模型是真正的应用阶段
Sutskever I, Vinyals O, Le Q V. Sequence to sequence learning with neural networks[J]. Advances in neural information processing systems, 2014, 27.
Cho K, Van Merriënboer B, Gulcehre C, et al. Learning phrase representations using RNN encoder-decoder for statistical machine translation[J]. arXiv preprint arXiv:1406.1078, 2014.
其实在前面RNN变体中已经说过了,就是encoder-decoder模型,在这里重申一下。
比如一个机器翻译任务,首先把原文输入到encoder,经过循环,最后一步输出一个隐变量a,用这个a作为decoder的第一个a,decoder的第一个x可以选0,此后每一层循环用的x,都直接用上一层循环的输出y,直到输出整句。
Mao J, Xu W, Yang Y, et al. Deep captioning with multimodal recurrent neural networks (m-rnn)[J]. arXiv preprint arXiv:1412.6632, 2014.
Vinyals O, Toshev A, Bengio S, et al. Show and tell: A neural image caption generator[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2015: 3156-3164.
Karpathy A, Fei-Fei L. Deep visual-semantic alignments for generating image descriptions[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2015: 3128-3137.
又比如图片解释任务,encoder不一定要从文本中提取,还可以从图片中提取,比如用AlexNet(去掉soft-max层)作为encoder,这样就可以得到一个长度为n的特征向量,把这个向量丢进decoder就可以得到输出。
实际上,Machine translation的encoder-decoder结构中的decoder,就是一个语言模型,且是一个一对多的序列生成语言模型。
抽象一点,就是条件语言模型。
但是问题在于,输出的是一系列soft-max向量,如何选择最佳的句子成为问题。
一种简单的思路就是每个词只取最大概率的,另一种简单的思路是直接按照概率进行采样。
但是这两种都不是很靠谱,第一种可能有误,第二种基于概率就更不靠谱了。
更大的问题是,你只有确定t-1位置的输出概率分布,才能确定t位置的输出概率分布,所以你想要直接得出概率最大的句子,不太容易。进一步说,搜索空间有 1000 0 T 10000^T 10000T这么大,根本搜不完,所以这里反而回归了最优化理论。
arg max y < 1 > , ⋯ , y < T > P ( y < 1 > , ⋯ , y < T > ∣ X ) \mathclap{\argmax_{y^{<1>},\cdots,y^{
比如,假设第一层有AB两个选项,第二层有CD两个选项,第一个词P(A)=0.6,P(B)=0.4,很多人就会选A,但是紧接着第一层选了A以后,P(C|A)=0.5,P(D|A)=0.5,P(C|B)=1,P(D|B)=0.
如果你想当然的选择了A,那么最终结果就是0.6*0.5=0.3,但是如果你先选了B,那么最终结果就可以是0.4*1=0.4,看起来吃亏结果反而概率还更大。
以上的选择思路叫贪心,每次选择最大概率的,这样的问题在于容易陷入局部最优,贪心AC不如不贪心的BC就说明了这种方法的缺陷。
首先确定搜索宽度Beam Width,这里以3举例。
对于 y < 1 > y^{<1>} y<1>,我们从中取三个概率最大的作为束的状态。
下面的符号,注意区分 y < t > 和 y ^ < t > y^{
此后,分别以这三个状态作为 y < 1 > y^{<1>} y<1>,分别去计算三个 y ^ < 2 > \hat{y}^{<2>} y^<2>,由此,这个就代表 P ( y < 2 > ∣ x , y < 1 > ) P(y^{<2>}|x,y^{<1>}) P(y<2>∣x,y<1>),进一步可以计算出 P ( y < 1 > , y < 2 > ∣ x ) = P ( y < 1 > ∣ x ) P ( y < 2 > ∣ x , y < 1 > ) P(y^{<1>},y^{<2>}|x)=P(y^{<1>}|x)P(y^{<2>}|x,y^{<1>}) P(y<1>,y<2>∣x)=P(y<1>∣x)P(y<2>∣x,y<1>),之后,选择 P ( y < 1 > , y < 2 > ∣ x ) P(y^{<1>},y^{<2>}|x) P(y<1>,y<2>∣x)最大的三个 y < 1 > , y < 2 > y^{<1>},y^{<2>} y<1>,y<2>组合作为新的束状态,继续进行递归的计算。
由此可见,这里的局部束搜索仍然和最优化理论中的局部束搜索一样,只不过选择最优束不是通过当前步概率,而是通过联合条件分布 P ( y < 1 > , y < 2 > ∣ x ) P(y^{<1>},y^{<2>}|x) P(y<1>,y<2>∣x)来选择。
局部束的开销并不大,束宽为n,则只需要同时维持n个RNN即可。
如果n=1,则局部束搜索退化成贪心搜索。
首先是概率累乘造成的数值下溢问题。
P ( y < 1 > , ⋯ , y < T > ∣ x ) = arg max y ∏ t = 1 T y P ( y < t > ∣ x , y < 1 > , ⋯ , y < t − 1 > ) P(y^{<1>}, \cdots,y^{
既然是比大小,那可以施加一个单调函数,这样也不会影响到最后结果,所以进行log处理,类似于对数最大似然的处理方式,可以将趋于0的值转化为负数之和,有效解决下溢
P ( y < 1 > , ⋯ , y < T > ∣ x ) = arg max y ∑ t = 1 T y log P ( y < t > ∣ x , y < 1 > , ⋯ , y < t − 1 > ) P(y^{<1>}, \cdots,y^{
前面加了单调函数相当于做了个等效变换,所以还是可以按照累乘分析。
这就引出另一个潜在问题,因为输出的长度不是固定的(直到有EOS才会停止,这也是递归的特征),而每一项概率都是小于0的,所以算法会倾向于选择更短的序列,因为少乘1项,结果肯定概率高。如果从对数角度理解,结果也是一样。
这个时候,只需要对长度进行一个修正即可,自然引出归一化。最简单的归一化就是平均,但是还应该考虑到,有时候简单的翻译确实更好,所以最好取个折中,可以继续叠参数,就是加一个指数 α \alpha α,如果指数为1,就是完全平均归一化,如果指数为0,就是完全不归一化,这个指数可以作为超参数调节。
P ( y < 1 > , ⋯ , y < T > ∣ x ) = arg max y 1 T y α ∑ t = 1 T y log P ( y < t > ∣ x , y < 1 > , ⋯ , y < t − 1 > ) P(y^{<1>}, \cdots,y^{
假设结果不太好,那么有两种可能:
如何以最小的成本定位这两个问题是一个新的问题,毕竟有的大模型跑一次就得几千块。
先针对一个错误样本做判断。
假设 y ∗ y^* y∗是人工结果(绝对正确), y ^ \hat{y} y^是输出的结果。首先计算 P ( y ∗ ∣ x ) , P ( y ^ ∣ x ) P(y^*|x),P(\hat{y}|x) P(y∗∣x),P(y^∣x),然后比较大小,生成两种情况。
P(y∗∣x)<P(y^∣x)
很显然,考虑到局部束搜索并不是遍历,存在运气因素,所以一个样本并不能决定整个模型的错误,我们需要找出所有错误样本,判断每个样本错在哪,最后给整个模型的错误定性,比如Beam Search出问题的比例是90%,那大概率就是Beam Search出bug了。
如果同时存在很好的翻译,那么该如何在这些翻译中选出最好的呢?
Bleu就是要解决这个问题,在我心目中,最好的翻译应当是信达雅,但是我不是搞这个领域的,就略过了Bleu了。
Bahdanau D, Cho K, Bengio Y. Neural machine translation by jointly learning to align and translate[J]. arXiv preprint arXiv:1409.0473, 2014.
前面说到的Bleu评分用于给翻译打分,但是Bleu的对太短与太长的句子表现都不好,尤其是超过20长度以后准确率会快速下降,这是因为一次性翻译长句子本身就很难。
现实中,人翻译长句子都是一截一截翻译的,有了这种机制,就可以保证翻译长句子时的准确率。
具体到架构,前面的encoder没有太多改变,主要是decoder时,增加了一个注意力矩阵。对每一个decoder输出,都要同时参考所有encoder的隐变量,参考的权重就是注意力权重,写作 α < t , t ′ > \alpha^{
更多的细节将会在后面解释。
Xu K, Ba J, Kiros R, et al. Show, attend and tell: Neural image caption generation with visual attention[C]//International conference on machine learning. PMLR, 2015: 2048-2057.
首先是encoder,实际使用中,encoder通常都是双向RNN,可能使用GRU和LSTM模型。
这样,每一个encoder位置有一正一反两个隐变量。两个隐变量构成这一步的特征向量,写作 a < t ′ > a^{
在decoder阶段,用 S < t > S^{
我对架构有两个不确定的疑问
现在的架构已经改变,encoder部分是双向RNN,只负责提供隐变量,这些隐变量由注意力矩阵进行采集,构成上下文变量c,供给给decoder部分作为输入,逐层输出。
接下来自上而下说明如何计算c
这就是全部算法,至于具体的维度细节,就没有细究了,这个算法的缺陷在于时间复杂度是 O ( T x , T y ) O(T_x,T_y) O(Tx,Ty),因为实际上是要构建一个注意力矩阵。好在句子一般不长,30个词顶天了,所以复杂度还可以容忍。
这个网络训练下来,会收获一个优秀的注意力权重,以及一个好的计算e的参数。
对输入信息选择性的加权,这种注意力思想可以放到各种领域中,比如图片相关,这也和人的视觉机制相似,人的眼睛视野很大,但是你只会注意直视部分,而不是余光。
至于可解释性,貌似已经有注意力机制可视化做出来了,感觉也不会很难,毕竟权重就摆在那里。
语音识别是seq2seq应用的另一个领域,视频识别也是类似。
同图片的卷积,文本的embeddings,声音也需要预处理:将波形图转化为声谱图(spectrogram),横轴是时间,纵轴是频率,某一个点的颜色代表某时间某频率的能量(响度)大小,实际上这种方式也是一种仿生处理。
我感觉,频率相当于embeddings的特征维度,那这个声谱图可以理解为类似embeddings的东西,变成声谱图以后,类似的发音就会有类似的特征向量。
现在的语音识别系统都是end-to-end的,不需要手工预处理数据,以前都是先手工把音频转化为phonemes(音位),比如quick转化为kwik,类似于提取音标。
在语音识别领域,输入的维度要远远大于输出维度,因为采样率如果是100,那一秒钟就有100个帧,但是你一秒钟可能就只说了一个字。
这个就很经典,和翻译一模一样,但是输出是26个英文字母(我感觉用词也可以)
这里可见注意力模型的厉害了,如果没有注意力模型,那么长的输入,效果估计不会太好。
Graves A, Fernández S, Gomez F, et al. Connectionist temporal classification: labelling unsegmented sequence data with recurrent neural networks[C]//Proceedings of the 23rd international conference on Machine learning. 2006: 369-376.
这个模型是n对n的等长模型。
比如一个输出可能是“ttt_h_eee___<空格>__qqq__u__ii___ccc_kkk”
对应的识别就是一个“the quick”,
原理在于,下划线是一种分隔符,用于分割连续重复的字母,这样就可以融合逐帧识别产生的冗余数据了。
小爱同学之类的设备,你要唤醒就得使用特定的词,这个词就叫触发词。
这是一个新型领域,所以并没有成熟算法。这里只有一个比较好的例子。
大致思路就是把输入扔进语音识别系统中,输出不是识别出来的语句,而是0和1,如果出现触发词(从头到尾说完一个词),就在结尾输出1,否则就是0.
细节没讲。