序言

1. 内容介绍

  本章介绍深度学习算法-循环神经网络,主要介绍循环神经网络的常见变种,包括 递归神经网络双向循环神经网络 以及 深度循环神经网络

2. 理论目标

  • Recursive 语法解析树
  • Recursive NN 传播与参数更新
  • BiRNN 模型结构
  • BiRNN 传播的数学推导
  • DRNN 设计理念
  • DRNN 的模型结构与参数更新

3. 实践目标

  • 掌握 Recursive 语法解析树
  • 掌握 Recursive NN 传播与参数更新
  • 掌握 BiRNN 模型结构
  • 掌握 BiRNN 传播的数学推导
  • 掌握 DRNN 设计理念
  • 掌握 DRNN 的模型结构与参数更新

4. 内容目录

  • 1.递归神经网络
  • 2.双向循环神经网络
  • 3.深度循环神经网络

第1节 递归神经网络

  递归神经网络 (Recursive Neural Network) 由 Pollack 于 1990 年引入,而 Bottou 在 2011 年描述了这类网络代表循环网络的潜在用途 学习推理

神经网络的输入层单元个数是固定的,因此必须用循环或者递归的方式来处理长度可变的输入,递归神经网络是代表循环网络的另一种扩展,它被构建为深的 树状结构 而不是 RNN 的链状结构,因为是不同类型的计算图。

  与循环网络相比,递归网络的明显优势是

  • 对于具有相同长度 \tauτ 的序列,深度可以急剧从 \tauτ 减小为 \theta(\log\tau)θ(logτ), 可以有效地解决长期依赖的问题
  • 对于含有不同歧义的输入数据,递归网络不再采用序列而是按照树/图结构处理信息,输出不同的 语法解析树 则对应不同的意思

  不过同样因为递归神经网络的输入是树/图结构,而这种结构需要花费很多人工去标注,导致其在行业应用中并不流行

1.1 递归网络语法解析树

  因为神经网络的输入层单元个数是固定的,因此必须用 循环 或者 递归 的方式来处理 长度可变 的输入。循环神经网络实现了前者,通过将长度不定的输入分割为等长度的小块,然后再依次的输入到网络中,从而实现了神经网络对变长输入的处理。例如处理一句话的输入时,可以将其看作是不同词依照时间顺序组成的序列,然后每次向循环神经网络输入一个词,如此循环直至整句话输入完毕,循环神经网络将产生对应的输出,依此就能处理任意长度的输入

  

  然而,有时候把句子看做是词的序列是不够的,比如这句话 『两个外语学院的学生』,可以看出这句话有明显歧义

  • 『两个外语学院的/学生』,学生可能有许多,但他们来自于两所外语学校
  • 『两个/外语学院的学生』,也就是只有两个学生,他们是外语学院的

  为了使模型区分出两个不同的意思,递归网络必须能够按照 图/树结构 去处理信息,而不是序列,即通过两个不同的语法解析树则区别不同的语义

  

上例显示了自然语言可组合的性质,即词可以组成句、句可以组成段落、段落可以组成篇章,而更高层的语义取决于底层的语义以及不同组合方式

  递归神经网络是一种 表示学习,它可以将词、句、段、篇按照他们的语义映射到同一个向量空间中,也就是把可组合图/数结构的信息表示为一个个有意义的向量,并以此为基础去完成更高级的任务,比如递归神经网络在做情感分析时,可以比较好的处理否定句

  

蓝色表示正面评价,白色是中性评价,红色表示负面评价

每个节点是一个向量,这个向量表达了以它为根的子树的情感评价

比如 intelligent humor 是正面评价,而 care about cleverness wit or any other kind of intelligent humor 是中性评价

模型能够正确的处理 doesn’t 的含义,将正面评价转变为负面评价

  尽管递归神经网络具有更为强大的表示能力,但是在实际应用中并不太流行。其中一个主要原因是,递归神经网络的图/树结构需要花费很多人工去标注

循环神经网络处理句子,可以直接把句子作为输入。然而,递归神经网络处理句子,就必须把每个句子标注为语法解析树的形式,这无疑要花费非常大的精力。很多时候,相对于递归神经网络能够带来的性能提升,这个投入是不太划算的

