第六章课后题(LSTM | GRU)

news2025/1/22 16:13:32

目录

  • 习题6-3 当使用公式(6.50)作为循环神经网络得状态更新公式时,分析其可能存在梯度爆炸的原因并给出解决办法.
  • 习题6-4 推导LSTM网络中参数的梯度,并分析其避免梯度消失的效果​编辑
  • 习题6-5 推导GRU网络中参数的梯度,并分析其避免梯度消失的效果​
  • 附加题 6-1P 什么时候应该用GRU? 什么时候用LSTM?
  • 附加题 6-2P LSTM BP推导

习题6-3 当使用公式(6.50)作为循环神经网络得状态更新公式时,分析其可能存在梯度爆炸的原因并给出解决办法.

1
梯度爆炸问题:在公式 Z k = U h k − 1 + W x k + b Z_k=Uh_{k-1}+Wx_k +b Zk=Uhk1+Wxk+b为在第k kk时刻函数 g ( ∗ ) g(*) g()的输入,在计算公式(6.34)中的误差项 δ t , k = ∂ L t ∂ z k δ_{t,k} = \frac{\partial L_{t}}{\partial z_{k}} δt,k=zkLt,梯度可能会过大,从而导致梯度爆炸问题。

解决办法:增加门控装置。

习题6-4 推导LSTM网络中参数的梯度,并分析其避免梯度消失的效果​编辑

公式
手动推导一下
2
分析避免梯度消失的效果:简单的来讲,RNN的输出由连乘决定,连乘可能会出现梯度消失。LSTM的输出由累加决定,累加的方式克服了上述的问题。

梯度更新时,梯度的大小主要取决于前后状态导数再连乘关系,即: ∏ j t ∂ c j ∂ c j − 1 \prod_{j}^{t}\frac{\partial c_{j}}{\partial c_{j-1}} jtcj1cj

RNN两个状态求导满足(tanh激活函数类似): σ ( 1 − σ ) W \sigma\left( 1-\sigma \right)W σ(1σ)W,求导绝对值范围为: [ 0 ∼ 1 4 W ] [0\sim\frac{1}{4}W] [041W]

而LSTM输入门状态更新时,两个状态求导则中有一部分直接取决于forget gate的输出值: σ ( W x + b ) \sigma\left( Wx+b \right) σ(Wx+b),求导绝对值范围为 [ 0 ∼ 1 ] \left[ 0\sim1 \right] [01]

由于RNN很大程度上取决于W 的取值(与4的大小关系),若认定最终所期望学得的系数W 是绝对值稀疏的,即其要么大要么小,对于RNN而言是容易产生梯度消失和梯度爆炸的。而LSTM相比于RNN更稳定,稀疏的话其对应的求导范围看极端一点也是0和1,是不是就类似Relu的作用了呢?因此,在通过几次连乘操作时LSTM相比RNN而言能缓解梯度的消失问题。

习题6-5 推导GRU网络中参数的梯度,并分析其避免梯度消失的效果​

公式
2
3
推导一下:
1
2
3
4
5
3
分析:LSTM和GRU里面都存储了一个中间状态,并把中间状态持续从前往后传,和当前步的特征合并来做预测,合并过程用的是加法模型,这点其实和ResNet的残差模块有点类似。

附加题 6-1P 什么时候应该用GRU? 什么时候用LSTM?

先说明一下GRU和LSTM的区别:GRU作为LSTM的一种变体,将忘记门和输入门合成了一个单一的更新门。同样还混合了细胞状态和隐藏状态,加诸其他一些改动。最终的模型比标准的 LSTM 模型要简单,也是非常流行的变体。GRU 输入输出的结构与普通的 RNN 相似,其中的内部思想与 LSTM 相似。与 LSTM 相比,GRU 内部少了一个”门控“,参数比LSTM 少,但是却也能够达到与 LSTM 相当的功能。

