吴恩达CS230深度学习笔记(五)

2020-02-14

涉及 序列模型。

循环序列模型

RNN

one-hot式神经网络(输入为n个one-hot向量,输出为一个长度为vocabulary的one-hot向量)的不足:

  • 输入和输出数据在不同例子中可以有不同的长度,不是所有的例子都有着同样输入长度$T_{x}$或是同样输出长度的$T_{y}$。即使每个句子都有最大长度,也许你能够填充(pad)或零填充(zero pad)使每个输入语句都达到最大长度,但仍然看起来不是一个好的表达方式。
  • 像这样单纯的神经网络结构,它并不共享从文本的不同位置上学到的特征。不同位置上的相同字符会视为不同,缺乏对位置信息的捕捉。
循环神经网络是从左向右扫描数据,同时每个时间步的参数也是共享的,我们用$W_{\text{ax}}$来表示管理着从$x^{<1>}$到隐藏层的连接的一系列参数,每个时间步使用的都是相同的参数$W_{\text{ax}}$。而激活值也就是水平联系是由参数$W_{aa}$决定的,同时每一个时间步都使用相同的参数$W_{aa}$,同样的输出结果由$W_{\text{ya}}$决定。

在这个循环神经网络中,它的意思是在预测${\hat{y}}^{< 3 >}$时,不仅要使用$x^{<3>}$的信息,还要使用来自$x^{<1>}$和$x^{<2>}$的信息,因为来自$x^{<1>}$的信息可以通过这样的路径(上图编号1所示的路径)来帮助预测${\hat{y}}^{<3>}$。这个循环神经网络的一个缺点就是它只使用了这个序列中之前的信息来做出预测,没有使用序列中后部分的信息,尤其当预测${\hat{y}}^{<3>}$时,它没有用到$x^{<4>}$,$x^{<5>}$,$x^{<6>}$等等的信息。

循环神经网络用的激活函数经常是tanh,不过有时候也会用ReLU,但是tanh是更通常的选择。选用哪个激活函数是取决于你的输出$y$,如果它是一个二分问题,那么我猜你会用sigmoid函数作为激活函数,如果是$k$类别分类问题的话,那么可以选用softmax作为激活函数。

更一般的情况下,在$t$时刻,

$$\hat y^{< t >} = g_{2}(W_{{ya}}a^{< t >} + b_{y})$$

我们来分析一下前向传播的计算,现在你有一个输入序列,$x^{<1>}$,$x^{<2>}$,$x^{<3>}$一直到$x^{< T_{x} >}$,然后用$x^{<1>}$还有$a^{<0>}$计算出时间步1的激活项,再用$x^{<2>}$和$a^{<1>}$计算出$a^{<2>}$,然后计算$a^{<3>}$等等,一直到$a^{< T_{x} >}$。所有的这些激活项都要取决于参数$W_{a}$和$b_{a}$。

然后为了计算反向传播,你还需要一个损失函数。我们先定义一个元素损失函数,叫交叉熵损失函数(Cross Entropy Loss):

现在我们来定义整个序列的损失函数,将$L$定义为

$$L(\hat y,y) = \ \sum_{t = 1}^{T_{x}}{L^{< t >}(\hat y^{< t >},y^{< t >})}$$

RNN的一些变种:

  • “多对多”(many-to-many):输入$x^{<1>}$来计算$\hat y^{<1>}$,$\hat y^{<2>}$等等一直到$\hat y^{}$。输入和输出的长度可能不相同。
  • “多对一”(many-to-one):不再在每个时间上都有输出了,而是让这个RNN网络读入整个句子,然后在最后一个时间上得到输出。
  • “一对多”(one-to-many):只输入一个$x$,每个时间步都有输出。

本的RNN算法还有一个很大的问题,就是梯度消失的问题。一个数值主要与附近的输入有关,后面层的输出基本上很难受到序列靠前的输入的影响。这是因为不管输出是什么,不管是对的,还是错的,这个区域都很难反向传播到序列的前面部分,也因此网络很难调整序列前面的计算。梯度消失在训练RNN时是首要的问题,尽管梯度爆炸也是会出现,但是梯度爆炸很明显,因为指数级大的梯度会让你的参数变得极其大,以至于你的网络参数崩溃,你会看到很多NaN,或者不是数字的情况,这意味着你的网络计算出现了数值溢出。