1.2 递归网络前向传播

  递归神经网络的输入是两个子节点,输出是将这两个子节点编码后产生的父节点,父节点的维度和每个子节点是相同的

  

C_1,C_2C1​,C2​ 分别是表示两个子节点的向量,PP 是表示父节点的向量

子节点和父节点组成一个 全连接神经网络,也就是子节点的每个神经元都和父节点的每个神经元两两相连

  矩阵 WW 表示这些连接上的权重,维度为 d \times 2dd×2d,其中,dd 表示每个节点的维度, 则父节点的计算公式可以写成

\qquad\qquad p = \tanh(W{C_1 \brack C_2} + b)p=tanh(W[C2​C1​​]+b)

其中 \tanhtanh 是激活函数,bb 是偏置项,也是一个维度为 dd 的向量

  将产生的父节点的向量和其他子节点的向量再次作为网络的输入,再次产生它们的父节点。如此递归下去,直至整棵树处理完毕。最终将得到 根节点 (Root) 的向量,可以认为它是对整棵树的表示,这样就实现了把树映射为一个向量

  

1.3 递归网络反向传播

  递归神经网络的反向传播算法 Back Propagtion Through Structure (BPTS) 和循环神经网络 BPTT 算法类似,两者不同之处在于,前者需要将残差 \deltaδ 从根节点反向传播到各个子节点,而后者是将残差 \deltaδ 从当前时刻 t^ktk 反向传播到初始时刻 t^1t1

  设 \mathbf{net}_pnetp​ 是父节点的加权输入,则有

\qquad\qquad\mathbf{net}_p = W {C_1 \brack C_2} + bnetp​=W[C2​C1​​]+b

  定义 \delta_pδp​ 为误差函数 EE 相对于父节点 PP 的加权输入 \mathbf{net}_pnetp​ 的导数,则有

\qquad\qquad\delta_p \stackrel{def}{=} \dfrac {\partial E}{\partial \mathbf{net}_p}δp​=def∂netp​∂E​

  因篇幅限制,在此不列举各项偏函数矩阵转换的过程,其梯度简化式为

\qquad\qquad\begin{cases}\dfrac{\partial E}{\partial W} = \sum\limits^{}_l\dfrac{\partial E}{\partial W^{(l)}}\\\dfrac{\partial E}{\partial \bf{b}} = \sum\limits^{}_l\dfrac{\partial E}{\partial {\bf{b}}^{(l)}}\\\end{cases}\qquad\qquad⎩⎪⎪⎪⎨⎪⎪⎪⎧​∂W∂E​=l∑​∂W(l)∂E​∂b∂E​=l∑​∂b(l)∂E​​ 其中 \dfrac{\partial E}{\partial W^{(l)}} = \begin{bmatrix}\dfrac{\partial E}{\partial w^{(l)}_{1,1}} & \dots & \dfrac{\partial E}{\partial w^{(1,m)}}\\\vdots & \ddots & \vdots\\\dfrac{\partial E}{\partial w^{(n,1)}} & \dots &\dfrac{\partial E}{\partial w^{(n,m)}}\\\end{bmatrix} = \delta^{(l)}({\bf{c}}^{(l)})^T, \qquad \dfrac{\partial E}{\partial {\bf{b}}^{(l)}} = \begin{bmatrix} \dfrac{\partial E}{\partial {\bf{b}}^{(l)}_1}\\\vdots\\\dfrac{\partial E}{\partial {\bf{b}}^{(l)}_n}\end{bmatrix} = \delta_p^{(l)}∂W(l)∂E​=⎣⎢⎢⎢⎢⎢⎢⎡​∂w1,1(l)​∂E​⋮∂w(n,1)∂E​​…⋱…​∂w(1,m)∂E​⋮∂w(n,m)∂E​​⎦⎥⎥⎥⎥⎥⎥⎤​=δ(l)(c(l))T,∂b(l)∂E​=⎣⎢⎢⎢⎢⎢⎢⎡​∂b1(l)​∂E​⋮∂bn(l)​∂E​​⎦⎥⎥⎥⎥⎥⎥⎤​=δp(l)​

  则其权重更新公式为

