对于一个文本中出现的单词 \(w_i\) 的几率,他更多的依靠的是前 \(n\) 个单词,而不是这句话中前面全部的单词。
\[ P\left(w_{1}, \ldots, w_{m}\right)=\prod_{i=1}^{i=m} P\left(w_{i} | w_{1}, \ldots, w_{i-1}\right) \approx \prod_{i=1}^{i=m} P\left(w_{i} | w_{i-n}, \ldots, w_{i-1}\right) \]
在翻译系统中就是对于输入的短语,经过对全部的输出的语句进行评分,获得几率最大的那个输出,做为预测的几率。算法
对于N-Gram模型,首先要知道其中的该模型中的 count的意思,count 能够用来表示单词出现的频率,这个模型与条件几率密切相关,其中,
\[ \begin{aligned} p\left(w_{2} | w_{1}\right) &=\frac{\operatorname{count}\left(w_{1}, w_{2}\right)}{\operatorname{count}\left(w_{1}\right)} \\ p\left(w_{3} | w_{1}, w_{2}\right) &=\frac{\operatorname{count}\left(w_{1}, w_{2}, w_{3}\right)}{\operatorname{count}\left(w_{1}, w_{2}\right)} \end{aligned} \]
对于上面的式子的解释就是,咱们将 连续单词出现的频率做为几率,而后经过条件几率的形式预测出下一个单词。这个模型面临的问题是,选取多大的框,也就是选取前面多少个单词,这里面还牵涉到稀疏问题,没必要要的信息就不存储,同时还要存储必要信息。网络
对于上面的模型须要考虑一些问题,首先是,分母分子为零的app
传统的模型能够简化为下面的图片中的样式:函数
蓝色的一层是对输入的处理,获取单词向量:\(\boldsymbol{e}=\left[\boldsymbol{e}^{(1)} ; \boldsymbol{e}^{(2)} ; \boldsymbol{e}^{(3)} ; \boldsymbol{e}^{(4)}\right]\)。而后红色就是中间的隐含层,\(h=f\left(\boldsymbol{W} \boldsymbol{e}+\boldsymbol{b}_{1}\right)\),最后加一个 \(Softmax\) 层,就是分类的意思,\(\hat{y}=\operatorname{softmax}\left(U h+b_{2}\right)\)。优化
传统的 \(RNN\) 以下图所示,是一个比较简单的结构,咱们能够用两个式子来表示:spa
对于每一层的输入,像下面这个式子,其中激活函数通常会使用 \(tanh()\), 也可使用 \(sigmoid\),下面的两个矩阵 \(W^{(hh)}\) 和矩阵 \(W^{(hx)}\) 维度不一样,由于本质都是线性的,因此维度不一样没有关系。
\[ h_{t}=\sigma\left(W^{(h h)} h_{t-1}+W^{(h x)} x_{[t]}\right) \]
而后先经过一个矩阵 \(W^{(S)}\) 而后经过一个 \(Softmax\) 函数就能够了,
\[ \hat{y}_{t}=\operatorname{softmax}\left(W^{(S)} h_{t}\right) \]
对于 \(softmax\) 函数,咱们还要知道,\(\hat{y}_{t}\) 是最终预测的得分,而咱们 \(RNN\) 传递的是 \(h_t\)。其中\(W^{(S)} \in \mathbb{R}^{|V| \times D_{h}}\) and \(\hat{y} \in \mathbb{R}^{|V|}\)。翻译
上图就是对于一个句子的翻译,能够看出传统方法,与 RNN的区别。3d
咱们一般用交叉熵损失函数来表示错误率,交叉熵损失函数就是统计预测正确的原本正确的几率,而后取反做为目标函数,一般还会取一个对数,
\[ J^{(t)}(\theta)=-\sum_{j=1}^{|V|} y_{t, j} \times \log \left(\hat{y}_{t, j}\right) \]
若是一个语料库的大小为 \(T\),那么交叉熵损失函数就是应用于 大小为 \(T\) 的每个单词:
\[ J=\frac{1}{T} \sum_{t=1}^{T} J^{(t)}(\theta)=-\frac{1}{T} \sum_{t=1}^{T} \sum_{j=1}^{|V|} y_{t, j} \times \log \left(\hat{y}_{t, j}\right) \]
RNN还有一个概念叫作困惑,所谓困惑,定义以下:
\[ Perplexity =2^{J} \]code
使用 RNN的时的一些问题,blog
举个例子,对于两个句子:
"Jane walked into the room. John walked in too. Jane said hi to ___"
"Jane walked into the room. John walked in too. It was late in the day, and everyone was walking home after a long day at work. Jane said hi to ___"
使用RNN预测空格里面的单词,第一个句子预测正确的几率要更大一些。
下面从数学的角度解释梯度消失问题。
就像传统神经网络反向传播的时候同样,咱们要对参数矩阵求导,以此得到最佳的参数。而在 RNN中,咱们须要将每一次的损失加起来,也就是下面的式子:
\[ \frac{\partial E}{\partial W}=\sum_{t=1}^{T} \frac{\partial E_{t}}{\partial W} \]
对于每个时间点 \(t\),咱们使用链式规则,
\[ \frac{\partial E_{t}}{\partial W}=\sum_{k=1}^{t} \frac{\partial E_{t}}{\partial y_{t}} \frac{\partial y_{t}}{\partial h_{t}} \frac{\partial h_{t}}{\partial h_{k}} \frac{\partial h_{k}}{\partial W} \]
注意对于时间点 t, 咱们要考虑从起始点一直到时间点 t,这是由于 RNN是链式的,而不像传统的神经网络不是链式的,至关于每一步都要进行一次优化矩阵 W,因此计算 \(d h_{t} / d h_{k}\) 能够用下面的方法:
\[ \frac{\partial h_{t}}{\partial h_{k}}=\prod_{j=k+1}^{t} \frac{\partial h_{j}}{\partial h_{j-1}}=\prod_{j=k+1}^{t} W^{T} \times \operatorname{diag}\left[f^{\prime}\left(h_{j-1}\right)\right] \]
因此链式规则等价于下面的式子:
\[ \frac{\partial E}{\partial W}=\sum_{t=1}^{T} \sum_{k=1}^{t} \frac{\partial E_{t}}{\partial y_{t}} \frac{\partial y_{t}}{\partial h_{t}}\left(\prod_{j=k+1}^{t} \frac{\partial h_{j}}{\partial h_{j-1}}\right) \frac{\partial h_{k}}{\partial W} \]
上周讲到神经网络中的梯度降低的时候,对矩阵的链式求导,咱们讲到了雅可比矩阵,这里就用雅可比矩阵。
\[ \frac{\partial h_{j}}{\partial h_{j-1}}=\left[\frac{\partial h_{j}}{\partial h_{j-1,1}} \dots \frac{\partial h_{j}}{\partial h_{j-1, D_{n}}}\right]=\left[ \begin{array}{ccc}{\frac{\partial h_{j, 1}}{\partial h_{j-1,1}}} & {\cdots} & {\frac{\partial h_{j, 1}}{\partial h_{j-1, D_{n}}}} \\ {\vdots} & {\ddots} & {\vdots} \\ {\frac{\partial h_{j, D_{n}}}{\partial h_{j-1,1}}} & {\cdots} & {\frac{\partial h_{j, D_{n}}}{\partial h_{j-1, D_{n}}}}\end{array}\right] \]
上面的式子很重要,由于要计算 \(h_j\) 与 \(h_{j-1}\)之间的关系,\(h_{t}=\sigma\left(W^{(h h)} h_{t-1}+W^{(h x)} x_{[t]}\right)\)。对这个函数中 \(h_{j-1}\) 求偏导。根据求导的链式法则
\[ \frac{\partial h_{j}}{\partial h_{j-1}} = W^{T} \times \operatorname{diag}\left[f^{\prime}\left(h_{j-1}\right)\right] \]
咱们用 \(\beta_{W} ,\beta_{h}\)分别表示两个行列式的上确界,而对于上面的式子,咱们有:
\[ \left\|\frac{\partial h_{j}}{\partial h_{j-1}}\right\| \leq\left\|W^{T}\right\|\left\|\operatorname{diag}\left[f^{\prime}\left(h_{j-1}\right)\right]\right\| \leq \beta_{W} \beta_{h} \]
所以用于链式法则就是:
\[ \left\|\frac{\partial h_{t}}{\partial h_{k}}\right\|=\left\|\prod_{j=k+1}^{t} \frac{\partial h_{j}}{\partial h_{j-1}}\right\| \leq\left(\beta_{W} \beta_{h}\right)^{t-k} \]
咱们将最初的式子替换一下,就是下面这样:
\[ \frac{\partial E_{t}}{\partial W}=\sum_{k=1}^{t} \frac{\partial E_{t}}{\partial y_{t}} \frac{\partial y_{t}}{\partial h_{t}} \left(\beta_{W} \beta_{h}\right)^{t-k} \frac{\partial h_{k}}{\partial W} \]
显然这里有指数的问题,因此问题就与直接与 \(\beta_{W} ,\beta_{h}\)相关了。因此梯度消失的问题就是 \(\beta_{W} \beta_{h}\) 与 1 的大小关系的问题了。当 \(\beta_{W} \beta_{h}\) 大于 1的时候咱们成为梯度爆炸,接近 0 的时候,咱们称为梯度消失。
处理梯度上升的一个简单的策略就是设置阈值:
\[ \begin{array}{c}{\hat{g} \leftarrow \frac{\partial E}{\partial W}} \\ {\text { if }\|\hat{g}\| \geq \text { threshold then }} \\ {\hat{g} \leftarrow \frac{\text {threshold}}{\|\hat{g}\|} \hat{g}} \\ {\text { end if }}\end{array} \]
为了解决梯度消失问题,能够采用两种方法,分别是初始化矩阵 \(W^{(h h)}\),而不是随机取这个矩阵。另外一种方法是,激活函数使用 \(ReLU\) 而不是\(sigmod\) 函数,由于 ReLU 函数的导数要么是 0,要么是 1。
双向 RNN,顾名思义就是有两个方向相反的 RNN,若是未知的是中间位置的单词,咱们也能够反过来预测,这就是反向 RNN的思想。就如同下面的公式所说的:
\[ \vec{h}_{t}=f\left(\vec{W} x_{t}+\vec{V} \vec{h}_{t-1}+\vec{b}\right) \]
\[ \stackrel{\leftarrow}{h}_{t}=f\left(\stackrel\leftarrow{W} x_{t}+\stackrel{\leftarrow}{V} \stackrel{\leftarrow}h_{t+1}+\stackrel{\leftarrow}{b}\right) \]
\[ \hat{y}_{t}=g\left(U h_{t}+c\right)=g\left(U\left[\stackrel{\rightarrow}{h}_{t} ; \stackrel{\leftarrow}{h}_{t}\right]+c\right) \]
上面右图是多层 RNN 的模型,对于 \(h_t^{(i)}\),既与前一层 t 时刻的神经元 \(h_t^{(i-1)}\) 有关,还和 \(h_{t-1}^{(i)}\) 这一层前一个时刻的神经元有关,也就是每个时间步长,不只会纵向传播(RNN的序列传播),还会横向传播,全部的层,并行的向前传播),用公式表示就是:
\[ \vec{h}_{t}^{(i)}=f\left(\vec{W}^{(i)} h_{t}^{(i-1)}+\vec{V}^{(i)} \vec{h}_{t-1}^{(i)}+\vec{b}^{(i)}\right) \]
\[ \stackrel{\leftarrow}{h}_{t}^{(i)}=f\left(\stackrel{\leftarrow}{W}^{(i)} h_{t}^{(i-1)}+\stackrel{\leftarrow}{V}^{(i)} \stackrel{\leftarrow}{h}_{t-1}^{(i)}+\stackrel{\leftarrow}{b}^{(i)}\right) \]
\[ \hat{y}_{t}=g\left(U h_{t}+c\right)=g\left(U\left[\vec{h}_{t}^{(L)} ; \stackrel{\leftarrow}{h}_{t}^{(L)}\right]+c\right) \]
咱们使用 RNN来完成翻译,首先是 encoder,前面咱们讲过神经依赖解析算法,若是咱们用 RNN实现这一步,那就是这里的encoder了,这一步主要是讲源语句转化为 dense的单词向量。下面左图中的,前三层神经网络就是encoder的过程,而后最后两层就是将向量转换为另外一种语言,也就是decoder的过程,其实decoder真正作的是,将向量转为另外一种语言表示的向量。
下面的等式:
\[ h_{t}=\phi\left(h_{t-1}, x_{t}\right)=f\left(W^{(h h)} h_{t-1}+W^{(h x)} x_{t}\right) \]
表示的是encoder的过程。在decoder阶段,
\[ h_{t}=\phi\left(h_{t-1}\right)=f\left(W^{(h h)} h_{t-1}\right) \]
\[ y_{t}=\operatorname{softmax}\left(W^{(S)} h_{t}\right) \]
对于上面的模型,咱们可使用交叉熵损失函数做为目标函数:
\[ \max _{\theta} \frac{1}{N} \sum_{n=1}^{N} \log p_{\theta}\left(y^{(n)} | x^{(n)}\right) \]
对于 decoder阶段的隐层状态能够有三种不一样的输入,分别是:
因此咱们能够考虑结合这三个输出,也就获得下面的模型:
\[ h_{t}=\phi\left(h_{t-1}, c, y_{t-1}\right) \]
这个顺带提到,在谷歌提出的 sequence to sequence中,能够考虑将输入单词反转来提升翻译的准确率。
咱们先看下 GRU直观的解释。
\[ \tilde{h}_{t}=\tanh \left(r_{t} \circ U h_{t-1}+W x_{t}\right) \]
一个新的内存状态表示,对于一个新输入的单词,考虑过去的状态,既根据语境结合新的单词与前面上下文的语境。好比咱们读到句子中的一个绝不相关的单词,那么就不考虑这个单词的效益。
\[ r_{t}=\sigma\left(W^{(r)} x_{t}+U^{(r)} h_{t-1}\right) \]
能够看做是一个通过激活函数的门,来判断 \(h_{t-1}\) 对 \(h_t\) 的影响,判断是否能够彻底忽略 \(h_{t-1}\) 若是 \(h_{t-1}\) 与产生新内存无关。好比咱们进入一个彻底新的句子,在长语句中进入一个彻底新的句子,就能够不考虑 \(h_{t-1}\)。
\[ z_{t}=\sigma\left(W^{(z)} x_{t}+U^{(z)} h_{t-1}\right) \]
这也是一个门,用来判断更新的时候的取值,从上面的图中能够打看到, \(z_t\) 是在 \(\tilde{h}_{t}\) 与 \(h_{(\mathrm{t}-1)}\) 之间的权衡的。咱们能够这么说,当 \(z_t\) \(\approx 1\) 的时候,\(h_{t-1}\) 这一层几乎所有复制给 \(h_t\),而当 \(z_t\) $\approx 0 $ 的时候,咱们更多的将 \(\tilde{h}_{t}\) 传到下一个状态。
\[ h_{t}=\left(1-z_{t}\right) \circ \tilde{h}_{t}+z_{t} \circ h_{t-1} \]
隐含层在计算的时候,是考虑到对 \(\tilde{h}_{t}\) 与 \(h_{(\mathrm{t}-1)}\) 之间的权衡取舍,这也是 GRU的核心之一。GRU的核心就是,首先判断新来的单词与上下文之间的关系,须要联合语句构造新的语境。
LSTM以前有所接触,感受理解的不够深入,比起 GRU,门明显变多了,可是本质差不了太多,先看下直观解释:
\[ \tilde{c}_{t}=\tanh \left(W^{(c)} x_{t}+U^{(c)} h_{t-1}\right) \]
这一步与 GRU相似。
\[ i_{t}=\sigma\left(W^{(i)} x_{t}+U^{(i)} h_{t-1}\right) \]
判断新的单词是否值得做为参数,和 GRU同样。经过与上下文的结合,判断这个输入,有多大的权重做为新的特征。
\[ f_{t}=\sigma\left(W^{(f)} x_{t}+U^{(f)} h_{t-1}\right) \]
忘记层,与 Input Gate 相似,可是这里是判断是否忘记,也就是判断是否忘记前面所记录的信息,咱们能够理解为特征。
\[ c_{t}=f_{t} \circ c_{t-1}+i_{t} \circ \tilde{c}_{t} \]
这一层就是根据前面的几个门,信息留下的权重,新的信息考虑进去的权重。
\[ o_{t}=\sigma\left(W^{(o)} x_{t}+U^{(o)} h_{t-1}\right) \]
\[ h_{t}=o_{t} \circ \tanh \left(c_{t}\right) \]
这里的两个函数的目的是将 \(h_t\) 与 \(C_t\) 分开,由于 \(C_t\) 中存储了不少没必要要的信息。由于隐含层做为每个门的参数,因此这里须要考虑哪些信息留在隐含层。因此使用了一个门 \(O_t\)。