对于 LSTM 与 GRU 而言, 由于 GRU 参数更少,收敛速度更快,因此其实际花费时间要少很多,这可以大大加速了我们的迭代过程。 而从表现上讲,二者之间孰优孰劣并没有定论,这要依据具体的任务和数据集而定,而实际上,二者之间的 performance 差距往往并不大,远没有调参所带来的效果明显

附加题 6-2P LSTM BP推导

公式
3

import numpy as np

def sigmoid(x):
    return 1/(1+np.exp(-x))

def softmax(x):
    e_x = np.exp(x-np.max(x))# 防溢出
    return e_x/e_x.sum(axis=0)


def lstm_cell_forward(xt, a_prev, c_prev, parameters):    
    """
    Implement a single forward step of the LSTM-cell as described in Figure (4)
    Arguments:
    xt -- your input data at timestep "t", numpy array of shape (n_x, m).
    a_prev -- Hidden state at timestep "t-1", numpy array of shape (n_a, m)
    c_prev -- Memory state at timestep "t-1", numpy array of shape (n_a, m)
    parameters -- python dictionary containing:
    Wf -- Weight matrix of the forget gate, numpy array of shape (n_a, n_a + n_x)
    bf -- Bias of the forget gate, numpy array of shape (n_a, 1)
    Wi -- Weight matrix of the update gate, numpy array of shape (n_a, n_a + n_x)
    bi -- Bias of the update gate, numpy array of shape (n_a, 1)
    Wc -- Weight matrix of the first "tanh", numpy array of shape (n_a, n_a + n_x)
    bc --  Bias of the first "tanh", numpy array of shape (n_a, 1)
    Wo -- Weight matrix of the output gate, numpy array of shape (n_a, n_a + n_x)
    bo --  Bias of the output gate, numpy array of shape (n_a, 1)Wy -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a)
    by -- Bias relating the hidden-state to the output, numpy array of shape (n_y, 1)
    Returns:
    a_next -- next hidden state, of shape (n_a, m)
    c_next -- next memory state, of shape (n_a, m)
    yt_pred -- prediction at timestep "t", numpy array of shape (n_y, m)
    cache -- tuple of values needed for the backward pass, contains (a_next, c_next, a_prev, c_prev, xt, parameters)
    """
 
    # 获取参数字典中各个参数
    Wf = parameters["Wf"]
    bf = parameters["bf"]
    Wi = parameters["Wi"]
    bi = parameters["bi"]
    Wc = parameters["Wc"]
    bc = parameters["bc"]
    Wo = parameters["Wo"]
    bo = parameters["bo"]
    Wy = parameters["Wy"]
    by = parameters["by"]    
    # 获取 xt 和 Wy 的维度参数
    n_x, m = xt.shape
    n_y, n_a = Wy.shape    
    # 拼接 a_prev 和 xt
    concat = np.zeros((n_a + n_x, m))
    concat[: n_a, :] = a_prev
    concat[n_a :, :] = xt    
    # 计算遗忘门、更新门、记忆细胞候选值、下一时间步的记忆细胞、输出门和下一时间步的隐状态值
    ft = sigmoid(np.matmul(Wf, concat) + bf)
    it = sigmoid(np.matmul(Wi, concat) + bi)
    cct = np.tanh(np.matmul(Wc, concat) + bc)
    c_next = ft*c_prev + it*cct
    ot = sigmoid(np.matmul(Wo, concat) + bo)
    a_next = ot*np.tanh(c_next)    
    # 计算 LSTM 的预测输出
    yt_pred = softmax(np.matmul(Wy, a_next) + by)    
    # 保存各计算结果值
    cache = (a_next, c_next, a_prev, c_prev, ft, it, cct, ot, xt, parameters)    
    return a_next, c_next, yt_pred, cache

