NNDL 作业11 LSTM

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

LSTM遗忘门将输入映射到[0,1]之间,可以自主选择遗忘部分的信息的多少,来改善梯度消失的情况。既可以无限接近一,完全保留信息,长期信息的梯度不会消失;也可以无限接近于0,全部遗忘,不再往前传递之前的信息。

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

LSTM的真正运行过程中,g和h实际上使用tanh激活函数,而在这里,替换成了线性激活。你可以认为这里weight_Whh是全零,并且不带有偏置。或者认为把weight_Whh省略了。

 

1. 使用Numpy实现LSTM算子

程序:

import numpy as np
def sigmoid(x):
    return 1/(1+np.exp(-x))
Wi=np.array([0,100,0,-10])
Wc=np.array([1,0,0,0])
Wf=np.array([0,100,0,10])
Wo=np.array([0,0,100,-10])
ct=0
y=0
def lstm_cell(xt,a_prev,c_prev,Wi,Wc,Wf,Wo):
    ft=sigmoid(np.dot(xt,Wf.T))
    it=sigmoid(np.dot(xt,Wi.T))
    ct=np.dot(xt,Wc.T)
    # ct=np.tanh(ct)
    ot=sigmoid(np.dot(xt,Wo.T))
    c_prev=c_prev*ft+it*ct
    a_prev=ot*c_prev
    # a_prev=ot*np.tanh(c_prev)
    return a_prev,c_prev
x=[[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]]
xt=np.array(x)

a_prev=0
c_prev=0
memory=[]
y=[]
for i in range(xt.shape[0]):
    # print(i, "memory is : " , round(c_prev))
    # print(i, "memory is : " , c_prev)
    memory.append(round(c_prev))
    a,c=lstm_cell(xt[i],a_prev,c_prev,Wi,Wc,Wf,Wo)
    a_prev=a
    c_prev=c
    # print(i,"y is : " , round(a_prev))
    y.append(round(a_prev))
    # print(i,"y is : " , a_prev)
print("memory: ",memory)
print("y: ",y)

运行结果:

memory:  [0, 0, 3, 3, 7, 7, 7, 0, 6]
y:  [0, 0, 0, 0, 0, 7, 0, 0, 6]

 

2. 使用nn.LSTMCell实现

torch.nn.LSTMCell(input_sizehidden_sizebias=Truedevice=Nonedtype=None)

程序中需要自定义权重矩阵,使得其参数相同,另外,把参数bias=False,不带偏置。根据文档的说明和上述程序运行流程,我们可以得知,weight_ih形状是(4,4)的矩阵,第一行是遗忘门权重,第二行是输入门权重,第三行是候选状态权重,第四行是输出门权重。

weight_hh 是一个(4,1)的权重矩阵,根据之前的分析,它应该被设置为全0。

这个无法实现结果和第一问的结果一样,就是因为激活函数不一样。torch内置的是包装好的,激活函数无法更改。所以要想知道结果对不对,那就只有更改numpy实现的程序,将线性激活改成tanh.

运行之后,结果:
 

y:  [0, 0, 0, 0, 0, 1, 0, 0, 1]

使用LSTMCell:
 

import torch
import torch.nn as nn
torch.manual_seed(0)
input_size = 4
hidden_size = 1

xt = 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.float32)

lstm_cell = nn.LSTMCell(input_size, hidden_size,bias=False)
lstm_cell.weight_ih.data=torch.tensor([[0.,100.,0.,10.],[0.,100.,0.,-10.],[1.,0.,0.,0.],[0.,0.,100.,-10.]])
lstm_cell.weight_hh.data=torch.zeros([4,1])
hx = torch.zeros(1, hidden_size)
cx = torch.zeros(1, hidden_size)

cellmemory=[]
celly=[]
for i in range(xt.shape[0]):
    # print(xt[i].unsqueeze(0))
    hx, cx = lstm_cell(xt[i].unsqueeze(0), (hx, cx))
    # print(i,"y is")
    # print(i,"memory is :",cx.detach().numpy()[0][0])
    # print(i,"y is : ",round(hx.detach().numpy()[0][0]))
    cellmemory.append(round(cx.detach().numpy()[0][0]))
    celly.append(round(hx.detach().numpy()[0][0]))
print(cellmemory)
print(celly)

结果:

[0, 0, 0, 0, 0, 1, 0, 0, 1]

 

3. 使用nn.LSTM实现

torch.nn.LSTM(selfinput_sizehidden_sizenum_layers=1bias=Truebatch_first=Falsedropout=0.0bidirectional=Falseproj_size=0device=Nonedtype=None)

同样,Bias=False.因为多了个num_layers,所以在参数初始化的时候稍微复杂一点。详情可见之后的程序中对比。

还有不同的就是,LSTM可以直接处理一整个序列,不需要管理时间步,所以不需要像LSTMCell那样进行循环。

程序:

import torch
import torch.nn as nn

input_size = 4
hidden_size = 1
num_layers = 1

xt = 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.float32)

lstm = nn.LSTM(input_size, hidden_size, num_layers,bias=False)

# 手动设置参数权重
lstm.weight_ih_l0.data = torch.Tensor([[0.,100.,0.,10.],[0.,100.,0.,-10.],[1.,0.,0.,0.],[0.,0.,100.,-10.]])
lstm.weight_hh_l0.data = torch.zeros([4,1])


hx = torch.zeros(num_layers, 1, hidden_size)
cx = torch.zeros(num_layers, 1, hidden_size)

output,_= lstm(xt.unsqueeze(1), (hx, cx))
k=0
for i in output.squeeze(1).detach().numpy():
    print(k," output y is : ",round(i[0]))
    k=k+1

运行结果:

0  output y is :  0
1  output y is :  0
2  output y is :  0
3  output y is :  0
4  output y is :  0
5  output y is :  1
6  output y is :  0
7  output y is :  0
8  output y is :  1

 结果是使用相同的参数和激活函数,三种方法得到的结果都是一致的。结果正确。

参考:

LSTMCell 用法

LSTM 用法

LSTM,GRU为什么可以缓解梯度消失问题?

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

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值