\qquad\qquad\begin{cases} W \gets W + \eta\dfrac{\partial E}{\partial W}\\{\bf{b}} \gets {\bf{b}} + \eta\dfrac{\partial E}{\partial {\bf{b}}}\end{cases}\qquad\qquad⎩⎪⎪⎨⎪⎪⎧​W←W+η∂W∂E​b←b+η∂b∂E​​ 其中 \etaη 是学习速率常数

1.4 PyTorch 代码复现

# %load recursivenn.py import torch import torch.nn as nn import torch.nn.functional as F class RecursiveNN(nn.Module): def __init__(self, vocabSize, embedSize=100, numClasses=5): super(RecursiveNN, self).__init__() self.embedding = nn.Embedding(int(vocabSize), embedSize) self.W = nn.Linear(2*embedSize, embedSize, bias=True) self.projection = nn.Linear(embedSize, numClasses, bias=True) self.activation = F.relu self.nodeProbList = [] self.labelList = [] def traverse(self, node): if node.isLeaf(): currentNode = self.activation(self.embedding(torch.LongTensor([node.getLeafWord()]))) else: currentNode = self.activation(self.W(torch.cat((self.traverse(node.left()),self.traverse(node.right())),1))) self.nodeProbList.append(self.projection(currentNode)) self.labelList.append(torch.LongTensor([node.label()])) return currentNode def forward(self, x): self.nodeProbList = [] self.labelList = [] self.traverse(x) self.labelList = torch.cat(self.labelList) return torch.cat(self.nodeProbList)


第2节 双向循环神经网络

  第 06 章介绍的 RNN 网络隐含了一个假设,即时刻 tt 的状态只能由过去的输入序列 \mathcal{S} = \lbrace \vec{x}^{(1)}, \vec{x}^{(2)}, \dots, \vec{x}^{(t-1)}\rbraceS={x(1),x(2),…,x(t−1)},以及当前的输入 \vec{x}^{(t)}x(t) 来决定。但在实际应用中,网络输出 \vec{o}^{(t)}o(t) 可能依赖于整个输入序列

如语音识别任务中,当前语音对应的单词不仅取决于前面的单词,也取决于后面的单词。因为词与词之间存在 语义依赖

  双向循环神经网络 (Bidirectional RNN, BiRNN) 就是为了解决这种双向依赖问题,它在需要双向信息的应用中非常成功,如 手写识别语音识别 等。BiRNN 是一个相对简单的 RNNs,由两个 RNNs 上下叠加在一起组成,输出由这两个 RNNs 的隐藏层状态决定

2.1 BiRNN 模型结构

  顾名思义,BiRNN 结合时间上从序列 起点移动 的 RNN 和另一个时间上从 序列末尾 移动的 RNN

  • \overrightarrow{h}^{(t)}h(t) 代表通过时间向未来移动的子 RNN 状态,向右传播信息
  • \overleftarrow{h}^{(t)}h(t) 代表通过时间向过去移动的子 RNN 状态,向左传播信息

  这允许输出单元 o^{(t)}o(t) 能够计算同时依赖于过去和未来且对时刻 tt 的输入值最敏感的表示,而不必指定 tt 周围固定大小的窗口,因此在每个点 tt,输出单元 o^{(t)}o(t) 可以受益于 \overrightarrow h^{(t)}h(t) 中关于过去的相关概要以及输出 \overleftarrow h^{(t)}h(t) 中关于未来的相关概要

2.2 BiRNN 传播推导

  给定时间步 tt 的小批量输入 X_t \in \Re^{n\times d}Xt​∈ℜn×d (样本数为 nn,输入个数为 dd) 和隐藏层激活函数为 \phiϕ, 在 BiRNN 的模型架构中,设共有 hh 个隐藏单元,该时间步 tt 正向隐藏状态为 \overrightarrow h^{(t)} \in \Re^{n\times h}h(t)∈ℜn×h, 反向隐藏状态为 \overleftarrow h^{(t)} \in \Re^{n\times h}h(t)∈ℜn×h, 则有

\qquad\qquad\overleftarrow h^{(t)} = \phi(x_tW_{x,h}^{(f)} + \overleftarrow h^{(t-1)}W_{h,h}^{(f)} + b_h^{(f)})h(t)=ϕ(xt​Wx,h(f)​+h(t−1)Wh,h(f)​+bh(f)​)

