NNDL 作业11 LSTM

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

        这里我听的是哔哩哔哩上的讲解,这个视频对公式的推导讲解的很详细,每个公式是怎么来的都讲解的很透彻:5.LSTM如何缓解梯度消失(公式推导)_哔哩哔哩_bilibili和 清晰图解LSTM、BPTT、RNN的梯度消失问题_哔哩哔哩_bilibili,以第一个链接的视频讲解为主,图也截取自这里。

下面开始进行推导:(下面的图是我由讲解画出的图)

路径:

推导公式:

路径:

推导公式:

路径图:(由于路径过多一一画出太过繁杂,这里仅写出路径)

推导公式:

LSTM避免梯度消失的原因:

  以上公式只是t=3时的推导,如果是更多的时间步,就是多个类似公式的累乘。从这一步的结果中我们可以发现,其结果的取值范围并不一定局限在[0,1]中,而是有可能大于1的。 

可以总结为两个原因:

   1、cell state传播函数中的“加法”结构确实起了一定作用,它使得导数有可能大于1;
   2、LSTM中逻辑门的参数可以一定程度控制不同时间步梯度消失的程度。

(参考:为什么LSTM可以缓解梯度消失?_lstm为什么能解决梯度消失-CSDN博客

但是我在搜索了一些资料后发现LSTM只能缓解梯度消失,并不能完全解决梯度消失问题。

习题6-3P  编程实现下图LSTM运行过程

同学提出,未发现输入。可以适当改动例题,增加该输入。

实现LSTM算子,可参考实验教材代码。

 

1. 使用Numpy实现LSTM算子

        这段代码是在今天也是元气满满的一天呢_深度学习,利用python解决力扣问题,csp ccf  随机更新-CSDN博客发我的代码的基础上进行修改的代码。

import numpy as np

# x1,x2,x3
x = [[3,1,0],[4,1,0], [2,0,0], [1,0,1], [3,-1,0]]
bias = 1
print("得到的输入为:", x)

# sigmoid 激活函数
def sigmoid(x):
    return np.round(1 / (1 + np.exp(-x)))

# input Gate
def input_gate(i,x,bias):
    inputs = x[i][0] * 0 + x[i][1] * 100 + x[i][2] * 0 + bias * (-10)
    return sigmoid(inputs)

# Forget_Gate
def forget_gate(i,x,bias):
    forgets = x[i][0] * 0 + x[i][1] * 100 + x[i][2] * 0 + bias * 10
    return sigmoid(forgets)

# output gate
def output_gate(i,x,bias):
    outputs = x[i][0] * 0 + x[i][1] * 0 + x[i][2] * 100 + bias * (-10)
    return sigmoid(outputs)

# Block
def Block(i,x,bias):
    blocks = x[i][0] * 1 + x[i][1] * 0 + x[i][2] * 0 + bias * 0
    return blocks

print(Block(0,x,bias),input_gate(0,x,bias),forget_gate(0,x,bias),output_gate(0,x,bias))
# 延迟器
hidden = []
y = []
temp=0
for i in range(len(x)):#遍历
    input1=Block(i,x,bias) * input_gate(i,x,bias)#输入门控制
    forget=forget_gate(i,x,bias)#遗忘门控制
    if forget==1:
        temp+=input1#暂存
        hidden.append(temp)#存入隐藏层
    else:
        temp=0
        hidden.append(temp)
    #输出门控制
    control_hidden=output_gate(i,x,bias)
    if control_hidden==1:
        y.append(temp)
    else:
        y.append(0)
print("中间结果为:",hidden)
print("最终结果为:", y)

可以看出运行结果与正确结果一致。

2. 使用nn.LSTMCell实现

        参考熬夜患者_PTA 乙级,算法,DL模型-CSDN博客给出的中文版本的官方文档内容,比在官网上直接英译汉看的明白很多,中文网站链接:PyTorch - torch.nn.LSTMCell (runebook.dev)

下面给出官网链接:LSTMCell — PyTorch 2.1 documentation(英文版)

代码:

import torch
import torch.nn as nn

# 输入数据 x 维度需要变换,因为LSTMcell接收的是(time_steps,batch_size,input_size)
# time_steps = 9, batch_size = 1, input_size = 4
x = torch.tensor([[1, 0, 0, 1],
                  [3, 1, 0, 1],
                  [2, 0, 0, 1],
                  [4, 1, 0, 1],
                  [2, 0, 0, 1],
                  [1, 0, 1, 1],
                  [3, -1, 0, 1],
                  [6, 1, 0, 1],
                  [1, 0, 1, 1]], dtype=torch.float)
x = x.unsqueeze(1)
# LSTM的输入size和隐藏层size
input_size = 4
hidden_size = 1

# 定义LSTM单元
lstm_cell = nn.LSTMCell(input_size=input_size, hidden_size=hidden_size, bias=False)

lstm_cell.weight_ih.data = torch.tensor([[0, 100, 0, 10],  # forget gate
                                         [0, 100, 0, -10],  # input gate
                                         [1, 0, 0, 0],  # output gate
                                         [0, 0, 100, -10]]).float()  # cell gate
lstm_cell.weight_hh.data = torch.zeros([4 * hidden_size, hidden_size])
# https://runebook.dev/zh/docs/pytorch/generated/torch.nn.lstmcell

hx = torch.zeros(1, hidden_size)
cx = torch.zeros(1, hidden_size)
outputs = []
for i in range(len(x)):
    hx, cx = lstm_cell(x[i], (hx, cx))
    outputs.append(hx.detach().numpy()[0][0])
outputs_rounded = [round(x) for x in outputs]
print(outputs_rounded)

3. 使用nn.LSTM实现

中文版:PyTorch - torch.nn.LSTM (runebook.dev)

官网:PyTorch - torch.nn.LSTM (runebook.dev)

import torch
import torch.nn as nn
 
 
# 输入数据 x 维度需要变换,因为 LSTM 接收的是 (sequence_length, batch_size, input_size)
# sequence_length = 9, batch_size = 1, input_size = 4
x = torch.tensor([[1, 0, 0, 1],
                  [3, 1, 0, 1],
                  [2, 0, 0, 1],
                  [4, 1, 0, 1],
                  [2, 0, 0, 1],
                  [1, 0, 1, 1],
                  [3, -1, 0, 1],
                  [6, 1, 0, 1],
                  [1, 0, 1, 1]], dtype=torch.float)
x = x.unsqueeze(1)
 
# LSTM 的输入 size 和隐藏层 size
input_size = 4
hidden_size = 1
 
# 定义 LSTM 模型
lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size, bias=False)
 
