第1关:循环神经网络简介

任务描述

本关任务:通过学习循环神经网络的相关知识,完成单向循环网络的编写。

相关知识

为了完成本关任务,你需要掌握:

  1. 循环神经网络概述;
  2. 一般循环神经网络;
  3. 单向循环神经网络。
循环神经网络概述

对于我们已经学过的传统神经网络,它们能够实现分类以及标注任务,但一旦处理具有前后遗存关系的数据时,效果就不是十分理想了。这个问题主要由于传统神经网络的结构所导致。这时我们就需要一个不仅仅只依赖当前的输入,还需要结合前一时刻或后一时刻的输入作为参考。 循环神经网络就是根据这样的需求而设计的。循环神经网络的主要用途是处理和预测序列数据。循环神经网络最初就是为了刻画一个序列当前的输出与之前信息的关系。从网络结构上来看,循环神经网络会记忆之前的信息,并利用之前的信息影响后面节点的输出。也就是说,循环神经网络的隐藏层之间的节点是有连接的,隐藏层的输入不仅包含输入层的输出,还包括上一时刻隐藏层的输出。

一般循环神经网络

传统的神经网络结构一般分为三层:输入层、隐藏层、输出层。输入层的输入经过加权计算输出到隐藏层,作为隐藏层的输入。隐藏层再对从输入层得到的输入进行加权计算输入到输出层,最后通过激活函数,由输出层输出最终的结果。循环神经网络的结构与其十分的相似,都是由输入层、隐藏层和输出层构成,最大的区别在于循环神经网络的隐藏层多了一个自身到自身的环形连接,其结构如图 1 所示:


图1 循环神经网络结构示例

其中,x表示输入层,s表示隐藏层的输出,o表示输出层的值。U是输入x特征与隐藏层神经元全连接的权重矩阵,V则是隐藏层与输出层全连接的权值矩阵。o的输出由权值矩阵V和隐藏层输出s决定。s的输出不仅仅由权值矩阵U以及输入x来决定,还要依赖于新的权值矩阵W以及上一次s的输出。其中,W表示上一次隐藏层的输出到这一次隐藏层输入的权值矩阵。该层被称为循环层。

单向循环神经网络

将一般循环神经如图2所示展开便是单向循环神经网络:


图2 单向循环神经网络结构示例

对于单向循环神经网络的结构,你可以理解为网络的输入通过时间进行向后传播。当前隐藏层的输出st​除了取决于当前的输入层的输入向量xt​外,还受到上一时刻隐藏层的输出向量st+1​的影响,因此,当前时刻隐藏层的输出信息包含了 之前时刻的信息,表现出对之前信息记忆的能力 。 可以采用如下公式对单向循环神经网络进行表示 :

ot​=g(Vst​​)st​=f(Uxt​+Wst−1​)

其中ot​表示输出层的结果,g为输出层的激活函数,V为输出层的权值矩阵。st​表示隐藏层的结果,它由当前时刻的输入层输入xt​以及上一时刻隐藏层输出st−1​共同决定,U表示输入层到隐藏层的权值矩阵,W为上一时刻的值st−1​到这一次输入的权值矩阵,f为隐藏层的激活函数。循环神经网络的递归数学式如下所示:

ot​=g(Vst​)=​Vf(Uxt​+Wst−1​)=Vf(Uxt​+Wf(Uxt−1​+Wst−2​))=Vf(Uxt​+Wf(Uxt−1​+Wf(Uxt−2​+⋯)))=…​

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,完善循环神经网络的网络模型。

测试说明

平台会对你编写的代码进行测试:

测试输入:无 预期输出: init success! rnn success!

提示:

  • 循环神经网络的初始状态全部为零;
  • 隐藏层的结果需要经过激活后再传入输出层,本次实训采用tanh函数作为激活函数,可以使用torch.tanh()函数;
  • 矩阵相乘可以使用torch.matmul(a,b)函数。

开始你的任务吧,祝你成功!

第1关任务代码

