1. 从一个栗子开始 - Slot Filling

比如在一个订票系统上,我们的输入 “Arrive Taipei on November 2nd” 这样一个序列,我们设置几个槽位(Slot),希望算法能够将关键词'Taipei'放入目的地(Destination)槽位, 将November和2nd放入到达时间(Time of Arrival)槽位,将Arrive和on放入其他(Other)槽位,实现对输入序列的一个归类,以便后续提取相应信息。

用前馈神经网络(Feedforward Neural Network)来解决这个问题的话,我们首先要对输入序列向量化,将每一个输入的单词用向量表示,可以使用 One-of-N Encoding 或者是 Word hashing 等编码方法,输出预测槽位的概率分布。

但是这样做的话,有个问题就出现了。如果现在又有一个输入是 “Leave Taipei on November 2nd”,这里Taipei是作为一个出发地(Place of Departure),所以我们应当是把Taipei放入Departure槽位而不是Destination 槽位,可是对于前馈网络来说,对于同一个输入,输出的概率分布应该也是一样的,不可能出现既是Destination的概率最高又是Departure的概率最高。

所以我们就希望能够让神经网络拥有“记忆”的能力,能够根据之前的信息(在这个例子中是Arrive或Leave)从而得到不同的输出。将两段序列中的Taipei分别归入Destionation槽位和Departure槽位。


2. RNN

  • 基本概念

    在RNN中,隐层神经元的输出值都被保存到记忆单元中,下一次再计算输出时,隐层神经元会将记忆单元中的值认为是输入的一部分来考虑

    RNN中考虑了输入序列顺序,序列顺序的改变会影响输出的结果。

  • 常见变体

    • Elman Network
      将隐层的输出(即记忆单元中的值)作为下一次的输入

    \(h_t = \sigma_h(W_hx_t + U_h\color{green}{h_{t-1}} + b_h)\)

    \(y_t = \sigma_h(W_yh_t + b_y)\)

    • Jordan Network
      将上一时间点的输出值作为输入

    \(h_t = \sigma_h(W_hx_t + U_h\color{green}{y_{t-1}} + b_h)\)

    \(y_t = \sigma_h(W_yh_t + b_y)\)

    • Bidirectional RNN