# 设置 LSTM 的权重矩阵
lstm.weight_ih_l0.data = torch.tensor([[0, 100, 0, 10],   # forget gate
                                        [0, 100, 0, -10],  # input gate
                                        [1, 0, 0, 0],      # output gate
                                        [0, 0, 100, -10]]).float()  # cell gate
lstm.weight_hh_l0.data = torch.zeros([4 * hidden_size, hidden_size])
 
# 初始化隐藏状态和记忆状态
hx = torch.zeros(1, 1, hidden_size)
cx = torch.zeros(1, 1, hidden_size)
 
# 前向传播
outputs, (hx, cx) = lstm(x, (hx, cx))
outputs = outputs.squeeze().tolist()
 
# print(outputs)
outputs_rounded = [round(x) for x in outputs]
print(outputs_rounded)

 

总结:

1.  这次作业感悟最大的是对于LSTM反向传播的推导过程,推导过程我听了清晰图解LSTM、BPTT、RNN的梯度消失问题_哔哩哔哩_bilibili5.LSTM如何缓解梯度消失(公式推导)_哔哩哔哩_bilibili这两个视频讲解,第一个视频主要是讲解LSTM解决梯度消失的原因,对LSTM的过程进行了动图演示,公式主要参考第二个视频的讲解明白了公式的来龙去脉,根据讲解画出了反向传播的路径图并写出了推导公式。

2.关于第二问的代码我参考了DL Homework 11-CSDN博客【23-24 秋学期】NNDL 作业11 LSTM-CSDN博客大概了解了代码流程和函数使用,发现了一个很好用的中文版的函数解析,对于LSTM的过程有了详细的理解。

3. 我对作业9进行了部分完善和修改,由于完成作业9时生病回家了三天,完成的比较仓促,后续还会再完善。

作业来源:【23-24 秋学期】NNDL 作业11 LSTM-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值