import torch
    
    
def rnn(input,state,params):
    """
    循环神经网络的前向传播
    :param input: 输入,形状为 [ batch_size,num_inputs ]
    :param state: 上一时刻循环神经网络的状态,形状为 [ batch_size,num_hiddens ]
    :param params: 循环神经网络的所使用的权重以及偏置
    :return: 输出结果和此时刻网络的状态
    """
    W_xh,W_hh,b_h,W_hq,b_q = params
    """
    W_xh : 输入层到隐藏层的权重
    W_hh : 上一时刻状态隐藏层到当前时刻的权重
    b_h : 隐藏层偏置
    W_hq : 隐藏层到输出层的权重
    b_q : 输出层偏置
    """
    H = state
    ########## Begin ##########
    # 输入层到隐藏层
    H = torch.matmul(input, W_xh) + torch.matmul(H, W_hh) + b_h
    H = torch.tanh(H)
    # 隐藏层到输出层
    Y = torch.matmul(H, W_hq) + b_q
    ########## End ##########
    return Y,H
def init_rnn_state(num_inputs,num_hiddens):
    """
    循环神经网络的初始状态的初始化
    :param num_inputs: 输入层中神经元的个数
    :param num_hiddens: 隐藏层中神经元的个数
    :return: 循环神经网络初始状态
    """
    ########## Begin ##########
    init_state = torch.zeros((num_inputs,num_hiddens),dtype=torch.float32)
    ########## End ##########
    return init_state

第2关:循环神经网络简介

任务描述

本关任务:通过学习长短时记忆网络相关知识,编写实现长短时记忆网络。

相关知识

为了完成本关任务,你需要掌握:

  1. 长短时记忆网络;
  2. 门结构;
  3. 长短时记忆网络实现。
长短时记忆网络

传统的循环神经网络受限于梯度爆炸与梯度消失问题,使得网络随着输入序列的增长,抖动变得更为剧烈,导致无法学习 。长短时记忆网络( Long Short Term Memory Network, LSTM )便是为了解决此问题而被设计提出。其核心思想是通过添加一个网络内部状态c来记忆长期信息,这个新的状态我们称之为单元状态(Cell State),主要负责记忆长期信息。


图1 长短时记忆网络结构展开图

1为 LSTM 结构展开图,在某一时刻t,长短时记忆网络的神经元输入由三部分组成:当前网络的输入Xt​、上一时刻的输出st−1​以及上一时刻的单元状态ct−1​,神经元的输出为当前时刻的输出st​,当前时刻的单元状态为ct​。 如图2所示, LSTM 的核心是单元状态。单元状态像传送带一样,它贯穿整个网络却只有很少的分支,这样能保证信息不变的流过整个网络。后面会 LSTM 结构进行详细的说明。


图2 单元状态图

LSTM 能通过一种被称为门的结构对单元状态进行控制,选择性的决定让哪些信息通过。门的结构很简单,由一个 Sigmoid 层和一个点乘操作的组合而成。如图3所示:


图3 门示意图

其中黄色矩形表示 Sigmoid 层,红色圆圈代表点乘操作。

因为 Sigmoid 层的输出是01,这代表有多少信息能够流过Sigmoid 层。0表示都不能通过,1表示都能通过。 其神经元的结构如图4所示:


图4 LSTM 神经元结构示意图

其中的图标的含义如图5所示:


图5 图标示意图

Vector transfer 表示一个向量从一个节点的输出到其他节点的输入。Pointwise Operation 代表按位 Pointwise 的操作,例如向量的和。 Concatenate 表示向量的连接,Copy 表示内容被复制,然后分发到不同的位置。

门结构

一个 LSTM 里面包含三个门来控制单元状态,分别为:遗忘门、输入门和输出门。

遗忘门

LSTM 首先需要决定细胞状态需要留下那些信息,这个功能结构即遗忘门。 它主要决定上一时刻的输出ht−1​ct−1​状态是否保留到当前时刻的ct​当中。具体是通过一个 Sigmoid 层来实现。它通过查看ht−1​xt​信息来输出一个[0,1]之间的向量,该向量的值表示单元状态Ct−1​中哪些信息保留或丢弃。如图6所示:


图6 遗忘门示意图

它的输入为上一时刻的输出ht−1​与当前时刻的输入xt​,经过 Sigmoid 函数变换,得到内部当前时刻输出ft​。 具体公式表达如下 :

ft​=σ(Wf​[ht−1​,xt​]+bf​)

其中,Wf​ 表示遗忘门的权值矩阵,[ht−1​,xt​]表示两个向量纵向连接操作,bf​表示输入的偏置项。