\qquad\qquad\overrightarrow h^{(t)} = \phi(x_tW_{x,h}^{(b)} + \overrightarrow h^{(t+1)}W_{h,h}^{(b)} + b_h^{(b)})h(t)=ϕ(xt​Wx,h(b)​+h(t+1)Wh,h(b)​+bh(b)​)

其中 \lbrace W^{(f)}_{x,h}, W^{(b)}_{x,h}\rbrace \in \Re^{d \times h}, \lbrace W^{(f)}_{h,h}, W^{(b)}_{h,h}\rbrace \in \Re^{h \times h}{Wx,h(f)​,Wx,h(b)​}∈ℜd×h,{Wh,h(f)​,Wh,h(b)​}∈ℜh×h 和偏差 b^{(f)}_h \in \Re^{1 \times h}, b^{(b)}_h \in \Re^{1 \times h}bh(f)​∈ℜ1×h,bh(b)​∈ℜ1×h 均为模型参数

  连结两个方向的隐藏状态 \lbrace \overrightarrow h^{(t)}, \overleftarrow h^{(t)}\rbrace{h(t),h(t)} 来得到隐藏状态 h^{(t)} \in \Re^{n \times 2h}h(t)∈ℜn×2h,并将其输入到输出层, 假设共有 qq 个输出单元个数,计算输出 o^{(t)} \in \Re^{n \times q}o(t)∈ℜn×q

\qquad\qquad o^{(t)} = h^{(t)} W_{h,q} + b_qo(t)=h(t)Wh,q​+bq​

其中权重 W_{h,q} \in \Re^{2h\times q}Wh,q​∈ℜ2h×q 和偏差 b_q \in \Re^{1 \times q}bq​∈ℜ1×q 为输出层的模型参数

2.3 PyTorch 代码复现

  BiRNN 可以使用 RNN 类似的算法来做训练,因为两个方向的神经元没有任何相互作用。然而反向传播时,由于不能同时更新输入和输出层,因此需要额外的过程

  • 对于前向传播,传递正向状态和后向状态,然后输出神经元通过
  • 对于反向传播,首先输出神经元,然后传递正向状态和反向状态
  • 在进行前向和反向传播之后,更新权重

  BiRNN 使用的模型是 nn.LSTM, 在第 07 章中提到,LSTM 是一类可以处理长期依赖问题的特殊的 RNN,由 Hochreiter 和 Schmidhuber 于 1977 年提出,目前已有多种改进,且广泛用于各种各样的问题中

  • 参数 bidirectional=True 是表示该网路是一个双向的网络
  • 参数 batch_first=True 因为 nn.lstm() 接受的数据输入是 [序列长度,batch,输入维数],使用 batch_first 可以将输入变成 [batch,序列长度,输入维数]

# %load birnn.py import torch import torch.nn as nn class BiRNN(nn.Module): def __init__(self, input_size, hidden_size, num_layers, num_classes): super(BiRNN, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True) self.fc = nn.Linear(hidden_size*2, num_classes) # 2 for bidirection def forward(self, x): # Set initial states h0 = torch.zeros(self.num_layers*2, x.size(0), self.hidden_size) # 2 for bidirection c0 = torch.zeros(self.num_layers*2, x.size(0), self.hidden_size) # Forward propagate LSTM out, _ = self.lstm(x, (h0, c0)) # out: tensor of shape (batch_size, seq_length, hidden_size*2) # Decode the hidden state of the last time step out = self.fc(out[:, -1, :]) return out


第3节 深度循环神经网络

3.1 DRNN 模型特点

  RNN 的计算大致可以分解为三种变换

  • 从输入 \vec{x}^{(t)}x(t) 到隐状态 \vec{h}^{(t)}h(t) 的变换
  • 从前一个隐状态 \vec{h}^{(t)}h(t) 到下一个隐状态 \vec{h}^{(t+1)}h(t+1) 的变换
  • 从隐状态 \vec{h}^{(t)}h(t) 到输出 \vec{o}^{(t)}o(t) 的变换

  这三个变换都是浅层的,即由一个仿射变换加一个激活函数组成, 事实上可以对这三种变换中引入 深度

  • 通过将 RNN 隐状态分为多层来引入深度
  • 在这三种变换中,各自使用一个独立的 MLP, 可以是较浅的,也可以是较深的
  • 在第二种方式的基础上,类似 ResNet 的思想,在 “隐状态-隐状态” 的路径中引入 跳跃连接

