【23-24 秋学期】NNDL 作业11 LSTM

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

LSTM(长短期记忆网络)是简单循环神经网络的一个变体,可以有效地解决简单循环网络的梯度爆炸或消失问题。LSTM相较于简单循环神经网络,多出了三个控制门:输入门(input gate)、遗忘门(forget gate)和输出门(output gate)。

首先,写出LSTM的更新公式:

输入门:i_{t}=\sigma(W_{i}X_{t}+U_{i}h_{t-1}+b_{i})

遗忘门:f_{t}=\sigma(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})

非线性得到的候选状态:\tilde{C}_{t}= tanh(W_{c}X_{t}+U_{c}h_{t-1}+b_{c})

输出门:O_{t}=\sigma(W_{o}X_{t}+U_{o}h_{t-1}+b_{o})

内部状态:C_{t}=f_{t}\bigodotC_{t-1}+i_{t} \bigodot\tilde{C}_{t}

输出信息到隐藏状态的外部状态:h_{t}=O_{t}\bigodottanh(C_{t})

其中,X_{t}表示当前的输入,h_{t-1}表示前一刻的隐藏状态,C_{t-1} 表示前一刻的细胞状态,i_{t}表示输入门的输出, f_{t}表示遗忘门输出,C_{t}表示当前的细胞状态,O_{t}表示输出门的输出,h_{t}表示当前的隐藏状态。    

然后,对参数梯度进行推导。以权重W_{i}为例:

\frac{\partial L}{\partial W_{i}}=\sum_{t=1}^{T}\frac{\partial L}{\partial i_{t}} · \frac{\partial i_{t}}{\partial W_{i}}

通过链式法则得到:

\frac{\partial i_{t}}{\partial W_{i}}=\frac{\partial }{\partial W_{i}}\sigma(W_{i}X_{t}+U_{i}h_{t-1}+b_{i})=\sigma'(W_{i}X_{t}+U_{i}h_{t-1}+b_{i})·X_{t}

其中,\sigma'sigmoid函数的导数

同理,可得权重W_{f}W_{o}的导数为:

\frac{\partial f_{t}}{\partial W_{f}}=\frac{\partial }{\partial W_{f}}\sigma(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})=\sigma'(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})·X_{t}

\frac{\partial O_{t}}{\partial W_{o}}=\frac{\partial }{\partial W_{o}}\sigma(W_{o}X_{t}+U_{o}h_{t-1}+b_{o})=\sigma'(W_{o}X_{t}+U_{o}h_{t-1}+b_{o})·X_{t}

由此可得:(以f_{t}为例)

\frac{\partial f_{t}}{\partial h_{f}}=\frac{\partial }{\partial h_{f}}\sigma(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})=\sigma'(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})·h_{t-1}

\frac{\partial f_{t}}{\partial b_{f}}=\frac{\partial }{\partial b_{f}}\sigma(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})=\sigma'(W_{f}X_{t}+U_{f}h_{t-1}+b_{f})

i_{t}O_{t}对于U和b参数得导数与上式大致相同。

LSTM网络得设计使其能够有效地缓解梯度消失问题。

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

同学提出,未发现h_{t-1}输入。可以适当改动例题,增加该输入。

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

1. 使用Numpy实现LSTM算子

代码:

import numpy as np

x = np.array([[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]])   #x与b的数据
#以下为权重
W_i = np.array([0, 100, 0, -10]) #输入门
W_o = np.array([0, 0, 100, -10]) #输出门
W_f = np.array([0, 100, 0, 10]) #遗忘门
W_c = np.array([1, 0, 0, 0])    #内部状态
#sigmoid函数
def sigmoid(x):
    y = 1 / (1 + np.exp(-x))
    if y >= 0.5:
        return 1
    else:
        return 0

