循环神经网络主要用于呈序列形式的数据,如文字、音频,可以实现语音识别、自然语言处理、动作识别等功能。

文章目录

  • 符号约定
  • 建立RNN模型
    • 向前传播
    • 向后传播
  • 更多RNN模型
    • 多对多
    • 多对一
    • 一对多
    • 不等长多对多
  • 语言模型
    • 文本训练
    • 文本生成
  • 门控循环单元(Gated Recurrent Unit)
  • 长短期记忆(Long Short Term Memory)
  • 双向循环神经网络(Bidirectional RNN)
  • 深度RNN

符号约定

因为数据都是序列形式,所以输入输出我们用尖括号上标表示其在序列中的位置,x<t>x^{<t>}x<t>表示输入序列第ttt个数据,输出y<t>y^{<t>}y<t>同理。用TxT_xTx​表示输入序列长度,TyT_yTy​表示输出序列长度。此外,圆括号表示多样本中样本的序号,x(i)<t>x^{(i)<t>}x(i)<t>表示第iii个样本序列中第ttt个数据。

在自然语言处理(NLP)问题中,我们还经常用到一个词汇表,其中是可能用到的词汇,通常按字典序排列,规模在一万至几十万不等。通过该词典,我们可以将序列中的每个数据表示成一位热键(one-hot),每个单词都被一个列向量表示,这个向量中只有单词在词典中对应的索引为1,其余元素均为0。
当遇到不在词典中的词,则打一个未知标记。

建立RNN模型

以文本中的人名识别问题为例,一个朴素的神经网络可能是输入层的每个节点都输入一个序列中的词汇,而输出层每个节点输出0或1表示该位置的单词是否是人名。这就会有两个问题,其一是文本的长度变化很大,输入输出的节点很可能不够用或者多余;其次模型从文本中学习到的内容不能共享,如果人名的出现位置变了,那些学习了如何识别人名的节点就无法发挥作用。

那么RNN是如何解决这些问题的呢?首先,我们设置网络的初始激活值a<0>a^{<0>}a<0>(一般是全0向量),之后输入序列第一个数据x<1>x^{<1>}x<1>,得到第一个预测输出y^<1>\hat{y}^{<1>}y^​<1>,然后将这一步得到的参数传给序列下一个位置的计算,如此循环直到计算到序列的最后一位,这样就实现了参数共享,且不受序列长度的限制。

向前传播

首先,设置初始激活值a<0>=0⃗a^{<0>}=\vec{0}a<0>=0,然后进行第一个数据的计算,激活值和输入都乘以权重再加上偏置经过激活函数得到激活值,激活值再计算经过(可能是另一个)激活函数得到一个输出y<1>y^{<1>}y<1>,即
a<1>=g1(Waaa<0>+Waxx<1>+ba)y^<1>=g2(Wyaa<1>+by)\begin{aligned} &a^{<1>}=g_1(W_{aa}a^{<0>}+W_{ax}x^{<1>}+b_a)\\ &\hat{y}^{<1>}=g_2(W_{ya}a^{<1>}+b_y) \end{aligned} ​a<1>=g1​(Waa​a<0>+Wax​x<1>+ba​)y^​<1>=g2​(Wya​a<1>+by​)​
这里g1g_1g1​一般是tanh⁡\tanhtanh函数(我们用其他方法避免梯度消失问题),g2g_2g2​则根据需要的输出选择,人名识别是一个二元分类问题,所以g2g_2g2​选择逻辑函数。

更一般的传递过程就是每一次激活层都从上一次循环的激活值基础上进行运算,然后本次的激活值一通运算之后得到本次的输出。
a<t>=g1(Waaa<t−1>+Waxx<t>+ba)y^<t>=g2(Wyaa<t>+by)\begin{aligned} &a^{<t>}=g_1(W_{aa}a^{<t-1>}+W_{ax}x^{<t>}+b_a)\\ &\hat{y}^{<t>}=g_2(W_{ya}a^{<t>}+b_y) \end{aligned} ​a<t>=g1​(Waa​a<t−1>+Wax​x<t>+ba​)y^​<t>=g2​(Wya​a<t>+by​)​