def lstm_forward(x, a0, parameters):    
    """
    Arguments:
    x -- Input data for every time-step, of shape (n_x, m, T_x).
    a0 -- Initial hidden state, of shape (n_a, m)
    parameters -- python dictionary containing:
                 Wf -- Weight matrix of the forget gate, numpy array of shape (n_a, n_a + n_x)
                 bf -- Bias of the forget gate, numpy array of shape (n_a, 1)
                 Wi -- Weight matrix of the update gate, numpy array of shape (n_a, n_a + n_x)
                 bi -- Bias of the update gate, numpy array of shape (n_a, 1)
                 Wc -- Weight matrix of the first "tanh", numpy array of shape (n_a, n_a + n_x)
                 bc -- Bias of the first "tanh", numpy array of shape (n_a, 1)
                 Wo -- Weight matrix of the output gate, numpy array of shape (n_a, n_a + n_x)
                 bo -- Bias of the output gate, numpy array of shape (n_a, 1)
                 Wy -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a)
                 by -- Bias relating the hidden-state to the output, numpy array of shape (n_y, 1)
    Returns:
    a -- Hidden states for every time-step, numpy array of shape (n_a, m, T_x)
    y -- Predictions for every time-step, numpy array of shape (n_y, m, T_x)
    caches -- tuple of values needed for the backward pass, contains (list of all the caches, x)
    """
    # 初始化缓存列表
    caches = []    
    # 获取 x 和 参数 Wy 的维度大小
    n_x, m, T_x = x.shape
    n_y, n_a = parameters['Wy'].shape    
    # 初始化 a, c 和 y 的值
    a = np.zeros((n_a, m, T_x))
    c = np.zeros((n_a, m, T_x))
    y = np.zeros((n_y, m, T_x))    
    # 初始化 a_next 和 c_next
    a_next = a0
    c_next = np.zeros(a_next.shape)    
    # 循环所有时间步
    for t in range(T_x):        
    # 更新下一时间步隐状态值、记忆值并计算预测 
        a_next, c_next, yt, cache = lstm_cell_forward(x[:,:,t], a_next, c_next, parameters)        
        # 在 a 中保存新的激活值 
        a[:,:,t] = a_next        
        # 在 a 中保存预测值
        y[:,:,t] = yt        
        # 在 c 中保存记忆值
        c[:,:,t]  = c_next        
        # 添加到缓存列表
        caches.append(cache)    
        # 保存各计算值供反向传播调用
    caches = (caches, x)    
    return a, y, c, caches

