精华内容
下载资源
问答
  •  

     

     

     

     

     

     

     

    展开全文
  • 循环神经网络(Recurrent Neural Networks, RNN)主要用于时序数据,最常见的时序数据如文章,视频等,ttt时刻的数据与t−1t-1t−1时刻的数据存在内在的联系。RNN模型能够对这样的时序数据建模。 2. 算法原理 RNN...

    1. 概述

    循环神经网络(Recurrent Neural Networks, RNN)主要用于时序数据,最常见的时序数据如文章,视频等,tt时刻的数据与t1t-1时刻的数据存在内在的联系。RNN模型能够对这样的时序数据建模。

    2. 算法原理

    RNN模型的基本结构如下所示(图片来自参考文献):

    在这里插入图片描述
    如上图所示,循环神经网络通过使用自带反馈的神经元,能够处理任意长度的时序数据,对此结构按照时间展开的形式如下所示(图片来自参考文献):

    在这里插入图片描述

    2.1. RNN的结构

    上图中给出了RNN的内部结构,RNN根据输入输出主要可以分为以下三种:

    • 多输入单输出,如文本的分类问题;
    • 单输入多输出,如描述图像;
    • 多输入多输出,又分为等长或者不等长两种情况,等长如机器作诗,不等长如seq2seq模型;

    这里以多输入单输出的情况为例,多输入单输出的具体结构如下所示:

    在这里插入图片描述

    2.2. RNN的计算过程

    假设对于一个长度为TT的序列{x1,x2,,xT}\left \{ x_1,x_2,\cdots ,x_T \right \},其中xi=(xi,1,xi,2,,xi,n)x_i=\left ( x_{i,1},x_{i,2},\cdots ,x_{i,n} \right )是一个nn维的向量,假设RNN的输入xx的维度为n×1n\times 1,隐含层状态hth_t的维度为H×1H\times 1,RNN的状态更新公式为:

    ht=f(Uht1+Wxt+b)h_t=f\left ( Uh_{t-1}+Wx_t+b \right )

    通常h0h_0会设置为全00的向量。模型中的参数UU的维度为H×HH\times HWW的维度为H×nH\times nbb的维度为H×1H\times 1,对于具体的分类问题,其输出为:

    y^=softmax(Woht+bo)\hat{y}=softmax(W_oh_t + b_o)

    假设对于分类问题有cc个类别,则参数WoW_o的维度为c×Hc\times Hbob_o的维度为c×1c\times 1。最终的损失函数为:

    J(U,W,b,Wo,bo)=1mi=1mL(y(i),y^(i))J\left ( U,W,b,W_o,b_o \right )=\frac{1}{m}\sum _{i=1}^mL\left ( y^{(i)},\hat{y}^{(i)} \right )

    其中

    L(y(i),y^(i))=j=1cyj(i)logy^j(i)L\left ( y^{(i)},\hat{y}^{(i)} \right )=-\sum_{j=1}^{c}y_j^{(i)}log\: \hat{y}_j^{(i)}

    2.3. RNN中参数的求解

    对于RNN模型,通常使用BPTT(BackPropagation Through Time)的训练方式,BPTT也是重复的使用链式法则,对于RNN而言,损失函数不仅依赖于当前时刻的输出层,也依赖于下一时刻。为了简单起见,以一个样本为例,此时的损失函数可以记为L(y,y^)L\left ( y,\hat{y} \right ),模型的参数为U,W,b,Wo,boU,W,b,W_o,b_o,具体的求解过程如下所示:

    首先对y^\hat{y}重新定义,样本属于第(i)(i)个类别的预测值为:

    y^(i)=eWoiht+boil=1ceWolht+bol\hat{y}_{(i)}=\frac{e^{W_{oi}h_t+b_{oi}}}{\sum _{l=1}^{c}e^{W_{ol}h_t+b_{ol}}}

    LWoi\frac{\partial L}{\partial W_{oi}}Lboi\frac{\partial L}{\partial b_{oi}}分别为:

    LWoi=(y(i)y^(i))ht\frac{\partial L}{\partial W_{oi}}=-\left ( y_{(i)}-\hat{y}_{(i)} \right )h_t

    Lboi=(y(i)y^(i))\frac{\partial L}{\partial b_{oi}}=-\left ( y_{(i)}-\hat{y}_{(i)} \right )

    假设ff为tanh,而tanh(a)tanh(a)的导数为1tanh(a)21-tanh(a)^2,以LU\frac{\partial L}{\partial U}为例:

    LU=Ly^y^hthtU+Ly^y^hththt1ht1U++Ly^y^hththt1h1h0\frac{\partial L}{\partial U}=\frac{\partial L}{\partial \hat{y}}\cdot \frac{\partial \hat{y}}{\partial h_t}\cdot \frac{\partial h_t}{\partial U}+\frac{\partial L}{\partial \hat{y}}\cdot \frac{\partial \hat{y}}{\partial h_t}\cdot \frac{\partial h_t}{\partial h_{t-1}}\cdot \frac{\partial h_{t-1}}{\partial U}+\cdots +\frac{\partial L}{\partial \hat{y}}\cdot \frac{\partial \hat{y}}{\partial h_t}\cdot \frac{\partial h_t}{\partial h_{t-1}}\cdots \frac{\partial h_1}{\partial h_0}

    htht1=[1tanh(ht)2]U\frac{\partial h_t}{\partial h_{t-1}}=\left [ 1-tanh\left ( h_t \right )^2 \right ]\cdot U,这是个小于1的数,从上面的公式我们发现,时序数据越长,后面的梯度就趋于0。

    2.4. RNN存在的问题

    从上述的BPTT过程来看,RNN存在长期依赖的问题,由于反向传播的过程中存在梯度消失或者爆炸的问题,简单的RNN很难建模长距离的依赖关系。

    参考文献

    展开全文
  • 文章列表 1.深度学习基础模型算法原理及编程实现–01.感知机. 2.深度学习基础模型算法原理及编程实现–02.线性单元 ....3.深度学习基础模型算法原理及编程实现–03.全链接 ....循环神经网络. 9.深度...

    文章列表
    1.深度学习基础模型算法原理及编程实现–01.感知机.
    2.深度学习基础模型算法原理及编程实现–02.线性单元 .
    3.深度学习基础模型算法原理及编程实现–03.全链接 .
    4.深度学习基础模型算法原理及编程实现–04.改进神经网络的方法 .
    5.深度学习基础模型算法原理及编程实现–05.卷积神经网络.
    6.深度学习基础模型算法原理及编程实现–06.循环神经网络.
    9.深度学习基础模型算法原理及编程实现–09.自编码网络.
    10.深度学习基础模型算法原理及编程实现–10.优化方法:从梯度下降到NAdam.
    11.深度学习基础模型算法原理及编程实现–11.构建简化版的tensorflow—MiniFlow【实现MLP对MNIST数据分类】.

    深度学习基础模型算法原理及编程实现–06.循环神经网络

    前面介绍的全连接神经网络和卷积神经网络,都只能单独的取处理一个个的输入,前一个输入和后一个输入是完全没有关系的。但在处理序列信息时,前后输入是相关的,如语义理解需要将前后的词语贯联起来;视频处理也需要前后多帧图像的分析。这时就需要引入深度学习领域中循环神经网络(Recurrent Neural Network)来解决问题。正如全连接及卷积神经网络可以处理大小可变的图像,循环神经网络也可以处理长度变化的序列问题。

    循环神经网络简介

    RNN在自然语言处理中应用的较多,比如语言模型,通过给定一句话前面的部分,预测接下来最有可能的一个词是啥。在语音转文本(STT)的应用中,声学模型输出的结果可能是若干个可能的候选词,这时就需要语言模型从中选择一个最可能的词;图像到文本的识别(orc)也是类似的。
    使用RNN之前,语言模型主要采用N-Gram,N是一个正整数,表示一个词出现的概率只与前面N个词汇相关。而一个词的出现可能与前面整个句子的语境都相关,且句子的长度可能很长,从而只能增加N;但N的增大会导致训练模型大小呈指数级增加。
    RNN理论上可以往前(后)看任意多个词。循环神经网络种类繁多,。。。

    7.2 循环神经网络的设计原理

    说到这里你可能一头雾水,不知道为什么循环神经网络的节点要设计成这样,这里给大家一个直观的理解,之前介绍的全连接和卷积都是前向网络,然后通过隐藏层向前传播到输出层。在前馈网络中,输入没有顺序可言。
    这里写图片描述
    可用下面的公式表示上图前向神经网络的计算方法:
    这里写图片描述
    循环神经网络就是为了解决序列问题而提出的,可以简单将其理解为由多个前向网络并排组成的网络,并且隐藏层之间存在信息传递(路由),其网络结构示意如下图所示。
    这里写图片描述
    为什么要这么做呢,这里举一个例子:预测steep一词中的下一个字母,为了简化问题,可假设整个字母表由 S、T、E 和 P 组成,从正常的前馈网络开始,传入字母S期望的输出为T,传入T期望获得E,现在传入E,在这个词中E后面跟另一个E或P,而这里显示的网络没有足够的信息来决定预测哪一个字母是正确的结果。要解决这个问题,需要获得关于字母历史序列的信息,一个很显然的方法是将上一步的隐藏层输出路由到下一个隐藏层的输入中,即将隐藏层输出信息做为下一隐藏层的输入信息的一部分。所以现在,当网络看到E时,由于隐藏层之间信息的路由,网络知道字母序列在前面看到了S、T和E,所以下一个字母应该为E,就不会在E和P之间迷惑了,这就是循环神经网络。

    7.2 循环神经网络模型

    7.2.1 RNN VS CNN

    (1) CNN单个隐藏层中的节点之间是没有相连关系的,但RNN中是有的。
    (2) CNN中隐藏层输入仅包含当前的输入,而RNN隐藏层的输入不仅包含当前的输入,还会对前面输入的信息进行记忆并应用于当前的输出计算

    7.2.2 单向循环神经网络单个节点

    单向循环神经网络隐藏层中的神经元节点模型可表示如下:

    这里写图片描述
    这里写图片描述
    这里写图片描述

    从上式可以看出RNN的输出受前面所有时刻输出信息的影响,这就说明了为什么循环神经网络各个节点会对前面输入的信息进行记忆并应用于当前输出的原因。

    7.2.3 双向循环神经网络单个节点

    对语言模型而言,如果想对某个有上下文的句子填入某个词,是要同时观察前面和后面的信息的,因此需要双向神经网络。双向神经网络隐藏层中第k层第t个时刻的神经元节点模型可表示如下:


    这里写图片描述
    这里写图片描述

    7.2.4 循环神经网络

    将上面的双向循环神经网络隐藏层扩展成 层 个时刻的深度循环神经网络模型,当 ,即隐藏层深度大于等于2时,循环神经网络又可称为深度神经网络,其模型可表示如下:


    这里写图片描述

    这里写图片描述

    7.3 循环神经网络的训练

    循环神经网络的训练算法:BPTT(Backpropagation through time,随时间反向传播)
    BPTT算法是针对循环层的训练算法,它的基本原理和BP算法是一样的,也包含同样的三个步骤:
    1. 前向计算每个神经元的输出值;
    2. 反向计算每个神经元的误差项值,它是误差函数E对神经元j的加权输入的偏导数;
    3. 计算每个权重的梯度。
    最后再用随机梯度下降算法更新权重。

    7.3.1 前向计算

    前向计算在式(8.6)中已经描述过了,只需将其拆分开来即可。

    7.3.1.1 输入层


    这里写图片描述

    7.3.1.2 隐藏层


    这里写图片描述

    7.3.1.3 输出层


    这里写图片描述

    7.3.2 误差项计算

    BTPP算法将第l层t时刻的误差项值沿两个方向传播,一个方向是沿隐藏层深度方向将其传递到上一层网络,这部分只误差项只和权重矩阵U有关;另一个是方向是将其沿时间轴传递到初始时刻,这部分误差项只和权重矩阵W有关。

    7.3.2.1 误差项沿时间轴的传递规律


    这里写图片描述

    7.3.2.2 误差项沿网络深度的传递规律
    7.3.2.2.1 隐藏层沿网络深度的误差项


    这里写图片描述

    7.3.2.2.2 输出层误差项


    这里写图片描述

    7.3.3 权重矩阵梯度更新


    这里写图片描述


    这里写图片描述

    7.4 梯度爆炸和消失

    基本的循环神经网络不能较好的处理较长序列,因为其在训练过程中很容易发生梯度爆炸和梯度消失,这导致训练时梯度不能在较长序列中一直传递下去,从而使RNN无法捕捉到长距离的影响。
    为什么会产生梯度爆炸和消失的现象呢?由式(7.15)可知,

    这里写图片描述

    式中β为矩阵模的上界,如果N-n很大,也就是历史信息较长的话,β大于1或小于1会分别导致梯度爆炸及消失。通常梯度爆炸更容易处理,因为梯度爆炸时会报NaN错误,可设置梯度阈值来限制较大梯度;而梯度消失较难处理一些。通常有三种方法处理梯度消失问题:
    1.合理的初始化权重值。初始化权重,使每个神经元尽可能不要取极大或极小值,以躲开梯度消失的区域。
    2.使用relu代替sigmoid和tanh作为激活函数。
    3.使用其他结构的RNNs,比如长短时记忆网络(LTSM)和Gated Recurrent Unit(GRU)。

    7.5 小节

    至此,我们讲完了基本的循环神经网络、它的训练算法:BPTT。由于基本的循环神经网络存在梯度爆炸和梯度消失问题,并不能真正的处理好长距离的依赖(虽然有一些技巧可以减轻这些问题),但真正得到广泛的应用的是循环神经网络的一个变体:长短时记忆网络。它内部有一些特殊的结构,可以很好的处理长距离的依赖。下面给出了数字加法的RNN实现(python版本),由于该问题比较简单,只需一个隐藏层就可以得到较好的结果,但为了验证文中公式的准确性,分别考虑了隐藏层为1-4层的情况。运行结果如下:
    这里写图片描述

    详细代码如下:

    #-*- coding: UTF-8 -*- 
    from RNN import *
    import numpy as np
    binary_dim = 8
    alpha = 0.1
    rnn = RNN(binary_dim, 2, 16, 1, SigmoidActivator)
    largest_number = pow(2,binary_dim)
    for j in range(20000):
        a_int = np.random.randint(largest_number/2)
        a_bin = np.unpackbits(np.array([[a_int]],dtype=np.uint8).T,axis=1)
        b_int = np.random.randint(largest_number/2)
        b_bin = np.unpackbits(np.array([[b_int]],dtype=np.uint8).T,axis=1)
        X = np.vstack((a_bin,b_bin)).T
        c_int = a_int + b_int
        y_bin = np.unpackbits(np.array([[c_int]],dtype=np.uint8).T,axis=1)[0]
        pre_bin = rnn.forward(X[range((X.shape[0]-1),-1,-1),:])
        err = rnn.backward(y_bin[range((y_bin.shape[0]-1),-1,-1)])
        rnn.gradeUpdata(alpha)
        if(j%100 == 0):
            out = 0
    #        for index,x in enumerate(reversed(pre_bin)):
            for index,x in enumerate(pre_bin):
                out += x*pow(2,index)
            if(np.abs(out - a_int - b_int) < 1e-5):
                print('%6d' %(j), 'step err:%0.3f  %5d' %(err[0], a_int), '+%5d' %(b_int), '=%5d' %(int(out)), '_right')
            else:
                print('%6d' %(j), 'step err:%0.3f  %5d' %(err[0], a_int), '+%5d' %(b_int), '=%5d' %(int(out)), '_wrong')
    #-*- coding: UTF-8 -*- 
    from activators import *
    import numpy as np
    #alpha = 0.1
    class NodeNet(object):
        def __init__(self, iInputDim, iHiddenDim):
            self.m_dOutputArray = np.zeros([1, iHiddenDim])
            self.m_dDeltaArray  = np.zeros([1, iHiddenDim])
            self.m_dInputArray  = np.zeros([1, iInputDim])
    
    class OnewayRNNLayer(object):
        def __init__(self, iNodeNum, iInputDim, iHiddenDim, activator):
            self.m_NodeSet                 = [NodeNet(iInputDim, iHiddenDim) for _ in range(iNodeNum)]
            self.m_iNodeNum                = iNodeNum
            self.m_iInputDim               = iInputDim
            self.m_iHiddenDim              = iHiddenDim
            self.m_WForPreTime  = 2*np.random.random([iHiddenDim, iHiddenDim])-1
    #        self.m_WForPreTime  = np.random.normal(0, 1/np.sqrt(iHiddenDim*iHiddenDim), [iHiddenDim, iHiddenDim])
            self.m_WForPreLayer = 2*np.random.random([iInputDim, iHiddenDim])-1
    #        self.m_WForPreLayer = np.random.normal(0, 1/np.sqrt(iInputDim*iHiddenDim), [iInputDim, iHiddenDim])
            self.m_WGradForPreTime  = np.zeros_like(self.m_WForPreTime)
            self.m_WGradForPreLayer = np.zeros_like(self.m_WForPreLayer)
            self.m_activator               = activator
            self.m_inputArray       = np.array([iNodeNum, iInputDim])
        def forward(self, inputArray):
            self.m_inputArray = inputArray
            preTimeArray = np.zeros([1, self.m_iHiddenDim])
            self.m_outArray = np.zeros([self.m_iNodeNum,self.m_iHiddenDim])
            for i in range(self.m_iNodeNum):
                self.m_NodeSet[i].m_dOutputArray = self.m_activator.forward(np.dot(preTimeArray,self.m_WForPreTime) + np.dot(inputArray[i].reshape(1,inputArray.shape[1]),self.m_WForPreLayer))
                self.m_outArray[i,:] = self.m_NodeSet[i].m_dOutputArray 
                preTimeArray = self.m_NodeSet[i].m_dOutputArray
            return self.m_outArray
        def backward(self, inputDelta, WGradForPreLayer):
            nextTimeArray = np.zeros([1, self.m_iHiddenDim])
            delta = []
            for i in range(self.m_iNodeNum-1,-1,-1):
    #            delta.append(np.multiply(np.dot(nextTimeArray, self.m_WForPreTime.T) + np.dot(inputDelta[i], self.m_WGradForPreLayer.T), self.m_activator.backward(self.m_NodeSet[i].m_dOutputArray)))
                delta.append(np.multiply(np.dot(nextTimeArray, self.m_WForPreTime.T) + np.dot(inputDelta[i], WGradForPreLayer.T), self.m_activator.backward(self.m_NodeSet[i].m_dOutputArray)))
                nextTimeArray = delta[-1]
            delta.reverse() #delta是从后向前求的,而其在list中是依次添加的,所以需逆序后才是按原有时间序列排序的delta
            self.m_WGradForPreTime  = np.zeros_like(self.m_WForPreTime)
            self.m_WGradForPreLayer = np.zeros_like(self.m_WForPreLayer)
            for i in range(self.m_iNodeNum-1,-1,-1):
                if(i != 0):
                    self.m_WGradForPreTime += np.dot(self.m_NodeSet[i-1].m_dOutputArray.T, delta[i])
                elif(i == 0):
                    self.m_WGradForPreTime += np.dot(np.zeros_like(self.m_NodeSet[0].m_dOutputArray).T, delta[i]) #由于被加项是0矩阵,因此该项可以去掉
    #            self.m_WGradForPreTime += np.dot(self.m_NodeSet[i].m_dOutputArray.T, delta[i])
                self.m_WGradForPreLayer += np.dot(np.array([self.m_inputArray[i]]).T, delta[i])
            return delta
    
        def gradeUpdata(self, alpha):
            self.m_WForPreTime -= alpha*self.m_WGradForPreTime 
            self.m_WForPreLayer -= alpha*self.m_WGradForPreLayer 
    
    class RNN(object):
        def __init__(self, iNodeNum, iInputDim, iHiddenDim, iOutputDim, activator):
            self.m_outputActivator = activator
            self.m_layers = [
                             OnewayRNNLayer(iNodeNum, iInputDim, iHiddenDim, activator),
    #                         OnewayRNNLayer(iNodeNum, iHiddenDim, iHiddenDim*2, activator),
    #                         OnewayRNNLayer(iNodeNum, iHiddenDim*2, iHiddenDim, activator),
    #                         OnewayRNNLayer(iNodeNum, iHiddenDim, iHiddenDim, activator)
                             ];
            self.m_dOutputArray = np.zeros([iNodeNum, iOutputDim])
            self.m_WOutputLayer = 2*np.random.random([iHiddenDim, iOutputDim])-1
    #        self.m_WOutputLayer = np.random.normal(0, 1/np.sqrt(iHiddenDim*iOutputDim), [iHiddenDim, iOutputDim])
            self.m_iOutputNum = iOutputDim
            self.m_iNodeNum   = iNodeNum
    
        def forward(self, inputArray):
            for i in range(len(self.m_layers)):
                inputArray = self.m_layers[i].forward(inputArray)
            for i in range(self.m_layers[-1].m_iNodeNum):
                self.m_dOutputArray[i] = self.m_outputActivator.forward(np.dot(self.m_layers[-1].m_NodeSet[i].m_dOutputArray, self.m_WOutputLayer))
            return np.round(self.m_dOutputArray)
    
        def backward(self, labelArray):
            err = 0
            deltaA = np.zeros([self.m_iNodeNum, self.m_iOutputNum])
            self.m_WGradOutputLayer = np.zeros_like(self.m_WOutputLayer)
            for i in range(self.m_layers[-1].m_iNodeNum):
                deltaOutput = self.m_dOutputArray[i] - labelArray[i]
                deltaA[i] = np.dot(deltaOutput, self.m_layers[-1].m_activator.backward(self.m_dOutputArray[i]))
                self.m_WGradOutputLayer += self.m_layers[-1].m_NodeSet[i].m_dOutputArray.T * deltaA[i]  #矩阵相城用dot, 矩阵与数相乘直接用*
                err += np.abs(deltaOutput)
    
            inputDelta = deltaA
            hlay = self.m_layers[0]
            nextTimeArray = np.zeros([1, hlay.m_iHiddenDim])
            delta = []
            for i in range(hlay.m_iNodeNum-1,-1,-1):
                delta.append(np.multiply(np.dot(nextTimeArray, hlay.m_WForPreTime.T) + np.dot(inputDelta[i], self.m_WOutputLayer.T)    , hlay.m_activator.backward(hlay.m_NodeSet[i].m_dOutputArray)))
    #           delta.append(np.multiply(np.dot(nextTimeArray, hlay.m_WForPreTime.T) + np.dot(inputDelta[i], self.m_WGradForPreLayer.T), hlay.m_activator.backward(hlay.m_NodeSet[i].m_dOutputArray)))
                #注意,隐藏层的最后一层用到输出层中的权重矩阵
                nextTimeArray = delta[-1]
            delta.reverse() #delta是从后向前求的,而其在list中是依次添加的,所以需逆序后才是按原有时间序列排序的delta
            hlay.m_WGradForPreTime  = np.zeros_like(hlay.m_WForPreTime)
            hlay.m_WGradForPreLayer = np.zeros_like(hlay.m_WForPreLayer)
            for i in range(hlay.m_iNodeNum-1,-1,-1):
                if(i != 0):
                    hlay.m_WGradForPreTime += np.dot(hlay.m_NodeSet[i-1].m_dOutputArray.T, delta[i])
                elif(i == 0):
                    hlay.m_WGradForPreTime += np.dot(np.zeros_like(hlay.m_NodeSet[0].m_dOutputArray).T, delta[i]) #由于被加项是0矩阵,因此该项可以去掉
                hlay.m_WGradForPreTime += np.dot(hlay.m_NodeSet[i].m_dOutputArray.T, delta[i])
                hlay.m_WGradForPreLayer += np.dot(np.array([hlay.m_inputArray[i]]).T, delta[i])
    
            if(len(self.m_layers)>=2):
                for i in range(len(self.m_layers)-2,-1,-1):
                    delta = self.m_layers[i].backward(delta, self.m_layers[i+1].m_WForPreLayer)
            return err
    
        def gradeUpdata(self, alpha):
            self.m_WOutputLayer -= alpha*self.m_WGradOutputLayer
            for i in range(len(self.m_layers)):
                self.m_layers[i].gradeUpdata(alpha)
    

    由于个人也是刚刚系统的接触深度学习,有不对的地方还希望广大同学告诉我,希望大家多多指导。
    python版本:https://pan.baidu.com/s/1qZLJ7Gg
    C++版本:待上传

    展开全文
  • RNN网络结构 上图就是一个最简单的RNN,图看上去密密麻麻,有点...相邻的两层是全连接网络,比如输入层到循环层,两层中每个神经元都互相连接。数据会从输入层进入到网络中,与ANN不同的是,这里的一个样本是一个...

            因循环神经网络基于ANN之上,理解ANN有助于理解RNN,所以阅读此文,建议先阅读《机器学习之人工神经网络(ANN)》

    RNN网络结构

    上图就是一个最简单的RNN,图看上去密密麻麻,有点玄虚。下面细细道来。首先我们看图的左边,这个网络分为三层,输入层(紫色表示),隐藏层(绿色表示),输出层(黄色表示),其中隐藏层在RRN中也称之为循环层,为什么称之为循环后,后面再说。相邻的两层是全连接网络,比如输入层到循环层,两层中每个神经元都互相连接。数据会从输入层进入到网络中,与ANN不同的是,这里的一个样本是一个序列,举个例子,假设序列的长度为T,输入的一个样本为\mathbf{x}=\mathbf{(x_{1},x_{2},...,x_{T})},每个分量\mathbf{x_t}=(x_{t1},x_{t2},...,x_{tn})(看成列向量,本文如无特殊说明,单个向量都是列向量)。每个\mathbf{x_t}并不是同时输入到网络中,而是按照时间先后输入,它们之间有时间顺序,比如时刻t=1时,输入\mathbf{x_1},t=2时刻输入\mathbf{x_2},依次输入。这和ANN是不同的,在ANN中,我们之间\mathbf{x_t}之间是相互独立的,输入没有先后顺序。现在我们来看数据在RNN网络中是如何流动的?假设在t=1时刻我们将数据\mathbf{x_{1}}输入到了网络中,在隐藏层会经过线性加权和激活函数非线性处理,如下:

    \mathbf{u}_1=W_{xh}\mathbf{x}_1+\mathbf{b}_h

    \mathbf{h_1}=f(\mathbf_{u_1})

    其中W_{xh}\mathbf{b}_h分别是输入层到循环层的权重矩阵和偏置向量。

    \mathbf{h_1}就是t=1时刻循环层的输出,它有两个去向:

    (1)第一个是流向输出层,在输出层也经过线性加权和非线性处理,其中非线性处理可以没有,不失一般性,我们假设有非线性处理记为g,最后输出层的输出如下:

    \mathbf{v}_1=W_{0}\mathbf{h}_1+\mathbf{b}_0

    \mathbf{y^*_1}=g(\mathbf_{v_1})

    其中W_{0}\mathbf{b}_0分别是循环层到输出层的权重矩阵和偏置向量。\mathbf{y^*_1}是当前时刻的最终输出结果。

    (2)第二个是流向同一层的所有神经元(包括自己)。作为下一个时刻(也就是t=2)循环层每个神经元的一部分输入,后面我们再说。

    当t=2时刻时,我们再输入层输入数据\mathbf{x_2},这个数据流向循环层,这个时候循环层不仅仅把\mathbf{x_2}作为输入,它还把上一时刻当前循环层的输出\mathbf{h_1}作为输入,也就是循环层每个神经元有两部分输入,分别为\mathbf{x_2}\mathbf{h_1},如下:

    \mathbf{u}_2=W_{xh}\mathbf{x}_2+W_{hh}\mathbf{h}_1+\mathbf{b}_h

    \mathbf{h_2}=f(\mathbf_{u_2})

    其中W_{hh}循环层到循环层的权重矩阵。与t=1时刻相同,循环层的输出\mathbf{h_2}也是有两个流向,第一个是输出层:

    \mathbf{v}_2=W_{0}\mathbf{h}_2+\mathbf{b}_0

    \mathbf{y^*_2}=g(\mathbf_{v_2})

    另一个是流向下一个时刻的当前循环层。一直这样下次,直到t=T时刻,数据\mathbf{x_T}输入网络,最终输出:

    \mathbf{v}_T=W_{0}\mathbf{h}_T+\mathbf{b}_0

    \mathbf{y^*_T}=g(\mathbf_{v_T})

    理解了数据的流动,再来看上面这个图就不难了,其中左边表示的是t-1时刻的神经网络的情况,右边表示的是t时刻神经网络的情况,左右两个网络实际是同一个网络,只是处于不同的时刻而已。连接循环层之间的橘黄色,红色和绿色实线表示\mathbf{h}_{t-1}流向下一时刻的循环层。循环神经网络也因此得名。这也是RNN和ANN不同之处。RNN网络表征了在不同时刻,循环层是相互依赖的,这正好将数据之间的依赖性通过神经网络的关系描述出来了。如果将每一层都看成一个点,那么整个数据流动的神经网络示意图如下:

     

    权重矩阵和偏置向量

            根据上面的数据流动,我们很容易得到任意时刻t的数据变换情况,如下:

    循环层线性加权:\mathbf{u}_t=W_{xh}\mathbf{x}_t+W_{hh}\mathbf{h}_{t-1}+\mathbf{b}_h

    循环层非线性处理:\mathbf{h}_t=f(\mathbf_{u_t})

    输出层线性加权:\mathbf{v}_t=W_{0}\mathbf{h}_t+\mathbf{b}_0

    输出层非线性处理:\mathbf{y^*}_t=g(\mathbf{v}_t)

    和ANN类似,首先我们构建RNN的损失函数,对于输入样本\mathbf{x}=\mathbf{(x_{1},x_{2},...,x_{T})},每个\mathbf{x_t}对应一个输出\mathbf{y}^*_t,并且假设\mathbf{x_t}对应的真实值为\mathbf{y}_t,对于k个类的分类问题,如果\mathbf{x_t}属于第i个类,那么\mathbf{y}_t是一个k维向量,第i个分量为1,其余分量为0。对于t时刻,RNN的输出值\mathbf{y}^*_t和真实值\mathbf{y}_t的距离可以定义为t时刻的误差:

    L_t=||\mathbf{y}^*_t-\mathbf{y}_t||^2

    对于长度为T的整个样本\mathbf{x}来说,总的误差就是

    L=\sum_{i=1}^TL_t=\sum_{i=1}^T||\mathbf{y}^*_t-\mathbf{y}_t||^2

    上面从距离的角度给出了一个损失函数。下面我们再从概率的角度给出RNN的另一个损失函数。这个时候,RNN的输出层非线性处理g取softmax函数,也就是说\mathbf{y}^*_t是经过softmax处理过的输出了,所以它的第i个分量就可以看成属于第i个类的概率了。

    \mathbf{y}^T_t\mathbf{y}^*_t乘积之后也就是属于第i个类的概率。\mathbf{y}^T_t\mathbf{y}^*_t最大化是我们希望的,所以我们希望-\mathbf{y}^T_t\mathbf{y}^*_t越小越好,并且ln函数不影响单调性,所以可以使用下面这个量来刻度损失函数:

    L_t=-\mathbf{y}^T_tln\mathbf{y}^*_t

    它就是常见的交叉熵损失函数。那么整个序列\mathbf{x}的总误差就是:

    L=-\sum_{i=1}^T\mathbf{y}^T_tln\mathbf{y}^*_t

    到这里我们给RNN构建了两种损失函数。接下来就是计算损失函数对权重矩阵和偏置向量的梯度,也就是如下几个量:

    \frac{\partial L}{\partial W_{xh}}\frac{\partial L}{\partial W_{hh}}\frac{\partial L}{\partial W_{0}}\frac{\partial L}{\partial \mathbf{b}_{h}}\frac{\partial L}{\partial \mathbf{b}_{0}}

    下面逐个推导。先推导输出层的权重矩阵和偏置向量的梯度,如下:

    (1)\frac{\partial L}{\partial W_{0}}\frac{\partial L}{\partial \mathbf{b}_{0}}

    这个是循环层到输出层的权重矩阵和偏置向量的梯度,注意到循环层到输出层的网络结构和ANN是一样的,所以根据ANN的结果和

    \mathbf{v}_t=W_{0}\mathbf{h}_t+\mathbf{b}_0

    得到:

    \frac{\partial L}{\partial \mathbf{b}_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial \mathbf{b}_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial \mathbf{v}_{t}}

    \frac{\partial L}{\partial W_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial W_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial \mathbf{v}_{t}}\mathbf{h}_{t}^T

    输出层的权重和偏置项梯度都依赖于\frac{\partial L_t}{\partial \mathbf{v}_{t}},而根据

    L_t=||\mathbf{y}^*_t-\mathbf{y}_t||^2\mathbf{y^*}_t=g(\mathbf{v}_t)

    即:L_t=||g(\mathbf{v}_t)-\mathbf{y}_t||^2,容易求得:\frac{\partial L_t}{\partial \mathbf{v}_{t}}

     

    然后推导循环层的权重矩阵和偏置项的梯度,如下:

    (2)\frac{\partial L}{\partial W_{xh}}\frac{\partial L}{\partial W_{hh}}\frac{\partial L}{\partial \mathbf{b}_{h}}

    因为L是关于\mathbf{u}_1,\mathbf{u}_2,...,\mathbf{u}_T的函数,而且每个\mathbf{u}_t是关于W_{xh}的函数,且\mathbf{u}_t=W_{xh}\mathbf{x}_t+W_{hh}\mathbf{h}_{t-1}+\mathbf{b}_h,根据链式法则得到:

    \frac{\partial L}{\partial W_{xh}}=\sum_{i=1}^T\frac{\partial L}{\partial \mathbf{u}_t}\frac{\partial \mathbf{u}_t}{\partial W_{xh}}=\sum_{i=1}^T\frac{\partial L}{\partial \mathbf{u}_t}\mathbf{x}_t^T

    \frac{\partial L}{\partial W_{hh}}=\sum_{i=1}^T\frac{\partial L}{\partial \mathbf{u}_t}\frac{\partial \mathbf{u}_t}{\partial W_{hh}}=\sum_{i=1}^T\frac{\partial L}{\partial \mathbf{u}_t}\mathbf{h}_{t-1}^T

    \frac{\partial L}{\partial \mathbf{b}_{h}}=\sum_{i=1}^T\frac{\partial L}{\partial \mathbf{u}_t}\frac{\partial \mathbf{u}_t}{\partial \mathbf{b}_{h}}=\sum_{i=1}^T\frac{\partial L}{\partial \mathbf{u}_t}

    我们发现上面三个式子中,都含有\frac{\partial L}{\partial \mathbf{u}_t},实际它是总损失L对中间变量\mathbf{u}_t的梯度,简记为\mathbf{\delta }_t=\frac{\partial L}{\partial \mathbf{u}_t}(注这里\mathbf{\delta }_t是向量,无法黑体表示)

    上面三个式子变为:

    \frac{\partial L}{\partial W_{xh}}=\sum_{i=1}^T\delta_t\mathbf{x}_t^T

    \frac{\partial L}{\partial W_{hh}}=\sum_{i=1}^T\delta_t\mathbf{h}_{t-1}^T

    \frac{\partial L}{\partial \mathbf{b}_{h}}=\sum_{i=1}^T\delta_t

    下面来计算误差\mathbf{\delta }_t,做法是找出\mathbf{\delta }_t\mathbf{\delta }_{t+1}两者的递推关系。先计算t时刻的损失L_t对中间变量\mathbf{u}_{t-1}的梯度\frac{\partial L_t}{\partial \mathbf{u}_{t-1}}

    \mathbf{u}_t=W_{xh}\mathbf{x}_t+W_{hh}\mathbf{h}_{t-1}+\mathbf{b}_h

    \mathbf{h}_{t-1}=f(\mathbf{u}_{t-1})             

    L_t看成是\mathbf{h}_{t-1}的复合函数,根据链式法则(或者直接ANN结论,参见《机器学习之人工神经网络(ANN)》)得到:\frac{\partial L_t}{\partial \mathbf{u}_{t-1}}=\frac{\partial L_t}{\partial \mathbf{h}_{t-1}}\frac{\partial \mathbf{h}_{t-1}}{\partial \mathbf{u}_{t-1}}=\frac{\partial L_t}{\partial \mathbf{h}_{t-1}}\bigodot f'(\mathbf{u}_{t-1})=(\frac{\partial L_t}{\partial \mathbf{u}_{t}}\frac{\partial \mathbf{u}_{t}}{\partial \mathbf{h}_{t-1}})\bigodot f'(\mathbf{u}_{t-1})=(\frac{\partial L_t}{\partial \mathbf{u}_{t}}W_{hh})\bigodot f'(\mathbf{u}_{t-1})

    上式建立了t时刻的\frac{\partial L_t}{\partial \mathbf{u}_{t-1}}\frac{\partial L_t}{\partial \mathbf{u}_{t}}之间的递推关系。根据RNN循环层的特征,L_t中只含有\mathbf{u}_{t},不含\mathbf{u}_1,\mathbf{u}_2,...,\mathbf{u}_{t-1},而且\mathbf{u}_{t}的值会传播到以后时刻中取,也就是\mathbf{u}_{t+1},\mathbf{u}_{t+2},...,\mathbf{u}_{T}\mathbf{u}_{t}有关

    \mathbf{\delta }_t=\frac{\partial L}{\partial \mathbf{u}_t}=\sum_{j=1}^T\frac{\partial L_j}{\partial \mathbf{u}_t}=\sum_{j=t}^T\frac{\partial L_j}{\partial \mathbf{u}_t}

    =\frac{\partial L_t}{\partial \mathbf{u}_t}+\sum_{j=t+1}^T\frac{\partial L_j}{\partial \mathbf{u}_t}

    =\frac{\partial L_t}{\partial \mathbf{u}_t}+\sum_{j=t+1}^T\frac{\partial L_j}{\partial \mathbf{u}_{t+1}}\frac{\partial \mathbf{u}_{t+1}}{\partial \mathbf{u}_t}

    =\frac{\partial L_t}{\partial \mathbf{u}_t}+\sum_{j=t+1}^T\frac{\partial L_j}{\partial \mathbf{u}_{t+1}}\frac{\partial \mathbf{u}_{t+1}}{\partial \mathbf{h}_t}\frac{\partial \mathbf{h}_{t}}{\partial \mathbf{u}_t}

    =\frac{\partial L_t}{\partial \mathbf{u}_t}+(\sum_{j=t+1}^T\frac{\partial L_j}{\partial \mathbf{u}_{t+1}}W_{hh})\bigodot f'(\mathbf{u}_{t})

    =\frac{\partial L_t}{\partial \mathbf{u}_t}+(\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

    =\frac{\partial L_t}{\partial \mathbf{h}_t}\frac{\partial \mathbf{h}_t}{\partial \mathbf{u}_t}+(\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

    =\frac{\partial L_t}{\partial \mathbf{h}_t}\bigodot f'(\mathbf{u}_{t})+(\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

    =(\frac{\partial L_t}{\partial \mathbf{v}_t}\frac{\partial \mathbf{v}_t}{\partial \mathbf{h}_t})\bigodot f'(\mathbf{u}_{t})+(\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

    =(\frac{\partial L_t}{\partial \mathbf{v}_t}W_0)\bigodot f'(\mathbf{u}_{t})+(\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

    \frac{\partial L_t}{\partial \mathbf{v}_{t}}容易求得。最终得到\mathbf{\delta }_t\mathbf{\delta }_{t+1}两者的递推关系为:

    \mathbf{\delta }_t=(\frac{\partial L_t}{\partial \mathbf{v}_t}W_0+\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

    该式的递推终点是t=T时刻的误差\mathbf{\delta }_T,即

    \mathbf{\delta }_T=\frac{\partial L}{\partial \mathbf{u}_T}=\frac{\partial L}{\partial \mathbf{v}_T}\frac{\partial \mathbf{v}_T}{\partial \mathbf{h}_T}\frac{\partial \mathbf{h}_T}{\partial \mathbf{u}_T}=(\frac{\partial L}{\partial \mathbf{v}_T}W_0)\bigodot f'(\mathbf{u}_{T})

     

    我们将以上的结论整理如下:

    输出层权重矩阵和偏置向量梯度如下计算:

                                                                        \frac{\partial L}{\partial \mathbf{b}_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial \mathbf{b}_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial \mathbf{v}_{t}}

                                                                       \frac{\partial L}{\partial W_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial W_{0}}=\sum_{i=1}^{T}\frac{\partial L_t}{\partial \mathbf{v}_{t}}\mathbf{h}_{t}^T

    循环层权重矩阵和偏置向量梯度如下计算:

                                                                     \frac{\partial L}{\partial W_{xh}}=\sum_{i=1}^T\delta_t\mathbf{x}_t^T

                                                                     \frac{\partial L}{\partial W_{hh}}=\sum_{i=1}^T\delta_t\mathbf{h}_{t-1}^T

                                                                     \frac{\partial L}{\partial \mathbf{b}_{h}}=\sum_{i=1}^T\delta_t

                                                                    \mathbf{\delta }_t=(\frac{\partial L_t}{\partial \mathbf{v}_t}W_0+\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t})

                                                                   \mathbf{\delta }_T=(\frac{\partial L}{\partial \mathbf{v}_T}W_0)\bigodot f'(\mathbf{u}_{T})

    根据L_t=||g(\mathbf{v}_t)-\mathbf{y}_t||^2,容易求得\frac{\partial L_t}{\partial \mathbf{v}_{t}}

     

    BBTT算法

             有了上面权重矩阵和偏置向量的计算公式,很容易得到BBTT算法了,具体算法流程如下:

    (1)初始化

    分别初始化W_{xh},W_{hh},W_{0},\mathbf{b}_{0},\mathbf{b}_{h}

    (2)对于时刻t=1,2,...,T

    对样本\mathbf{x}=\mathbf{(x_{1},x_{2},...,x_{T})}进行正向传播,就是让每个时刻的数据\mathbf{x}_t输入到网络中,计算出输出层权重矩阵和偏置向量:

    \frac{\partial L}{\partial \mathbf{b}_{0}}和 \frac{\partial L}{\partial W_{0}}。并记录下\mathbf{x}_t\mathbf{h}_{t-1}

    使用梯度下降法更新权重和偏置项

    W_{0}^{new}=W_{0}-\eta\frac{\partial L}{\partial W_{0}}

    \mathbf{b}_{0}^{new}=\mathbf{b}_{0}-\eta\frac{\partial L}{\partial \mathbf{b}_{0}}

    (3)对时刻t=T,T-1,...,1反向传播

    计算出\mathbf{\delta }_T=(\frac{\partial L}{\partial \mathbf{v}_T}W_0)\bigodot f'(\mathbf{u}_{T}),使用递推\mathbf{\delta }_t=(\frac{\partial L_t}{\partial \mathbf{v}_t}W_0+\delta_{t+1}W_{hh})\bigodot f'(\mathbf{u}_{t}),计算出循环层的权重矩阵和偏置向量的梯度:

    \frac{\partial L}{\partial W_{xh}}=\sum_{i=1}^T\delta_t\mathbf{x}_t^T, \frac{\partial L}{\partial W_{hh}}=\sum_{i=1}^T\delta_t\mathbf{h}_{t-1}^T,  \frac{\partial L}{\partial \mathbf{b}_{h}}=\sum_{i=1}^T\delta_t

    使用梯度下降法更新循环层的权重矩阵和偏置向量:

    W_{xh}^{new}=W_{xh}-\eta\frac{\partial L}{\partial W_{xh}}

    W_{hh}^{new}=W_{hh}-\eta\frac{\partial L}{\partial W_{hh}}

    \mathbf{b}_{h}^{new}=\mathbf{b}_{h}-\eta\frac{\partial L}{\partial \mathbf{b}_{h}}

    (4)判断

    如果迭代次数或者损失误差达到允许范围,算法停止,否则进入(2)继续正向传播。

     

     

    展开全文
  • 本文部分内容引用了以下文章及书籍,在此由衷感谢以下作者的分享! ... ... 《TensorFlow实战Google深度学习框架》 1.循环神经网络简介 传统的机器学习算法非常...
  • 《深度学习》之 循环神经网络 原理 超详解一、简介二、结构3.1 循环结构3.2 RNN 结构三、训练算法四、基于 RNN 的语言模型例子1、首先,要把词表达为向量的形式:2、为了输出 “最可能” 的词,所以需要计算词典中每...
  • 循环神经网络——RNN的训练算法:BPTT基本步骤前向计算误差项的计算权重梯度的计算RNN的梯度爆炸和消失问题 基本步骤 BPTT算法是针对循环层的训练算法,它的基本原理和BP算法是一样的,也包含同样的三个步骤: 1.前...
  • 系列博客是博主学习神经...卷积神经网络在本系列中先告一段落,我们开始学习循环神经网络的相关知识。本系列的主旨是基础学习,大致了解各个神经网络的基本原理。至于更深的应用,我们留待以后学习。 正向传播...
  • 循环神经网络

    2019-03-17 17:55:18
    循环神经网络1.1 RNN的结构1.2 反向传播算法1.3参考文献:2. 双向RNN3. 递归神经网络4. LSTM、GRU5. Text-RNN的原理。9. Recurrent Convolutional Neural Networks(RCNN)原理 1. 循环神经网络 在DNN和CNN中,...
  • 循环神经网络RNN

    2021-02-20 16:21:12
    1.46.循环神经网络RNN RNN是Recurrent Neural Networks的缩写,即循环神经网络,它常用于解决序列问题。RNN有记忆功能,除了当前输入,还把上下文环境作为预测的依据。它常用于语音识别、翻译等场景之中。 RNN是序列...
  • 文章列表 1.深度学习基础模型算法原理及编程实现–01.感知机. 2.深度学习基础模型算法原理及编程实现–02.线性单元 ....3.深度学习基础模型算法原理及编程实现–03.全链接 ....循环神经网络. 9.深度...
  • 文章列表 1.深度学习基础模型算法原理及编程实现–01.感知机. 2.深度学习基础模型算法原理及编程实现–02.线性单元 ....3.深度学习基础模型算法原理及编程实现–03.全链接 ....循环神经网络. … ...
  • 本文着重讨论循环神经网络(Recurrent Neural Network,RNN)的数学推导过程(主要是反向过程),不会对RNN做全面的介绍,其特点,缺点假定读者已经了解,并且假定读者已经掌握全连接(FC)神经网络的原理和相关函数...
  • 转移系统 采用简单的前馈神经网络(无循环)进行转移状态的计算2.特征构造采用的Chen 和 Manning(2014)的方法3.引入CRF全局优化算法采用柱搜索的方式避免局部优化算法带来的标注偏置问题。基于CRF损失函数对神经...
  • 二 RNN(循环神经网络)2.1 RNN模型结构2.2 RNN的反向传播三 RNN的一些改进算法3.1 LSTM算法(Long Short Term Memory, 长短期记忆网络 )3.2 GRU算法四 基于Tensorflow的基本操作和总结 一 RNN概述   前面我们叙述了...
  • (1)什么是梯度下降和链式求导法则 1.梯度下降 假设我们有一个函数J(w),如下图所示。...而初始位置的切线斜率a>0(也是该位置对应的导数大于0),w=w-eta*a(eta是学习率)就能让w的值减小,循环求导更新w直到J(w)取到最
  • 循环神经网络与text-rnn循环神经网络循环神经网络介绍循环神经网络应用循环神经网络计算梯度的方式梯度爆炸和梯度消失LSTMGRUtext-rnntext-rnn分类原理 循环神经网络 循环神经网络介绍 循环神经网络(Recurrent ...
  • Task8 循环神经网络

    2019-03-17 19:38:47
    1.2 循环神经网络的提出背景 1.3BPTT算法 二、双向RNN 三、 递归神经网络 四、LSTM、GRU的结构 4.1 LSTM 4.2 GRU( Gated Recurrent Unit,LSTM变体) 五、针对梯度消失(LSTM等其他门控RNN) 六、 Memory ...
  • 1.http://www.cnblogs.com/pinard/p/6509630.html (原理) 转载于:https://www.cnblogs.com/liutianrui1/p/10596568.html
  • 1. RNN神经网络模型原理

    千次阅读 2019-02-12 19:22:00
    循环神经网络(recurrent neural network)源自于1982年由Saratha Sathasivam 提出的霍普菲尔德网络。 传统的机器学习算法非常依赖于人工提取的特征,使得基于传统机器学习的图像识别、 语音识别以及自然语言处理等...
  • 循环神经网络的训练算法:BPTT BPTT算法是针对循环层的训练算法,它的基本原理和BP算法是一样的,也包含同样的三个步骤: 前向计算每个神经元的输出值;反向计算每个神经元的误差项δj值,它是误差函数E对神经...
  • 循环神经网络(Recurrent Neural Networks) RNN的训练方法——BPTT算法(back-propagation through time) 长期依赖(Long-Term Dependencies)问题 LSTM(long short-term memory) LSTM 的核心思想 逐步理解...
  • 模型优化(模型复杂度,损失函数,学习率,优化器,图片增强,dropout) CNN卷积神经网络(原理,LeNet5,AlexNet,VGGNet,InceptionNet,ResNet,物品识别) RNN循环神经网络原理,LSTM,GRU,股票预测) BP神经...
  • RNN是Recurrent Neural Networks的缩写,即循环神经网络,它常用于解决序列问题。RNN有记忆功能,除了当前输入,还把上下文环境作为预测的依据。它常用于语音识别、翻译等场景之中。 RNN是序列模型的基础,尽管能够...
  • 本论文技术性地介绍了三种最常见的神经网络:前馈神经网络、卷积神经网络和循环神经网络。且该文详细介绍了每一种网络的基本构建块,其包括了基本架构、传播方式、连接方式、激活函数、反向传播的应用和各种优化算法...
  • 前言 跳过废话,直接看正文 ...经过一段时间的学习,我初步了解了RNN的基本原理和实现方法,在...RNN的原理在网上能找到很多,我这里就不说了,说出来也不会比那些更好,这里先推荐一个RNN教程,讲的很好,四个po
  • RNN的基础知识和公式推导参考: ... 下面的部分实现代码也是基于上面的文章给出的,通过实现其中的组件...循环神经网络的训练算法:BPTT BPTT算法是针对循环层的训练算法,它的基本原理和BP算法是一样的,也包含同样...
  • 循环神经网络的提出背景、优缺点。着重学习RNN的反向传播、RNN出现的问题(梯度问题、长期依赖问题)、BPTT算法。 双向RNN3 LSTM、GRU的结构、提出背景、优缺点。 针对梯度消失(LSTM等其他门控RNN)、梯度爆炸...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 157
精华内容 62
关键字:

循环神经网络算法原理