我们还可以简化一下表达式,将WaaW_{aa}Waa​和WaxW_{ax}Wax​矩阵按列(左右)堆叠一起,将a<t−1>a^{<t-1>}a<t−1>和x<t>x^{<t>}x<t>按行(上下)堆叠在一起,表达式变成
a<t>=g1(Wa[a<t−1>,x<t>]+ba)y^<t>=g2(Wya<t>+by)\begin{aligned} &a^{<t>}=g_1(W_{a}[a^{<t-1>},x^{<t>}]+b_a)\\ &\hat{y}^{<t>}=g_2(W_{y}a^{<t>}+b_y) \end{aligned} ​a<t>=g1​(Wa​[a<t−1>,x<t>]+ba​)y^​<t>=g2​(Wy​a<t>+by​)​
其中
Wa=[WaaWax],[a<t−1>,x<t>]=[a<t−1>x<t>]W_a=\left[\begin{matrix} W_{aa}&W_{ax} \end{matrix}\right], [a^{<t-1>},x^{<t>}]=\left[\begin{matrix} a^{<t-1>}\\ x^{<t>} \end{matrix}\right] Wa​=[Waa​​Wax​​],[a<t−1>,x<t>]=[a<t−1>x<t>​]

向后传播

当我们用机器学习框架实现神经网络是,一般编程框架可以自动处理反向传播,我们简单了解一下如何向后传播即可。

由于这是一个二元分类问题,其损失函数按照逻辑回归的损失定义即可,对于序列的每个位置,有
L<t>(y^<t>,y<t>)=−y<t>log⁡y^<t>−(1−y<t>)log⁡(1−y^<t>)\mathcal{L}^{<t>}(\hat{y}^{<t>},y^{<t>})=-y^{<t>}\log \hat{y}^{<t>}-(1-y^{<t>})\log(1-\hat{y}^{<t>}) L<t>(y^​<t>,y<t>)=−y<t>logy^​<t>−(1−y<t>)log(1−y^​<t>)
整个样本的损失就是在序列上求和,即
L(y^,y)=∑t=1TyL<t>(y^<t>,y<t>)\mathcal{L}(\hat{y},y)=\sum_{t=1}^{T_y}\mathcal{L}^{<t>}(\hat{y}^{<t>},y^{<t>}) L(y^​,y)=t=1∑Ty​​L<t>(y^​<t>,y<t>)
所以反向传播就是求Wy,by,Wa,baW_y,b_y,W_a,b_aWy​,by​,Wa​,ba​对该损失函数的导数,且要在时间轴上反向计算,按照下图红色箭头从右到左依次运算:

更多RNN模型

上面介绍的模型算是比较基础的,输入输出的序列长度是一样的,下面介绍一些其他的RNN模型。

多对多

就是上面介绍的模型,每个输入序列每个元素都可以对应一个输出序列。

多对一

只在遍历完整个序列以后输出,比如说对一段文字打分。

一对多

只有一个输入或输入是空集,输出一段序列,比如自动写作/谱曲。

不等长多对多

输入和输出都是序列,但是长度不一样,比如文本翻译。

语言模型

语言建模是自然语言处理中最基本、最重要的任务之一,在这一领域RNN的表现也非常不错。

文本训练

对于一个样例文本,如"Cats average 15 hours of sleep a day.",我们先将序列中的每个单词都映射为一个与我们的词典对应的列向量,然后将这些向量作为网络的输入,词典中没有的词用<UNK>未知标记替代,结尾用<EOS>句尾标记替代。按序列顺序输入文本时,每次的输出表示根据已有输入,下一个单词为不同词汇的概率,也是对应词典的列向量,可以看作一个多元分类问题,因此输出的激活函数为softmax函数。

损失函数也与softmax的多元分类问题一致,将期望的输出列向量与预测得到的列向量取log按位相乘再求和,如下图。

文本生成