def lstm_cell_backward(da_next, dc_next, cache):    
    """
    Arguments:
    da_next -- Gradients of next hidden state, of shape (n_a, m)
    dc_next -- Gradients of next cell state, of shape (n_a, m)
    cache -- cache storing information from the forward pass
    Returns:
    gradients -- python dictionary containing:
     dxt -- Gradient of input data at time-step t, of shape (n_x, m)
     da_prev -- Gradient w.r.t. the previous hidden state, numpy array of shape (n_a, m)
     dc_prev -- Gradient w.r.t. the previous memory state, of shape (n_a, m, T_x)
     dWf -- Gradient w.r.t. the weight matrix of the forget gate, numpy array of shape (n_a, n_a + n_x)
     dWi -- Gradient w.r.t. the weight matrix of the update gate, numpy array of shape (n_a, n_a + n_x)
     dWc -- Gradient w.r.t. the weight matrix of the memory gate, numpy array of shape (n_a, n_a + n_x)
     dWo -- Gradient w.r.t. the weight matrix of the output gate, numpy array of shape (n_a, n_a + n_x)
     dbf -- Gradient w.r.t. biases of the forget gate, of shape (n_a, 1)
     dbi -- Gradient w.r.t. biases of the update gate, of shape (n_a, 1)
     dbc -- Gradient w.r.t. biases of the memory gate, of shape (n_a, 1)
     dbo -- Gradient w.r.t. biases of the output gate, of shape (n_a, 1)
    """
 
    # 获取缓存值
    (a_next, c_next, a_prev, c_prev, ft, it, cct, ot, xt, parameters) = cache    # 获取 xt 和 a_next 的维度大小
    n_x, m = xt.shape
    n_a, m = a_next.shape    
    # 计算各种门的梯度
    dot = da_next * np.tanh(c_next) * ot * (1 - ot)
    dcct = dc_next * it + ot * (1 - np.tanh(c_next) ** 2) * it * da_next * cct * (1 - np.tanh(cct) ** 2)
    dit = dc_next * cct + ot * (1 - np.tanh(c_next) ** 2) * cct * da_next * it * (1 - it)
    dft = dc_next * c_prev + ot * (1 - np.tanh(c_next) ** 2) * c_prev * da_next * ft * (1 - ft)    # 计算各参数的梯度 
    dWf = np.dot(dft, np.concatenate((a_prev, xt), axis=0).T)
    dWi = np.dot(dit, np.concatenate((a_prev, xt), axis=0).T)
    dWc = np.dot(dcct, np.concatenate((a_prev, xt), axis=0).T)
    dWo = np.dot(dot, np.concatenate((a_prev, xt), axis=0).T)
    dbf = np.sum(dft, axis=1, keepdims=True)
    dbi = np.sum(dit, axis=1, keepdims=True)
    dbc = np.sum(dcct, axis=1, keepdims=True)
    dbo = np.sum(dot, axis=1, keepdims=True)
 
    da_prev = np.dot(parameters['Wf'][:,:n_a].T, dft) + np.dot(parameters['Wi'][:,:n_a].T, dit) + np.dot(parameters['Wc'][:,:n_a].T, dcct) + np.dot(parameters['Wo'][:,:n_a].T, dot)
    dc_prev = dc_next*ft + ot*(1-np.square(np.tanh(c_next)))*ft*da_next
    dxt = np.dot(parameters['Wf'][:,n_a:].T,dft)+np.dot(parameters['Wi'][:,n_a:].T,dit)+np.dot(parameters['Wc'][:,n_a:].T,dcct)+np.dot(parameters['Wo'][:,n_a:].T,dot) 
 
    # 将各梯度保存至字典
    gradients = {"dxt": dxt, "da_prev": da_prev, "dc_prev": dc_prev, "dWf": dWf,"dbf": dbf, "dWi": dWi,"dbi": dbi, 
                   "dWc": dWc,"dbc": dbc, "dWo": dWo,"dbo": dbo}    
    return gradients



def lstm_backward(da, caches):    
    """
    Arguments:
    da -- Gradients w.r.t the hidden states, numpy-array of shape (n_a, m, T_x)
    dc -- Gradients w.r.t the memory states, numpy-array of shape (n_a, m, T_x)
    caches -- cache storing information from the forward pass (lstm_forward)
    Returns:
    gradients -- python dictionary containing:
           dx -- Gradient of inputs, of shape (n_x, m, T_x)
           da0 -- Gradient w.r.t. the previous hidden state, numpy array of shape (n_a, m)
           dWf -- Gradient w.r.t. the weight matrix of the forget gate, numpy array of shape (n_a, n_a + n_x)
           dWi -- Gradient w.r.t. the weight matrix of the update gate, numpy array of shape (n_a, n_a + n_x)
           dWc -- Gradient w.r.t. the weight matrix of the memory gate, numpy array of shape (n_a, n_a + n_x)
           dWo -- Gradient w.r.t. the weight matrix of the save gate, numpy array of shape (n_a, n_a + n_x)
           dbf -- Gradient w.r.t. biases of the forget gate, of shape (n_a, 1)
           dbi -- Gradient w.r.t. biases of the update gate, of shape (n_a, 1)
           dbc -- Gradient w.r.t. biases of the memory gate, of shape (n_a, 1)
           dbo -- Gradient w.r.t. biases of the save gate, of shape (n_a, 1)
    """
 
    # 获取第一个缓存值
    (caches, x) = caches
    (a1, c1, a0, c0, f1, i1, cc1, o1, x1, parameters) = caches[0]    # 获取 da 和 x1 的形状大小
    n_a, m, T_x = da.shape
    n_x, m = x1.shape    
    # 初始化各梯度值
    dx = np.zeros((n_x, m, T_x))
    da0 = np.zeros((n_a, m))
    da_prevt = np.zeros((n_a, m))
    dc_prevt = np.zeros((n_a, m))
    dWf = np.zeros((n_a, n_a+n_x))
    dWi = np.zeros((n_a, n_a+n_x))
    dWc = np.zeros((n_a, n_a+n_x))
    dWo = np.zeros((n_a, n_a+n_x))
    dbf = np.zeros((n_a, 1))
    dbi = np.zeros((n_a, 1))
    dbc = np.zeros((n_a, 1))
    dbo = np.zeros((n_a, 1))    
    # 循环各时间步
    for t in reversed(range(T_x)):        
        # 使用 lstm 单元反向传播计算各梯度值
        gradients = lstm_cell_backward(da[:, :, t] + da_prevt, dc_prevt, caches[t])        
        # 保存各梯度值
        dx[:,:,t] = gradients['dxt']
        dWf = dWf + gradients['dWf']
        dWi = dWi + gradients['dWi']
        dWc = dWc + gradients['dWc']
        dWo = dWo + gradients['dWo']
        dbf = dbf + gradients['dbf']
        dbi = dbi + gradients['dbi']
        dbc = dbc + gradients['dbc']
        dbo = dbo + gradients['dbo']
 
    da0 = gradients['da_prev']
 
    gradients = {"dx": dx, "da0": da0, "dWf": dWf,"dbf": dbf, "dWi": dWi,"dbi": dbi,                
    "dWc": dWc,"dbc": dbc, "dWo": dWo,"dbo": dbo}    
    return gradients

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