3.2 DRNN 模型结构

3.2.1 添加 隐状态深度

  通过将 RNN 的隐状态分为多层来引入深度:隐状态有两层 \vec{h}^{(t)}h(t) 和 \vec{z}^{(t)}z(t), 隐状态层中层次越高,对输入提取的概念越抽象

  • 模型的数学表示

    \qquad\qquad o^{(t)}_k = p(y^{(t)} = k | \vec{x}^{(1)}, \dots, \vec{x}^{(t)}), k = 1,2,\dots, Kok(t)​=p(y(t)=k∣x(1),…,x(t)),k=1,2,…,K

  • 单个样本的损失

    \qquad\qquad L = - \sum\limits^{\tau}_{t=1}\sum\limits^K_{k=1}\mathbb{I}_{k=y^{(t)}}\enspace \log o^{(t)}_kL=−t=1∑τ​k=1∑K​Ik=y(t)​logok(t)​

  • 更新方程

    \qquad\qquad \vec{a}^{(t)}_1 = \vec{b}_1 + W_1\vec{h}^{(t-1)} + Ux^{(t)}a1(t)​=b1​+W1​h(t−1)+Ux(t)

    \qquad\qquad \vec{h}^{(t)} = tanh(\vec{a}^{(t)}_1)h(t)=tanh(a1(t)​)

    \qquad\qquad \vec{a}^{(t)}_2 = \vec{b}_2 + W_2\vec{z}^{(t-1)} + Rh^{(t)}a2(t)​=b2​+W2​z(t−1)+Rh(t)

    \qquad\qquad \vec{z}^{(t)} = tanh(\vec{a}^{(t)}_2)z(t)=tanh(a2(t)​)

    \qquad\qquad \vec{o}^{(t)} = softmax(\vec{c} + V\vec{z}^{(t)})o(t)=softmax(c+Vz(t))

可知每一层便是一个循环神经网络,而下一层的循环神经网络的输出作为上一层的输入,依次进行迭代而成

深度循环神经网络的应用范围较少,对于单层的模型已经可以实现对序列模型的编码,而深层次模型会造成一定的 过拟合和梯度 问题,因此很少被应用

3.2.2 添加 MLP 层

  使用一个独立的 MLP 所生成的额外深度将导致从时间步 tt 到时间步 t+1t+1 的最短路径变得更长,这可能导致优化困难而破坏学习效果

3.2.3 添加 跳跃连接

  类似 ResNet 的思想,在 隐状态-隐状态 的路径中引入跳跃连接,从而缓解最短路径变得更长的问题

开始实验