给定一个初始值(比如零向量),然后模型生成第一个预测向量,再将该预测向量传给下一次循环作为输入,得到序列下一个位置的预测向量……如此循环直到我们想要的长度或者有句尾标记。然后我们从一系列预测向量中采样(比如选择预测概率最大的那个或者随机采样等等)就能得到一个完整的句子。

除了以单词为基本单位的,还有以字母为基本单位的模型。大多数情况下,我们都使用单词级语言模型,但是随着计算机速度的加快,单词级的应用越来越多。但它们往往需要大量的硬件和更复杂的计算训练, 因此今天还没有被广泛使用。除非需要特殊处理很多未知单词或其他词汇词的程序。它们也被用于更专业的应用程序中,这些程序需要更专业词汇。

在训练好的模型中采样,就可以得到下图这样的生成文本:

门控循环单元(Gated Recurrent Unit)

对于一些长文本,相隔遥远的两个单词之间的联系会因为通过了多个激活函数变得微弱,有时候还会因为连续累乘造成数字过大,这就是深度网络中的梯度消失/爆炸问题。

为了解决梯度消失/爆炸问题,我们向网络中添加门控循环单元(GRU),这是一个类似于记忆模块的东西,通过控制权值来着重记忆一些内容,这样长文本中的关联词(如人称,时态)就不会断了联系。

新增记忆单元ccc、门控单元Γu\Gamma_uΓu​和计算ccc和Γu\Gamma_uΓu​的权值矩阵Wc,bc,Wu,buW_c,b_c,W_u,b_uWc​,bc​,Wu​,bu​,新的向前传播公式变为
c<t−1>=a<t−1>c~<t>=tanh⁡(Wc[c<t−1>,x<t>]+bc)Γu=σ(Wu[c<t−1>,x<t>]+bu)c<t>=a<t>=Γu∗c~<t>+(1−Γu)∗c<t−1>\begin{aligned} &c^{<t-1>}=a^{<t-1>}\\ &\tilde{c}^{<t>}=\tanh(W_c[c^{<t-1>},x^{<t>}]+b_c)\\ &\Gamma_u=\sigma(W_u[c^{<t-1>},x^{<t>}]+b_u)\\ &c^{<t>}=a^{<t>}=\Gamma_u*\tilde{c}^{<t>}+(1-\Gamma_u)*c^{<t-1>} \end{aligned} ​c<t−1>=a<t−1>c~<t>=tanh(Wc​[c<t−1>,x<t>]+bc​)Γu​=σ(Wu​[c<t−1>,x<t>]+bu​)c<t>=a<t>=Γu​∗c~<t>+(1−Γu​)∗c<t−1>​

上面还只是简化版GRU,完整版还有一个门控Γr\Gamma_rΓr​用来控制c<t−1>c^{<t-1>}c<t−1>到c~<t>\tilde{c}^{<t>}c~<t>的贡献:
c<t−1>=a<t−1>c~<t>=tanh⁡(Wc[Γr∗c<t−1>,x<t>]+bc)Γu=σ(Wu[c<t−1>,x<t>]+bu)Γr=σ(Wr[c<t−1>,x<t>]+br)c<t>=a<t>=Γu∗c~<t>+(1−Γu)∗c<t−1>\begin{aligned} &c^{<t-1>}=a^{<t-1>}\\ &\tilde{c}^{<t>}=\tanh(W_c[\Gamma_r*c^{<t-1>},x^{<t>}]+b_c)\\ &\Gamma_u=\sigma(W_u[c^{<t-1>},x^{<t>}]+b_u)\\ &\Gamma_r=\sigma(W_r[c^{<t-1>},x^{<t>}]+b_r) \\ &c^{<t>}=a^{<t>}=\Gamma_u*\tilde{c}^{<t>}+(1-\Gamma_u)*c^{<t-1>} \end{aligned} ​c<t−1>=a<t−1>c~<t>=tanh(Wc​[Γr​∗c<t−1>,x<t>]+bc​)Γu​=σ(Wu​[c<t−1>,x<t>]+bu​)Γr​=σ(Wr​[c<t−1>,x<t>]+br​)c<t>=a<t>=Γu​∗c~<t>+(1−Γu​)∗c<t−1>​

