学深度学习ep09--RNN
·
全连接网络权重数量过于庞大,针对序列信息,采用权重共享的方式减少权重数量
RNN cell--Linear

同一个RNN cell一直参与运算,那么RNN cell是如何构成的?

RNN网络的关键参数:seqLen序列长度,batchsize,inputsize

网络结构可视化如图,numlayers代表网络深度,每一层用一个RNNcell进行训练,每一个RNNcell包括一个Wih和一个Whh,维度分别为hiddensize*inputsize和hiddensize*hiddensize

第一层输出的hidden作为第二层的输入
下面是简单的RNN实现
import torch
batch_size=1
seq_len=3
input_size=4
hidden_size=2
num_layers=5
# cell=torch.nn.RNNCell(input_size=input_size,hidden_size=hidden_size)
#
# dataset=torch.randn(seq_len,batch_size,input_size)
# hidden=torch.zeros(batch_size,hidden_size)
#
# for idx,input in enumerate(dataset):
# print('='*20,idx,'='*20)
# print('input size',input.shape)#input形状是(batchsize,inputsize)
#
# hidden=cell(input,hidden)
#
# print('ouput size',hidden.shape)#hidden形状是(batchsize,hiddensize)
# print(hidden)
##################################################################
inputs=torch.randn(seq_len,batch_size,input_size)
hidden=torch.zeros(num_layers,batch_size,hidden_size)
#或者使用torch.nn.RNN
cell=torch.nn.RNN(input_size=input_size,hidden_size=hidden_size,num_layers=num_layers)
out, hidden=cell(inputs,hidden)#--》inputs=x1...xN;hidden=h0
#-->out=h1...hN;hidden=hN
#输入要求input(seqLen,batch,input_size)隐层(numLayers,batch,hidden_size)
#输出output(seqLen,batch,hidden_size) hidden(numLayers,batch,hidden_size)
print('output size',out.shape)
print('output:',out)
print('hidden size',hidden.shape)
print('hidden:',hidden)
下面希望实现一个seq到seq的转换任务,从hello转换成ohlol
根据输入构造词典-->添加索引-->用索引替代输入-->变成独热向量(索引位置是1,其他位置均为0)

对于这个例子,inputsize就是4,而序列长度是5
输出希望知道输入的是哪个字母,因此输出是一个四维向量,接一个softmax,即多分类问题