语言模型

利用RNN实现语言模型,相当于第一步以$x^{<1>}$(全初始化为0)作为输入,然后计算$\hat y^{<1>}$,这一步其实就是通过一个softmax层来预测字典中的任意单词会是第一个词的概率;然后把$\hat y^{<1>}$当作第二步的输入$x^{<2>}$,计算$\hat y^{<2>}$,表示当第一个词是$\hat y^{<1>}$,去计算第二个词的概率…每次的计算都会考虑之前得到的所有词,以此类推。

现在有一个新句子,它是$y^{<1>}$,$y^{<2>}$,$y^{<3>}$,现在要计算出整个句子中各个单词的概率,方法就是第一个softmax层会告诉你$y^{<1>}$的概率,这也是第一个输出,然后第二个softmax层会告诉你在考虑$y^{<1>}$的情况下$y^{<2>}$的概率,然后第三个softmax层告诉你在考虑$y^{<1>}$和$y^{<2>}$的情况下$y^{<3>}$的概率,把这三个概率相乘,最后得到这个含3个词的整个句子的概率。

要用RNN训练一个语言模型,要做的第一件事就是将语料库中的句子标记化,建立一个字典,然后将每个单词都转换成对应的向量,也就是字典中的索引。

定义句子的结尾,一般的做法就是增加一个额外的标记,叫做EOS,它表示句子的结尾,这样能够帮助你搞清楚一个句子什么时候结束。

如果你遇到了一个不在你词表中的单词,答案就是创建一个新的标记,也就是一个叫做Unknow Word的伪造单词,用<UNK>作为标记,来表示不在词表中的单词。

如果你建立一个基于字符的语言模型,比起基于词汇的语言模型,你的序列$\hat y^{<1>}$,$\hat y^{<2>}$,$\hat y^{<3>}$在你的训练数据中将会是单独的字符,而不是单独的词汇。使用基于字符的语言模型有优点也有缺点,优点就是你不必担心会出现未知的标识(OOV单词),一个主要缺点就是你最后会得到太多太长的序列,所以基于字符的语言模型在捕捉句子中的依赖关系也就是句子较前部分如何影响较后部分不如基于词汇的语言模型那样可以捕捉长范围的关系,并且基于字符的语言模型训练起来计算成本比较高昂。

GRU 和 LSTM 和 BiRNN

LSTM反向传播计算:

门求偏导:

参数求偏导 :

为了计算$db_f, db_u, db_c, db_o$ 需要各自对$d\Gamma_f^{\langle t \rangle}, d\Gamma_u^{\langle t \rangle}, d\tilde c^{\langle t \rangle}, d\Gamma_o^{\langle t \rangle}$ 求和。

最后,计算隐藏状态、记忆状态和输入的偏导数:

GRU的优点是这是个更加简单的模型,所以更容易创建一个更大的网络,而且它只有两个门,在计算性上也运行得更快,然后它可以扩大模型的规模,更加容易适应规模更大的问题。但是LSTM更加强大和灵活,因为它有三个门而不是两个。如果你想选一个使用,我认为LSTM在历史进程上是个更优先的选择,所以如果你必须选一个,我感觉今天大部分的人还是会把LSTM作为默认的选择来尝试。

具体的讲解建议去《动手学深度学习》看,上边讲的很浅显易懂,这里就不赘述了。

自然语言处理与词嵌入

词嵌入

