Andrew Ng深度学习课程笔记阅读记录(5.1):序列模型
1.NLP中怎么表示一个句子中单个的词?做一个词典(遍历一遍训练集,找到前多少个常用词),one-hot表示这个词典中的每一个单词,如果遇到一个不在词典中的单词,就创建一个<UNK>标记。
2.如果使用标准神经网络做NLP问题,可能遇到的问题有:①输入数据和输出数据不一定有同样的长度,即使你可以通过pad让每个输入语句都达到最大长,但这不是一个好的表示方法。②这样的一个网络不能共享从文本的不同位置学到的特征。于是引入RNN。
3.循环神经网络RNN
在每一个time-step,循环神经网络传递一个激活值到下一个time-step中用于计算。
其中,Wax中的下标a表示计算与a的输出相关的,下标x表示乘了一个与输入x相关的。
隐藏层的每个time-step用的激活函数经常是tanh,有时候也用Relu,y输出时选择的激活函数取决于要解决的问题,二分类用sigmoid,多分类用softmax。我们定义隐藏层0时刻的状态为一个零向量,然后如图所示从左到右完成前向传播。我们把表示用的向量堆起来,使用以下的方式来简化这个表示:
Backpropagation through time(BPTT)
为了计算反向传播,我们需要定义一个损失函数,使用交叉熵损失函数:
上式是关于某个time-step上某个单词的预测值的损失函数,整个序列的损失函数为:
反向传播示意图:
image.png
4.不同类型的RNN
5.语言模型
也就是表示某个特定句子出现的概率是多大
怎么建立?
首先需要有一个语料库,然后Tokenize,建立词典,将每个单词使用one-hot表示(也就是建立单词到索引的映射关系),此外可能还需要定义句子的结尾,一般增加一个EOS标记,未出现在词典中的词使用UNK表示。
假设我们现在想要解决这样一个问题:我们想要训练一个RNN预测“Cats average 15 hours of sleep a day.”第一步,使用零向量对输出进行预测,第二步,通过前面的输入,逐步预测后面的单词出现的概率。训练网络,使用交叉熵计算损失函数,对网络进行参数更新。
6.新序列采样
在训练一个序列模型之后,想要了解到这个模型学到了什么,一种非正式的方法就是进行一次序列采样。
在上面的问题中,我们模拟产生特定单词序列的概率,第一步,输入一个零向量x<1>=0,a<1>=0,产生的所有输出是一个经过softmax的概率,我们队这个softmax分布进行随即采样(可以使用np.random.choice),把这个采样作为下一个time-step的输入,让RNN预测下一个输出。
除了基于词汇的语言模型,我们也可以使用基于字符的语言模型,但基于字符的语言模型一个主要的缺点就是我们最后会得到太多太长的输出序列,其对于捕捉句子前后依赖关系,也就是句子前部分如何影响后面部分,不如基于词汇的语言模型那样效果好;同时基于字符的语言模型训练代价比较高。所以目前的趋势和常见的均是基于词汇的语言模型。
7.梯度消失
当句子较长时,输出y得到的梯度很难通过BPTT反向传播回去,这样导致很难会对前几层的权重有影响。梯度消失问题比较难解决,而梯度爆炸问题可以通过梯度修剪解决,梯度修剪就是观察梯度向量,如果大于某个阈值就缩放梯度向量使其不会过大。
8.GRU
前面的RNN可以用这个图表示:
GRU单元有一个新的变量叫做记忆细胞(cell),在时间t,有记忆细胞c{<t>},实际上这里的c{<t>}就等于我们之前的a{<t>}。每个time-step,我们用一个候选值来代替原本的记忆细胞c{<t>}
完整的GRU:在上面式子的基础上给记忆细胞的候选值加了一个门,可以任务是代表下一个c{<t>}的候选值和c{<t-1>}的相关性。于是一个完整的GRU有两个门,一个是更新门,一个是相关门。
9.LSTM
在LSTM中不再有a{<t>}=c{<t>}。LSTM的新特性是不止有一个更新门控制c^{<t>},见下图:
并且多了一个输出门。
LSTM的前向传播:
Peephole connection的意思是门的值不仅取决于a{<t-1>}和x{<t>},也取决于上一个记忆细胞c^{<t-1>}
10.深层循环神经网络(deep RNNs)
传统的神经网络中我们可能会叠加许多层,但对于RNN来说3层就已经不少了。常见的一种网络是把最后一层RNN的的输出去掉,换成一个水平无连接的深层网络