第09章 循环神经网络变种相关推荐

  1. 《Scikit-Learn与TensorFlow机器学习实用指南》第14章 循环神经网络

    第14章 循环神经网络 来源:ApacheCN<Sklearn 与 TensorFlow 机器学习实用指南>翻译项目 译者:@akonwang @alexcheen @飞龙 校对:@飞龙 ...

  2. 曹健老师 TensorFlow2.1 —— 第六章 循环神经网络

    第一章 第二章 第三章 第四章 第五章 本章目的:用 RNN 实现连续数据的预测 ( 以股票预测为例 ). 6.1 循环核 循环核:具有记忆力,通过不同时刻的参数共享,实现了对时间序列的信息提取.循环 ...

  3. TensorFlow 2.0深度学习算法实战教材---第11章 循环神经网络

    人工智能的强力崛起,可能是人类历史上最好的事情,也可能是最糟糕的事情.−史蒂芬•霍金 卷积神经网络利用数据的局部相关性和权值共享的思想大大减少了网络的参数量,非常适合于图片这种具有空间(Spatial ...

  4. 第07章 循环神经网络

    第1节 循环神经网络简介   循环神经网络 (Recurrent Neural Network) 或 RNN 是一类用于处理 序列数据 的神经网络 卷积神经网络是专门用于处理网格化数据 \Imℑ 的神 ...

  5. 第六章_循环神经网络(RNN)

    文章目录 第六章 循环神经网络(RNN) CNN和RNN的对比 http://www.elecfans.com/d/775895.html 6.1 为什么需要RNN? 6.1 RNN种类? RNN t ...

  6. NNDL 实验七 循环神经网络(1)RNN记忆能力实验

    NNDL 实验七 循环神经网络(1)RNN记忆能力实验 第6章 循环神经网络 6.1 循环神经网络的记忆能力实验 6.1.1 数据集构建 6.1.1.1 数据集的构建函数 6.1.1.2 加载数据并进 ...

  7. tensorflow lstm从隐状态到预测值_机器学习100天-Day2405 循环神经网络RNN(LSTM)

    说明:本文依据<Sklearn 与 TensorFlow 机器学习实用指南>完成,所有版权和解释权均归作者和翻译成员所有,我只是搬运和做注解. 进入第二部分深度学习 第十四章循环神经网络 ...

  8. keras 多层lstm_机器学习100天-Day2403 循环神经网络RNN(训练多层RNN)

    说明:本文依据<Sklearn 与 TensorFlow 机器学习实用指南>完成,所有版权和解释权均归作者和翻译成员所有,我只是搬运和做注解. 进入第二部分深度学习 第十四章循环神经网络 ...

  9. sklearn 神经网络_机器学习100天-Day2404 循环神经网络RNN(预测时间序列)

    说明:本文依据<Sklearn 与 TensorFlow 机器学习实用指南>完成,所有版权和解释权均归作者和翻译成员所有,我只是搬运和做注解. 进入第二部分深度学习 第十四章循环神经网络 ...

  10. 小常识10: 循环神经网络(RNN)与长短时记忆网络LSTM简介。

    小常识10:  循环神经网络(RNN)与长短时记忆网络LSTM简介. 本文目的:在计算机视觉(CV)中,CNN 通过局部连接/权值共享/池化操作/多层次结构逐层自动的提取特征,适应于处理如图片类的网格 ...

最新文章

  1. node给java发送文件_如何实现node上传文件到后台?
  2. [官方摘要]Setup And Configuration memcached with Tomcat
  3. python内置数据结构教程第四版答案_Python数据结构--内置数据结构
  4. 「后端小伙伴来学前端了」Vue中全局事件总线(GlobalEventBus)原理及探究过程
  5. Linux下VNC配置多个桌面和修改密码 不会当系统重启vnc失效
  6. python 需要多久能够学精通_python入门到精通需要学多久-史上最详细python学习路线-从入门到精通,只需5个月时间...
  7. 一个ABAP程序,能够批量下载有道云笔记里包含的图片
  8. gwt-2.8.2下载_GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
  9. 一个实用的JS自定义函数addLoadEvent()
  10. Cping (cmd shell )版本
  11. Win7系统IE、搜狗等浏览器首页被恶意网址qq789.com.cn劫持……
  12. macOS:删除 MDM 配置描述文件
  13. 流畅的python第六章 使用一等函数设计模式
  14. BZOJ4340:[BJOI2015]隐身术(后缀数组,ST表,DFS)
  15. 炼数成金Scala语言入门
  16. 如何写好一份数据分析报告?
  17. Acwing算法—动态规划
  18. 美国 计算机与艺术 专业,美国加州大学圣地亚哥分校计算机与艺术专业.pdf
  19. 21个经典的哲理故事
  20. 并行计算系列-阿姆达尔定律(Amdahl‘s Law)

热门文章

  1. Spark日志中的Tid是什么?详细解析和编程示例
  2. 基于nginx+consul-template+consul+springboot实现自动发现服务的集群
  3. SCUT_ACM_PLACTICE #1 STL竞赛入门
  4. 区块链软件公司:从事区块链行业不得不克服的五大障碍
  5. 【计算机毕业设计】074智能物流管理系统
  6. java-统计单词-统计字母个数
  7. 智能手表音频特性测试_智能穿戴设备有哪些?解析可穿戴设备的作用和测试
  8. GitHub常见标签生成教学,让你的开源库添加几分姿色。
  9. SQL*Loader-500: Unable to open file (v1x-access_log_20120916.dat)
  10. Git的方法和命令(2)