词嵌入在语言模型、机器翻译领域用的少一些,如果你从某一任务A迁移到某个任务B,只有A中有大量数据,而B中数据少时,迁移的过程才有用。所以对于很多NLP任务这些都是对的,而对于一些语言模型和机器翻译则不然。如何用词嵌入做迁移学习的步骤:

  • 第一步,先从大量的文本集中学习词嵌入。一个非常大的文本集,或者可以下载网上预训练好的词嵌入模型,网上你可以找到不少,词嵌入模型并且都有许可。
  • 第二步,你可以用这些词嵌入模型把它迁移到你的新的只有少量标注训练集的任务中,比如说用这个300维的词嵌入来表示你的单词。这样做的一个好处就是你可以用更低维度的特征向量代替原来的10000维的one-hot向量,现在你可以用一个300维更加紧凑的向量。尽管one-hot向量很快计算,而学到的用于词嵌入的300维的向量会更加紧凑。
  • 第三步,当你在你新的任务上训练模型时,在你的命名实体识别任务上,只有少量的标记数据集上,你可以自己选择要不要继续微调,用新的数据调整词嵌入。实际中,只有这个第二步中有很大的数据集你才会这样做,如果你标记的数据集不是很大,通常我不会在微调词嵌入上费力气。

Word2vec:CBOW是从原始语句推测目标字词;而Skip-Gram正好相反,是从目标字词推测出原始语句。CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。 (下图左边为CBOW,右边为Skip-Gram

负采样:刻意去生成一些负样本。

Glove:更简单的词嵌入方法。

词嵌入除偏:词嵌入本身可能具有一些如性别歧视、种族歧视的偏好。可采用作差取平均、中和步、均衡步等步骤。没碰到过,不仔细看了。

《动手学深度学习》里面讲过了,不再赘述。

序列模型和注意力机制

重点讲注意力机制,Seq2Seq、集束搜索等,参见《动手学深度学习》。

注意力机制

注意力模型或者说注意力这种思想(The attention algorithm, the attention idea)已经是深度学习中最重要的思想之一。

像这样给定一个很长的法语句子,在你的神经网络中,这个绿色的编码器要做的就是读整个句子,然后记忆整个句子,再在感知机中传递,而对于这个紫色的神经网络,即解码网络(the decoder network)将生成英文翻译。人工翻译并不会通过读整个法语句子,再记忆里面的东西,然后从零开始,机械式地翻译成一个英语句子。而人工翻译,首先会做的可能是先翻译出句子的部分,再看下一部分,并翻译这一部分。看一部分,翻译一部分,一直这样下去。你会通过句子,一点一点地翻译,因为记忆整个句子是非常困难的。注意力模型让一个神经网络只注意到一部分的输入句子。当它在生成句子的时候,更像人类翻译。

相当于对于$t$时刻的输入$x_t$,要额外地学一个向量$a^{},a^{}…a^{}$,每个$a^{}$都是一个注意力权重,表示当你生成第$t$个词时你应该放多少注意力在第$i$个单词上。所有的$a^{}$应该最终过一个softmax来确保它们的和为1。这里的t和i可以同时是encoder里的,表示编码时候的注意力;也可以是t代表decoder的i代表encoder的,表示在解码第t个单词时,需要放多多少注意力在编码的第i个单词上。很多个$a^t$结合起来,就最终形成了注意力矩阵$A$。

如何计算这些$e$项,一种方式是用小的神经网络去学习。$s^{t-1}$是神经网络在上个时间步的隐藏状态,$a^{t’}$是上个时间步的的特征。直观来讲就是,如果你想要决定要花多少注意力在$t’$的激活值上。然后用这个小网络去拟合$s^{t-1}$和$a^{t’}$到$e^{t,t’}$的计算函数,从而再计算$a^{<t,t’>}$。

这个算法的一个缺点就是它要花费三次方的时间,就是说这个算法的复杂是$O(n3)$的,如果你有$T_x$个输入单词和$T_y$个输出单词,于是注意力参数的总数就会是$T_x\times T_y$,所以这个算法有着三次方的消耗。但是在机器翻译的应用上,输入和输出的句子一般不会太长,可能三次方的消耗是可以接受。

这门课Attention讲的也只是最基础的概念,具体的学习还需要后续自己继续深入了解。

【原文出自黄海广博士 deeplearning_ai_books

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者,更多文章请访问想飞的小菜鸡