长短期记忆(Long Short Term Memory)

比GRU更强的记忆方法,将设置了更新Γu\Gamma_uΓu​、遗忘Γf\Gamma_fΓf​、输出Γo\Gamma_oΓo​三个参数来控制之前的信息对现在输出的影响。
c~<t>=tanh⁡(Wc[a<t−1>,x<t>]+bc)Γu=σ(Wu[a<t−1>,x<t>]+bu)Γf=σ(Wf[a<t−1>,x<t>]+bf)Γo=σ(Wo[a<t−1>,x<t>]+bo)c<t>=Γu∗c~<t>+Γf∗c<t−1>a<t>=Γo∗tanh⁡c<t>\begin{aligned} &\tilde{c}^{<t>}=\tanh(W_c[a^{<t-1>},x^{<t>}]+b_c)\\ &\Gamma_u=\sigma(W_u[a^{<t-1>},x^{<t>}]+b_u)\\ &\Gamma_f=\sigma(W_f[a^{<t-1>},x^{<t>}]+b_f)\\ &\Gamma_o=\sigma(W_o[a^{<t-1>},x^{<t>}]+b_o)\\ &c^{<t>}=\Gamma_u*\tilde{c}^{<t>}+\Gamma_f*c^{<t-1>}\\ &a^{<t>}=\Gamma_o*\tanh\ c^{<t>} \end{aligned} ​c~<t>=tanh(Wc​[a<t−1>,x<t>]+bc​)Γu​=σ(Wu​[a<t−1>,x<t>]+bu​)Γf​=σ(Wf​[a<t−1>,x<t>]+bf​)Γo​=σ(Wo​[a<t−1>,x<t>]+bo​)c<t>=Γu​∗c~<t>+Γf​∗c<t−1>a<t>=Γo​∗tanh c<t>​

双向循环神经网络(Bidirectional RNN)

普通RNN的一个缺点是我们按照序列顺序输入数据的时候,网络只能接收之前位置的信息,而有时候我们还需要网络接收序列位置在其之后的数据的信息,由此双向RNN应运而生。

实现很简单,建立一个反向的网络就可以了,然后输出预测值的时候综合考虑正向的激活值和反向的激活值,加没加GRU或LSTM都无所谓。

获取整个序列的信息既是优点也是缺点,这意味着我们必须要得到完整的一个序列的信息才能开始运算,对于一些实时场景BRNN就没有那么实用。

深度RNN

普通的RNN激活层只有一层,我们可以多加几层,每个激活层同时接收来自上一个循环的同一激活层和来自本次循环的上一个激活层的信息。这种加深操作同样不受GRU和LSTM的限制。

DRNN可以完成更复杂的计算,这同样意味着其耗费的训练成本和要求的运算性能更高。