集合框架----源码解读Vector篇

1.vector官方简绍 Vector类实现了一个可增长的对象数组。与数组一样,它包含可以使用整数索引访问的组件。但是,Vector的大小可以根据需要增加或缩小,以适应在创建Vector之后添加和删除项。 每个向量都试图通过维护一个容量和一个capacityIncr…

C#设计模式详解(2)——Factory Method(工厂方法)

文章目录C#设计模式详解(2)——Factory Method(工厂方法)工厂方法模式1.1 概念1.2 意图1.3 问题1.4 解决方案1.5 工厂方法模式结构1.6 案例代码1.7 游戏开发中的应用C#设计模式详解(2)——Factory Method(工厂方法) 工厂方法模式…

领悟《信号与系统》之 非周期信号的傅里叶变换

非周期信号的傅里叶变换一、非周期信号的傅里叶变换二、 典型信号的傅立叶变换1.单边指数信号2.偶双边指数3. 矩阵脉冲信号4. 奇双边指数5. 符号函数6. 冲激信号7. 阶跃信号三、常用傅里叶变换表这里记录的信号都是非周期信号的傅里叶变化,频谱变换的特点就是&#…

【计算机网络】数据链路层:使用广播信道的数据链路层(1)

局域网的数据链路层 局域网特点:网络为一个单位所拥有,地理范围和站点数目均有限。 地理范围和站点数目均有限。 局域网优点: 具有广播功能,从一个站点可以很方便地访问全网。 便于系统的拓展和演变,各设备的位置…

Discourse 论坛激活邮件问题

根据 Discourse 的官方推荐,我们使用的是 MailGun 的服务。 在大部分情况下都没有问题,但是在一些特定的邮件地址,例如 iCloud,我们在发送激活邮件的时候有提示为: "message": "5.5.1 Error: need MA…

实验:温湿度数据oled显示

OK,本次介绍一个oled实验 本来只想做oled实验的 后面想想这个实验太简单 就加上了温湿度传感器 oled可以打印英文和数字,比如用display.println(“Hello World!”)就可以了 如果打印汉字就比较复杂了 需要相应的软件,生成编码 然后一个字一个字打印 不过只要汉字不…

【数据结构】树——二叉树

1.树的介绍以及树的基本概念和性质 2.二叉树介绍以及二叉树的性质 3.二叉树的构建:穷举创建,递归创建 4.二叉树的基本操作 之前我们介绍了顺序表,链表,以及栈和队列,这几种数据结构都属于线性结构,而我们接…