输入门

通过遗忘门决定神经元中什么信息保留下来后,我们现在需要确定当前的输入xt​有多少信息需要保存到当前的单元状态ct​中,此功能结构为输入门。这里包含两个部分:第一,Sigmoid 层决定那些输入将要被更新。第二,一个 Tanh 层生成一个新的候选向量C~t​。这两部分的输出进行逐点相乘,从而对单元状态ct​进行更新。输入门结构如图7所示:


图7 输入门示意图

根据图7所示,输入门的计算公式如下:

it​=σ(Wi​[st−1​,xt​]+bi​)c~t​=tanh(Wc​[st−1​,xt​]+bc​)

在计算it​c~t​时,它们的权值矩阵是不同的,因此在训练的过程中需要单独训练。 通过遗忘门与输入门的计算后,我们可以对单元状态ct​进行更新操作。操作方法如图8所示:


图8 更新单元状态示意图

计算公式如下:

c=ft​∘ct−1​+it​∘c~t​

表示按元素逐乘操作。

输出门

更新完单元状态后需要根据ht−1​xt​来考虑如何将当前的信息进行输出,这部分功能由输出门完成。输出门主要来控制单元状态ct​有多少可以输出到长短时记忆网络的当前输出值ht​中,如图9所示:


图9 输出门示意图

该单元的输出主要依赖当前的神经元状态ct​,不只是单纯依赖单元状态,还需要进行一次信息过滤的处理,即由引入的 Sigmoid 层来完成。这一层将单元状态经过 Tanh 层处理后的数据进行元素相乘操作,将得到的ht​有选择地输出到下一时刻和对外输出。具体计算公式如下 :

ot​=σ(Wo​[st−1​,xt​]+bo​)st​=ot​∘tanh(ct​)

长短时记忆网络实现

LSTM 的实现步骤:

  1. 通过遗忘门,计算允许继续通过神经元的信息;

    F=sigmoid(Wxf​X+Whf​H+bf​)

  2. 通过输入门,计算当前输入中需要保留到单元状态的信息;

    IC~C​=sigmoid(Wxi​X+Whi​H+bi​)=tanh(Wxc​X+Whc​H+bc​)=F∘C+I∘C~​

  3. 通过输出门,计算需要输出的信息;

    OHnew​​=sigmoid(Wxo​X+Who​H+bo​)=O∘tanh(C)​

  4. 通过输出层计算输出。

    Y=Whq​Hnew​+bq​

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,编写实现 LSTM 的遗忘门、输入门、输出门。

测试说明

平台会对你编写的代码进行测试:

测试输入:无 预期输出: True

开始你的任务吧,祝你成功!

第2关任务代码

import torch
 
def lstm(X,state,params):
    """
    LSTM
    :param X: 输入
    :param state: 上一时刻的单元状态和输出
    :param params: LSTM 中所有的权值矩阵以及偏置
    :return: 当前时刻的单元状态和输出
    """
    W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q = params
    """
    W_xi,W_hi,b_i : 输入门中计算i的权值矩阵和偏置
    W_xf,W_hf,b_f : 遗忘门的权值矩阵和偏置
    W_xo,W_ho,b_o : 输出门的权值矩阵和偏置
    W_xc,W_hc,b_c : 输入门中计算c_tilde的权值矩阵和偏置
    W_hq,b_q : 输出层的权值矩阵和偏置
    """
    #上一时刻的输出 H 和 单元状态 C。
    (H,C) = state
    ########## Begin ##########
    # 遗忘门
    F = torch.matmul(X, W_xf) + torch.matmul(H, W_hf) + b_f
    F = torch.sigmoid(F)
    # 输入门
    I = torch.sigmoid(torch.matmul(X,W_xi)+torch.matmul(H,W_hi) + b_i)
    C_tilde = torch.tanh(torch.matmul(X, W_xc) + torch.matmul(H, W_hc) + b_c)
    C = F * C + I * C_tilde
    # 输出门
    O = torch.sigmoid(torch.matmul(X,W_xo)+torch.matmul(H,W_ho) + b_o)
    H = O * C.tanh()
    # 输出层
    Y = torch.matmul(H,W_hq) + b_q
    ########## End ##########
    return Y,(H,C)

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