深度学习:循环神经网络(RNN)相关推荐

  1. 深度学习 --- 循环神经网络RNN详解(BPTT)

    今天开始深度学习的最后一个重量级的神经网络即RNN,这个网络在自然语言处理中用处很大,因此需要掌握它,同时本人打算在深度学习总结完成以后就开始自然语言处理的总结,至于强化学习呢,目前不打算总结了,因为 ...

  2. 深度学习 循环神经网络RNN

    循环神经网络简介: 循环神经网络(Recurrent Neural Networks)是一种特殊的神经网络结构, 它是根据"人的认知是基于过往的经验和记忆"这一观点提出的. 它与D ...

  3. 深度学习---循环神经网络RNN详解(LSTM)

    上一节我们详细讲解了RNN的其中一个学习算法即BPTT,这个算法是基于BP的,只是和BP不同的是在反向传播时,BPTT的需要追溯上一个时间的权值更新,如下图,当前时刻是s(t),但是反向传播时,他需要 ...

  4. MLK | 一文理清深度学习循环神经网络

    MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于<百面机器学习>一书,结合自己的经验与思考做的一些总结 ...

  5. 深度学习-循环神经网络(RNN)

    作者: 明天依旧可好 QQ交流群: 807041986 注:关于深度学习的相关问题,若本文未涉及可在下方留言告诉我,我会在文章中进行补充的. 原文链接:https://mtyjkh.blog.csdn ...

  6. 深度学习--循环神经网络(Recurrent Neural Network)

    RNN(Recurrent Neural Network)是怎么来的? 一些应用场景,比如说写论文,写诗,翻译等等. 既然已经学习过神经网络,深度神经网络,卷积神经网络,为什么还要学习RNN? 首先我 ...

  7. 「NLP」 深度学习NLP开篇-循环神经网络(RNN)

    https://www.toutiao.com/a6714260714988503564/ 从这篇文章开始,有三AI-NLP专栏就要进入深度学习了.本文会介绍自然语言处理早期标志性的特征提取工具-循环 ...

  8. 深度学习~循环神经网络RNN, LSTM

    目录 1. 循环神经网络RNN 1.1 RNN出现背景 1.2 RNN概念 2. LSTM 2.1 LSTM出现背景 2.2 LSTM结构 参考 1. 循环神经网络RNN 1.1 RNN出现背景 pr ...

  9. 【NLP】 深度学习NLP开篇-循环神经网络(RNN)

    从这篇文章开始,有三AI-NLP专栏就要进入深度学习了.本文会介绍自然语言处理早期标志性的特征提取工具-循环神经网络(RNN).首先,会介绍RNN提出的由来:然后,详细介绍RNN的模型结构,前向传播和 ...

  10. 花书+吴恩达深度学习(十五)序列模型之循环神经网络 RNN

    目录 0. 前言 1. RNN 计算图 2. RNN 前向传播 3. RNN 反向传播 4. 导师驱动过程(teacher forcing) 5. 不同序列长度的 RNN 如果这篇文章对你有一点小小的 ...

最新文章

  1. 一些关于Rust在2019年的思考
  2. 《网页设计与前端开发 Dreamweaver+Flash+Photoshop+HTML+CSS+JavaScript 从入门到精通》—— 第1章 网页设计基础知识...
  3. OSChina 周六乱弹 ——世上无难事,只要肯放弃!
  4. 前端例程20211213:网页去色(以灰度形式显示)
  5. 自制StartUp宏病毒专杀小工具
  6. OpenBSD身份验证绕过和权限提升漏洞
  7. Bitmap createBitmap()裁剪图片
  8. DSPE-PEG3-Mal,带有DSPE的基团小分子PEG试剂
  9. WIN10任务栏的喇叭点了没反应,但是声音是正常的,就是不能调节音量
  10. 李南江的前端课程知识点(九)浮动流
  11. Java锁---偏向锁、轻量级锁、自旋锁、重量级锁
  12. Git:真实 merge
  13. 吐血整理一个月——终于把所有Python库整理齐了.....
  14. 常见的网络营销技巧有哪些?
  15. 2020.09.29重读 原2020.08.04读 MoreFusion
  16. 更改ip地址的软件多少钱一个月_武汉社保代缴多少钱一个月?武汉社保一个月交多少钱?...
  17. 关于LaTeX中的正文的字体大小
  18. MPI编程----计算cosx的积分
  19. 3318. 【BOI2013】Brunhilda的生日
  20. 网站关键词排名下掉?快查下是否入坑了这6个SEO误区

热门文章

  1. 轻松几步完成cisco交换机配置全是干货!
  2. 多线程打印ABCD顺序(带有线程池实现)
  3. 《Web漏洞防护》读书笔记——第6章,XXE防护
  4. MySQL 如何优化大分页查询?
  5. golang日志收集方案之ELK
  6. Objective-C Runtime 运行时之一:类与对象
  7. nginx简单的rewrite配置
  8. 服务器环境配置nginx / php / php-fpm(二)
  9. mysql统计一张表中条目个数的方法
  10. java线程状态、新建状态、运行状态、阻塞状态、等待阻塞、同步阻塞、其他阻塞、死亡状态