#初始化变量
temp = 0
t=0
y = []
p=[]
memory=[]
for input in x:
    memory.append(t)  # 将当前记忆值添加到memory中
    temp_c = np.tanh(np.sum(np.multiply(input, W_c)))
    temp_input = sigmoid(np.sum(np.multiply(input, W_i)))
    temp_forget = sigmoid(np.sum(np.multiply(input, W_f)))
    temp_output = sigmoid(np.sum(np.multiply(input, W_o)))
    temp = temp_c * temp_input + temp_forget * temp
    if input[1]== 1:
        t += input[0]
    if input[1]==-1:
        t=0
    if input[2] ==1:
        p.append(t)
    if input[2] ==0:
        p.append(0)    #h的状态
    y.append(temp_output * np.tanh(temp)) #LSTM得到的结果
print('c为:',memory)
print('输出门:',p)
outputs = [round(x) for x in y]  #将y中的数字整数化。
print(outputs)

结果:

2. 使用nn.LSTMCell实现

代码:

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)
#在第二个维度上加一个维度,便于与LSTM模型的输入匹配
x = x.unsqueeze(1)
# LSTM的输入大小和隐藏层大小
input_size = 4
hidden_size = 1

# 定义一个LSTM单元
lstm_cell = nn.LSTMCell(input_size=input_size, hidden_size=hidden_size, bias=False)
#为LSTM单元设置权重值
lstm_cell.weight_ih.data = torch.tensor([[0, 100, 0, 10],  # 遗忘门
                                         [0, 100, 0, -10],  # 输入门
                                         [1, 0, 0, 0],  # 内部状态
                                         [0, 0, 100, -10]],dtype=torch.float)  # 输出门
#设置隐层到隐层的权重为全0矩阵
lstm_cell.weight_hh.data = torch.zeros([4 * hidden_size, hidden_size])
#初始化隐层和细胞状态为全0状态
hx = torch.zeros(1, hidden_size)
cx = torch.zeros(1, hidden_size)
#创建一个存储输出的列表
outputs = []
#通过LSTM单元处理每个输入数据并收集输出
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实现

代码:

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增加一个时间步维度,使其维度变成(sequence_length, batch_size, input_size)
#使其能被LSTM模型接受
x = x.unsqueeze(1)

# LSTM 的输入大小 和隐藏层大小
input_size = 4
hidden_size = 1

# 定义 LSTM 模型   b为偏置。
lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size, bias=False)

# 设置 LSTM 的权重矩阵
#ih表示从输入门到隐层的权重矩阵,共经过四个门
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]],dtype=torch.float)  # cell gate
#hh表示从隐层到隐层的权重矩阵
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()
#对结果进行四舍五入处理,使其整数化,便于展示和观察
outputs_rounded = [round(x) for x in outputs]
print(outputs_rounded)

结果:

结论:

通过观察结果可以看到,当参数与激活函数相同时,结果一致。

参考:

DL Homework 11-CSDN博客

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

### 回答1: nndl-book是指《自然语言处理综述》一书,它是由计算机科学领域的权威学者Christopher Manning和Hinrich Schütze共同编写的一本综述自然语言处理技术的教材。这本书首次出版于1999年,现已有第二版和第三版。nndl-book的内容广泛而深入,涵盖了自然语言处理领域的基础知识和最新进展,包括文本处理、语法分析、语义理解、信息检索、机器翻译等等方面。此外,书中还涉及了许多实用的技术和算法,比如条件随机场、最大熵模型、词向量和深度学习等。nndl-book的读者群体包括学术界和工业界的研究者、开发者和学生,也适合对自然语言处理领域感兴趣的读者学习。总之,nndl-book是自然语言处理领域的一本重要的参考书籍,它为我们深入了解自然语言处理的技术和应用提供了宝贵的指导。 ### 回答2: NNDL-Book是一个著名的Python深度学习库,它是一个开源项目,由加拿大多伦多大学教授Geoffrey Hinton和他的学生Alex Krizhevsky等人创建。NNDL-Book在计算机视觉、自然语言处理和语音识别等领域得到广泛应用,它提供了丰富的神经网络模型和算法,包括卷积神经网络(CNN)、循环神经网络(RNN)和长短时记忆网络(LSTM)等。此外,NNDL-Book还提供了多种数据处理工具和训练技巧,以帮助开发者更高效地构建和训练深度学习模型。总的来说,NNDL-Book是深度学习领域的重要工具之一,对于帮助人们在各种应用场景中实现AI自动化,提高效率和精度都有很大的帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值