GreenPlum/PostGreSQL表锁处理

GreenPlum/PostGreSQL表锁处理 数据库中遇到表锁的情况,可以通过select * from pg_stat_activity;查看表锁的进程及进程ID,从而取消进程,解锁。 一、模拟表锁 1.1 模拟表数据 创建lock_test表,并随意插入一条数据,…

Oracle自治事务示例演示

自治事务 自治事务(Pragma autonomous_transaction):是PL/SQL块中的一个单独事务,与调用或触发自己的事务之间互不干扰,自己commit和rollback不会影响其他事务,也不会被其他事务所影响。 通俗的讲&#xff…

【Android App】在线语音识别功能实现(使用云知声平台与WebSocket 超详细 附源码)

需要源码和相关资源请点赞关注收藏后评论区留下QQ~~~ 一、在线语音识别 云知声的语音识别同样采用WebSocket接口,待识别的音频流支持MP3和PCM两种格式,对于在线语音识别来说,云知声使用JSON串封装报文,待识别的音频以二进制形式发…

webpack打包vue文件+gulp打包sass文件

webpack打包vue文件 1,下载依赖 npm i vue-loader npm i webpack-cli2,编写webpack配置文件 /*** 关于webpack的配置文件*/const path require(path)const { VueLoaderPlugin } require(vue-loader)const glob require(glob) // node自带的读取文件的库 /*** …

会多门编程语言的你,最推荐哪3-5门语言?

如果你还想在编程的路上继续提高,那我建议你至少学习4种编程语言。可用的编程语言有很多,所以选择一种感兴趣的学习就可以了。我这么建议的原因是,要掌握编程,建立信心,提高能力,最简单的办法就是学习多种编…

浅析工作流调度器Azkaban

title: Azkaban系列 第一章 概述 1.1 为什么需要工作流调度器 1、一个完整的数据分析系统通常都是由大量任务单元组成: shell 脚本程序,java 程序,mapreduce 程序、hive 脚本等 2、各任务单元之间存在时间先后及前后依赖关系 3、为了很好地…

TIA西门子博途V18安装教程及注意事项

TIA西门子博途V18安装教程及注意事项 前提条件: TIA Portal V18需要.Net Framework 3.5环境,所以在安装TIA V18之前要先安装它。大家可以在控制面板中的程序和功能中检查是否已经安装,如果没有,可以参考以下步骤自行安装: 操作系统&#x

jsp旅行网系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 旅行网系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql,使用java语…

[附源码]Python计算机毕业设计房屋租赁系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

2022级浙大MEM录取经验过程分享——有需求就要去匹配

我是2022 级 浙大MEM 新录取的考生,去年联考初试取得了213 分的成绩,综合拿到了148分,去年的提面中也拿到了优秀资格,在备考的过程中自己的一些心得体会和经验分享给大家,希望能够有所帮助。我的本科其实比较普通&…

python循环中的continue和break

目录 一.python中的continue 案例1 结果是 注意 案例2 结果是 二.python中的break 案例1 结果是 注意 案例2 结果是 三. python中continue和break的总结 一.python中的continue continue关键字用于:中断本次循环,直接进入下一次循环 continue可以用于:fo…

2.1.2 运算放大器的组成与分类、运算放大器的发展历程

笔者电子信息专业硕士毕业,获得过多次电子设计大赛、大学生智能车、数学建模国奖,现就职于南京某半导体芯片公司,从事硬件研发,电路设计研究。对于学电子的小伙伴,深知入门的不易,特开次博客交流分享经验&a…

1-10嵌入式Linux系统开发与应用|嵌入式Linux|第三章 Linux编程环境|下篇

目录 1.gcc编译器的使用 1.1gcc软件包 1.2一个基本实例 1.3gcc的主要选项 1.3.1指定函数库和包含文件的查找路径 1.3.2出错检查及警告 1.3.3优化选项 优化带来的问题 1.3.4调试选项 2.GNU C扩展简介 3.GNU make管理项目 3.1make简介 使用make管理项目的原因 4.编…