import torch
batch_size = 1
seq_len = 5 # 序列长度是 "hello" 的长度,即5
input_size = 4 # 词典大小 one-hot vector size
hidden_size = 4
idx2char=['e','h','l','o']
x_data=[1,0,2,2,3]
y_data=[3,1,2,3,2]
one_hot_lookup=[[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]]
x_one_hot=[one_hot_lookup[x] for x in x_data]
inputs=torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
labels=torch.LongTensor(y_data).view(-1)
class Model(torch.nn.Module):
def __init__(self,input_size,hidden_size,batch_size):
super(Model,self).__init__()
self.batch_size=batch_size
self.input_size=input_size
self.hidden_size=hidden_size
self.rnncell=torch.nn.RNNCell(input_size=self.input_size,hidden_size=self.hidden_size)
def forward(self,input,hidden):
hidden=self.rnncell(input,hidden)
return hidden
def init_hidden(self):
return torch.zeros(self.batch_size,self.hidden_size)
net=Model(input_size,hidden_size,batch_size)
criterion=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(net.parameters(),lr=0.01)
for epoch in range(200):
loss=0
optimizer.zero_grad()
hidden=net.init_hidden()
print('predicted string:',end='')
for input,label in zip(inputs,labels):#inputs维度是(seqLen,batchsize,inputsize);labels维度是(seqLen,1)
hidden=net(input,hidden)#input维度是(batchsize,inputsize);label维度是(1)
loss+=criterion(hidden,label.unsqueeze(0))
_,idx=hidden.max(dim=1)
print(idx2char[idx.item()],end='')
loss.backward()
optimizer.step()
print(',Epoch [%d/200] loss=%.4f' % (epoch+1,loss.item()))
以上是使用RNNCell的实现,还可以使用RNN函数,实现如下
import torch
batch_size = 1
seq_len = 5 # 序列长度是 "hello" 的长度,即5
input_size = 4 # 词典大小 one-hot vector size
hidden_size = 4
idx2char=['e','h','l','o']
x_data=[1,0,2,2,3]
y_data=[3,1,2,3,2]
one_hot_lookup=[[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]]
x_one_hot=[one_hot_lookup[x] for x in x_data]
inputs=torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
labels=torch.LongTensor(y_data)
class Model(torch.nn.Module):
def __init__(self,input_size,hidden_size,batch_size,num_layers=1):
super(Model,self).__init__()
self.num_layers=num_layers
self.input_size=input_size
self.hidden_size=hidden_size
self.batch_size=batch_size
self.rnn=torch.nn.RNN(input_size=self.input_size,hidden_size=self.hidden_size,num_layers=num_layers)
def forward(self,input):
hidden=torch.zeros(self.num_layers,self.batch_size,self.hidden_size)
out,_=self.rnn(input,hidden)
return out.view(-1,self.hidden_size)#展成两个维度,(seqLen*batchsize,hiddensize)
net=Model(input_size,hidden_size,batch_size,num_layers=1)
criterion=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(net.parameters(),lr=0.1)
for epoch in range(50):
optimizer.zero_grad()
outputs=net(inputs)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
_,idx=outputs.max(dim=1)
idx=idx.data.numpy()
print('predicted:',''.join([idx2char[x] for x in idx]),end='')
print(',epoch [%d/50] loss=%.3f' % (epoch+1,loss.item()))
需要注意的是one hot编码维度太高且稀疏,不好用-->embedding,转换成低维稠密向量
根据pytorch官方文档中的LSTM模型讲解,用最笨的方式实现LSTM如下
import torch
class Model(torch.nn.Module):
def __init__(self,input_size,hidden_size):
super(Model,self).__init__()
self.input_size=input_size
self.hidden_size=hidden_size
#四个xt
self.Wii=torch.nn.Linear(input_size,hidden_size)
self.Wif=torch.nn.Linear(input_size,hidden_size)
self.Wig = torch.nn.Linear(input_size, hidden_size)
self.Wio = torch.nn.Linear(input_size, hidden_size)
#四个ht-1
self.Whi = torch.nn.Linear(hidden_size,hidden_size)
self.Whf = torch.nn.Linear(hidden_size, hidden_size)
self.Whg = torch.nn.Linear(hidden_size, hidden_size)
self.Who = torch.nn.Linear(hidden_size, hidden_size)
def forward(self,x,h_prev,c_prev):
i_t=torch.sigmoid(self.Wii(x)+self.Whi(h_prev))
f_t=torch.sigmoid(self.Wif(x)+self.Whf(h_prev))
g_t=torch.tanh(self.Wig(x)+self.Whg(h_prev))
o_t=torch.sigmoid(self.Wio(x)+self.Who(h_prev))
c_t=f_t*c_prev+i_t*g_t
h_t=o_t*torch.tanh(c_t)
return h_t,c_t
class MyLSTM(torch.nn.Module):
def __init__(self,input_size,hidden_size):
super(MyLSTM,self).__init__()
self.input_size=input_size
self.hidden_size=hidden_size
self.cell=Model(input_size,hidden_size)
def forward(self,x):
batch_size,seq_len,_=x.shape
h_t = torch.zeros(batch_size, self.hidden_size, device=x.device)
c_t = torch.zeros(batch_size, self.hidden_size, device=x.device)
outputs = []
for i in range(seq_len):
x_t = x[:,i , :]
h_t,c_t=self.cell(x_t,h_t,c_t)
outputs.append(h_t.unsqueeze(1))
outputs_seq=torch.cat(outputs,dim=1)
return outputs_seq,(h_t,c_t)
# --- 测试代码 ---
# --- 测试代码 ---
if __name__ == '__main__':
# 定义模型参数
batch_size = 10
seq_len = 5
input_size = 8
hidden_size = 16
# 创建一个随机输入
random_input = torch.randn(batch_size, seq_len, input_size)
# 实例化模型
my_lstm = MyLSTM(input_size, hidden_size)
# 运行模型
output_sequence, (last_h, last_c) = my_lstm(random_input)
# 打印结果形状进行验证
print("Input shape:", random_input.shape)
print("Output sequence shape:", output_sequence.shape)
print("Last hidden state shape:", last_h.shape)
print("Last cell state shape:", last_c.shape)
# 期望的输出形状
print("\nExpected output sequence shape:", (batch_size, seq_len, hidden_size))
print("Expected last state shape:", (batch_size, hidden_size))
也可以用LSTM函数实现
import torch
class LSTM(torch.nn.Module):
def __init__(self,input_size,hidden_size):
super(LSTM,self).__init__()
self.lstm=torch.nn.LSTM(input_size=input_size,hidden_size=hidden_size)
def forward(self,x):
output,(h_n,c_n)=self.lstm(x)
return output,(h_n,c_n)
if __name__ == '__main__':
# 定义模型参数 (和之前完全一样)
batch_size = 10
seq_len = 5
input_size = 8
hidden_size = 16
# 创建一个随机输入
random_input = torch.randn(batch_size, seq_len, input_size)
# 实例化模型
official_lstm = LSTM(input_size, hidden_size)
# 运行模型
output_sequence, (last_h, last_c) = official_lstm(random_input)
# 打印结果形状进行验证
print("--- PyTorch Official nn.LSTM ---")
print("Input shape:", random_input.shape)
print("\n--- Outputs ---")
print("Output sequence shape:", output_sequence.shape)
print("Last hidden state shape:", last_h.shape)
print("Last cell state shape:", last_c.shape)
# 期望的输出形状
print("\n--- Expected Shapes ---")
print("Expected output sequence shape:", (batch_size, seq_len, hidden_size))
# 注意: 官方 LSTM 返回的 h_n, c_n 第一个维度是 (num_layers * num_directions)
# 在我们这个简单例子中,都是1,所以形状是 (1, batch_size, hidden_size)
print("Expected last state shape:", (1, batch_size, hidden_size))
更多推荐
所有评论(0)