3. Long Short-term Memory (LSTM)

  • 基本结构

    • 由Memory Cell, Input Gate, Output Gate, Forget Gate 组成
    • 特殊的神经元结构,包含4个input(三个Gate的控制信号以及输入的数据),1个output
    • 激活函数通常选用sigmoid function, sigmoid的输出介于0到1之间,表征了Gate的打开程度。
  • Traditional LSTM
    \[
    \begin{align}
    f_t & = \sigma_g(W_fx_t + \color{green}{U_fh_{t-1}} + b_f) \\
    i_t & = \sigma_g(W_i x_t + \color{green}{U_ih_{t-1}} + b_i) \\
    o_t & = \sigma_g(W_o x_t + \color{green}{U_oh_{t-1}} + b_o) \\
    c_t & = f_t\,{\circ}\,c_{t-1} + i_t\,{\circ}\,\sigma_c(W_cx_t\color{green}{+ U_ch_{t-1}} +b_c) \\
    h_t & = o_t \,{\circ}\, \sigma_h(c_t)
    \end{align}
    \]

  • Peephole LSTM, 在大部分的情况下,用\(\color{blue}{c_{t-1}}\)取代\(\color{green}{h_{t-1}}\)
    \[
    \begin{align}
    f_t & = \sigma_g(W_fx_t + \color{green}{U_f\color{blue}{c_{t-1}}} + b_f) \\
    i_t & = \sigma_g(W_i x_t + \color{green}{U_i\color{blue}{c_{t-1}}} + b_i) \\
    o_t & = \sigma_g(W_o x_t + \color{green}{U_o\color{blue}{c_{t-1}}} + b_o) \\
    c_t & = f_t\,{\circ}\,c_{t-1} + i_t\,{\circ}\,\sigma_c(W_cx_t +b_c) \\
    h_t & = o_t \,{\circ}\, \sigma_h(c_t)
    \end{align}
    \]

    • \(x_t\)表示输入向量,\(h_t\)表示输出向量,\(c_t\)表示记忆单元的状态向量,\(\circ\)代表Hadamard product(A.k.a. Schur product)
    • \(W\)表示输入权重,\(U\)表示循环权重,\(b\)表示偏置
    • \(\delta_g\)代表sigmoid function,\(\delta_c\)代表hyperbolic tangent, \(\delta_h\)表示 hyperbolic tangent(peephole LSTM论文中建议选用\(\delta_h(x)=x\))
    • \(f_t\),\(i_t\)和\(o_t\)表示门控向量值
      • \(f_t\)表示遗忘门向量,表征记忆旧信息的能力
      • \(i_t\)表示输入门向量,表征获取新信息的能力
      • \(o_t\)表示输出门向量,表征输出信息的能力
  • 补充知识点
    • Short-term,表示保留对前一时间点输出的短期记忆,相比于最原始的RNN结构中的记忆单元(每次有新的输入时记忆体的状态就会被更新,因此是短期的记忆),而LSTM的记忆体则拥有相对较长的记忆时间(由Forget Gate决定),所以是Long Short-term
    • LSTM一般采用多层结构组合,Multiple-layer LSTM
    • Keras中实现了LSTM,GRU([Cho,Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation,EMNLP'14] 只有两个Gate,容易训练),SimpleRNN层,可以方便的调用。

4. RNN如何学习?

  • 损失函数的定义:

    • 每一个时间点的RNN的输出和标签值的交叉熵(cross-entropy)之和
  • 训练过程:
    • 使用被称作Backpropagation through time(BPTT)的梯度下降法
    • 训练其实是比较困难的,因为Total Loss可能会出现剧烈的抖动
    • 根据论文[Razvan Pascanu,On the difficulty of training Recurrent Neural Networks,ICML'13]上对RNN的分析,损失函数的表面要么非常平坦,要么非常陡峭(The error surface is either very flat or very steep),当你的参数值在较为平坦的区域做更新时,因此该区域梯度值比较小,此时的学习率一般会变得的较大,如果突然到达了陡峭的区域,梯度值陡增,再与此时较大的学习率相乘,参数就有很大幅度更新(实线表示的轨迹),因此学习过程非常不稳定。Razvan Pascanu使用了叫做“Clipping”的训练技巧:为梯度设置阈值,超过该阈值的梯度值都会被cut,这样参数更新的幅度就不会过大(虚线表示的轨迹),因此容易收敛。
  • 为什么在RNN中会有这种问题?
    • 是因为激活函数选用了sigmoid而不是ReLU么?然而并不是。事实上,在RNN中使用ReLU反而效果会不如Sigmoid,不过也是看你的参数初始化值的选取,所以也不一定,比如后面提到的Quoc V.Le的那篇文章,使用特别初始化技巧硬训ReLU的RNN得到了可比拟LSTM的效果。因此激活函数并不是这里的关键点。
    • 那究竟是什么原因呢?我们来分析梯度更新公式中的\(w-\eta\frac{\partial{L}}{\partial{w}}\)来探寻一番。但是这样一个偏微分的关系我们应该如何来分析呢?这里我们用一个技巧:给w值一个微小的变化,观察对应的Loss的变化情况。假设当前模型是1000个只含有一个线性隐层的RNN级联结构。并假设我们当前的输入是100000……(只有第一个值是1,剩下全是0),因此最后的输出值是\(w^{999}\)。现在假设我们\(w\)的值是1,那么RNN在最后时间点的输出是1,给\(w\)一个微小的变化+0.01,此时的输出变成了大约20000!这段区域呈现出一个陡峭的趋势。如果给\(w\)一个微小的变化-0.01变为0.99,测试的输出基本变成0,哪怕是\(w\)变到0.01时,输出依旧是0,这段区域呈现出一个平坦的趋势。因此我们可以看出由于RNN采用时间序列的结构,权重值在不同时间点被反复使用,这种累积性的变化可能对结果造成极大的影响,也可能会很长一段时间保持平稳。
  • 常用的技巧

5. RNN的更多应用场景


6. 其他的学习资料


7. 本文参考资料

Deep & Structured 未完待续

【机器学习笔记】循环神经网络RNN的更多相关文章

  1. 用纯Python实现循环神经网络RNN向前传播过程(吴恩达DeepLearning.ai作业)

    Google TensorFlow程序员点赞的文章!   前言 目录: - 向量表示以及它的维度 - rnn cell - rnn 向前传播 重点关注: - 如何把数据向量化的,它们的维度是怎么来的 ...

  2. 循环神经网络(RNN, Recurrent Neural Networks)介绍(转载)

    循环神经网络(RNN, Recurrent Neural Networks)介绍    这篇文章很多内容是参考:http://www.wildml.com/2015/09/recurrent-neur ...

  3. 通过keras例子理解LSTM 循环神经网络(RNN)

    博文的翻译和实践: Understanding Stateful LSTM Recurrent Neural Networks in Python with Keras 正文 一个强大而流行的循环神经 ...

  4. 循环神经网络RNN及LSTM

    一.循环神经网络RNN RNN综述 https://juejin.im/entry/5b97e36cf265da0aa81be239 RNN中为什么要采用tanh而不是ReLu作为激活函数?  htt ...

  5. 深度学习之循环神经网络RNN概述,双向LSTM实现字符识别

    深度学习之循环神经网络RNN概述,双向LSTM实现字符识别 2. RNN概述 Recurrent Neural Network - 循环神经网络,最早出现在20世纪80年代,主要是用于时序数据的预测和 ...

  6. 循环神经网络RNN模型和长短时记忆系统LSTM

    传统DNN或者CNN无法对时间序列上的变化进行建模,即当前的预测只跟当前的输入样本相关,无法建立在时间或者先后顺序上出现在当前样本之前或者之后的样本之间的联系.实际的很多场景中,样本出现的时间顺序非常 ...

  7. 从网络架构方面简析循环神经网络RNN

    一.前言 1.1 诞生原因 在普通的前馈神经网络(如多层感知机MLP,卷积神经网络CNN)中,每次的输入都是独立的,即网络的输出依赖且仅依赖于当前输入,与过去一段时间内网络的输出无关.但是在现实生活中 ...

  8. 循环神经网络(RNN, Recurrent Neural Networks)介绍

    原文地址: http://blog.csdn.net/heyongluoyao8/article/details/48636251# 循环神经网络(RNN, Recurrent Neural Netw ...

  9. 《转》循环神经网络(RNN, Recurrent Neural Networks)学习笔记:基础理论

    转自 http://blog.csdn.net/xingzhedai/article/details/53144126 更多参考:http://blog.csdn.net/mafeiyu80/arti ...

  10. 吴恩达deepLearning.ai循环神经网络RNN学习笔记_看图就懂了!!!(理论篇)

    前言 目录: RNN提出的背景 - 一个问题 - 为什么不用标准神经网络 - RNN模型怎么解决这个问题 - RNN模型适用的数据特征 - RNN几种类型 RNN模型结构 - RNN block - ...

随机推荐

  1. C# 解决组合优化问题

    Google Optimization Tools介绍 Google Optimization Tools(OR-Tools)是一款专门快速而便携地解决组合优化问题的套件.它包含了: 约束编程求解器. ...

  2. [译] 怎样(以及为什么要)保持你的 Git 提交记录的整洁

    最近在掘金翻译了一篇文章,主要讲的是 Git 提交记录的维护,确实很有用,感兴趣的同学可以去看一下.链接如下: [译] 怎样(以及为什么要)保持你的 Git 提交记录的整洁 截图:

  3. iOS的KVO使用和轻量级封装

    KVO的使用方法 注冊 [object addObserver:observer forKeyPath:@"text" options:NSKeyValueObservingOpt ...

  4. Spring(十九)之异常处理

    异常处理,对于项目开发至关重要,总不能用户点击一个页面出错了,直接报500,那样用户体验多不好啊! 所以这里讲的是SpringMVC对异常的处理,希望能给大家带来一定的 帮助和启发. 一.编写实体 p ...

  5. MacType 文字之美 – 让 Windows 字体更漂亮

    苹果的Mac系统总能让人眼前一亮,除了其精美的软件界面设计外,最重要是其文字显示效果(渲染方式)比 Windows 更加清晰锐利,阅读起来更加舒服.于是就有高手开发了一款叫 GDI++ 的字体渲染引擎 ...

  6. python 在线生成文字云

    在线生成文字云 在线生成文字云地址  http://a.leechg.com:8080/wordcloud 效果图 大体步骤 1 接收请求中的文本,通过结巴分词处理文本. seg_generator ...

  7. 【luogu P3623 [APIO2008]免费道路】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3623 说是对克鲁斯卡尔的透彻性理解 正解: 先考虑加入水泥路,然后再考虑加入剩下必须要加入的最少鹅卵石路. ...

  8. NopCommerce 3.4中移动端访问抛弃响应式布局

    在Nop3.4中,他抛弃了原来的xxx.Mobile.cshtml的这种写法,而是采用了响应式布局,并且把规则也给改了,你在后台配置不启用响应式布局,在前台你仍然不能写xxx.Mobile.cshtm ...

  9. 第23章 I2C—读写EEPR

    本章参考资料:<STM32F76xxx参考手册>.<STM32F7xx规格书>.库帮助文档<STM32F779xx_User_Manual.chm>及<I2C ...

  10. dubbox provider cosumer 包坐标及xml

    provider pom <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http:// ...