循环神经网络学习
循环神经网络RNN
在时刻t,一旦得到当前输入数据x_t,循环神经网络会结合前一时刻t−1得到的隐式编码ℎ_t−1,如下产生当前时刻隐式编码ℎ_t:
ℎ_t=Φ(U×x_t+W×ℎ_t−1)
这里Φ(∙)是激活函数,一般可为Sigmoid或者Tanh激活函数,使模型能够忘掉无关的信息,同时更新记忆内容。U与W为模型参数。从这里可看出,当前时刻的隐式编码输出ℎ_t不仅仅与当前输入数据x_t相关,与网络已有的“记忆”ℎ_t−1也有着密不可分的联系
以词性标注为例子给出了一个输入序列数据(x_1,⋯,x_t−1,x_t,x_t+1,…,x_T)被循环神经网络处理的示意图。
参数W_x将x_t映射为隐式编码ℎ_t、参数W_o将ℎ_t映射为预测输出O_t、ℎ_t−1通过参数W_ℎ参与ℎ_t的生成。图中W_x、W_o和W_ℎ是复用参数。
也可以像这样理解:
其中,前一刻的S(t-1) 参与后一刻S(t)的计算。
长短期记忆网络LSTM
这一部分可以看一下B站上的大佬视频,我就做个总结:lstm原理
lstm主要就是要理解几个门的计算:
看一下总体计算公式
其具体运算如下:前四个方程对应下面四个激活函数运算后的结果,分别把前一步的隐藏信息h(t-1)和当前输入的信息x(t)进行矩阵相乘,特征融合操作,然后,遗忘权重f(t)与前一步的细胞信息单元C(t-1)点乘,再与新输入的特征信息i(t)点乘g(t)相加(其中g(t)可以看作特征选择的操作)得到新的细胞信息C(t),接着再进行第6步的运算,就可以得到当前的隐藏状态输出结果了,再对这给隐藏状态结果进行线性层映射,softmax操作,可以进行分类问题的实现
关于维度问题:
如输入一段话:(x_1,⋯,x_t−1,x_t,x_t+1,…,x_T),x_t-1可以看出成一个单词,该单词在NLP任务中是通常被映射成(1,512)的词向量,这里用1d表示。lstm中的i(t)、f(t)、o(t)维度和h(t)相同,可以记为1h,这个h是在调用lstm模块时自己设置的。所以联系上文公式,我们在训练时是训练的权重矩阵,W(i,i)、W(i,f)等,它们都是dh维的,而W(h,i)、W(h,f)与隐藏信息状态做运算,是hh的。
RNN LSTM 手写数字识别
# 1. 加载数据集
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torchvision
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 6. 定义函数:显示一批数据
def imshow(inp, title=None):
inp = inp.numpy().transpose((1, 2, 0))
mean = np.array([0.485, 0.456, 0.406]) # 均值
std = np.array([0.229, 0.224, 0.225]) # 标准差
inp = std * inp + mean
inp = np.clip(inp, 0, 1) # 限速值限制在0-1之间
plt.imshow(inp)
plt.show()
if title is not None:
plt.title(title)
#plt.pause(1)
# 7. 定义RNN模型
class RNN_Model(nn.Module):
def __init__(self, input_dim, hidden_dim, layer_dim, output_dim):
super(RNN_Model, self).__init__()
self.hidden_dim = hidden_dim
self.layer_dim = layer_dim
self.rnn = nn.RNN(input_dim, hidden_dim, layer_dim, batch_first=True, nonlinearity='relu')
# 全连接层
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
# (layer_dim, batch_size, hidden_dim)
h0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_().to(device)
# 分离隐藏状态,避免梯度爆炸
out, hn = self.rnn(x, h0.detach())
out = self.fc(out[:, -1, :])
return out
# 1. 定义模型
class LSTM_Model(nn.Module):
def __init__(self, input_dim, hidden_dim, layer_dim, output_dim):
super(LSTM_Model, self).__init__() # 初始化父类中的构造方法
self.hidden_dim = hidden_dim
self.layer_dim = layer_dim
# 构建LSTM模型
self.lstm = nn.LSTM(input_dim, hidden_dim, layer_dim, batch_first=True)
# 全连接层
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
# 初始化隐层状态全为0
# (layer_dim, batch_size, hidden_dim)
h0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_().to(device)
# 初始化cell state
c0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_().to(device)
# 分离隐藏状态,以免梯度爆炸
out, (hn, cn) = self.lstm(x, (h0.detach(), c0.detach()))
# 只需要最后一层隐层的状态
out = self.fc(out[:, -1, :])
return out
def train(train_loader,test_loader,net,Loss_Function,learning_rate,plot_loss,plot_accuary,model_name):
model=net
#nn.CrossEntropyLoss()
# 10. 定义优化器
learning_rate = learning_rate
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
# 13. 模型训练
sequence_dim = 28 # 序列长度
loss_list = [] # 保存loss
accuracy_list = [] # 保存accuracy
iteration_list = [] # 保存循环次数
iter = 0
for epoch in range(EPOCHS):
for i, (images, labels) in enumerate(train_loader):
model.train() # 声明训练
# 一个batch的数据转换为RNN的输入维度
images = images.view(-1, sequence_dim, input_dim).requires_grad_().to(device)
labels = labels.to(device)
# 梯度清零(否则会不断累加)
optimizer.zero_grad()
# 前向传播
outputs = model(images)
# 计算损失
loss = Loss_Function(outputs, labels)
# 反向传播
loss.backward()
# 更新参数
optimizer.step()
# 计数器自动加1
iter += 1
# 模型验证
if iter % 500 == 0:
model.eval() # 声明
# 计算验证的accuracy
correct = 0.0
total = 0.0
# 迭代测试集,获取数据、预测
for images, labels in test_loader:
images = images.view(-1, sequence_dim, input_dim).to(device)
# 模型预测
outputs = model(images)
# 获取预测概率最大值的下标
predict = torch.max(outputs.data, 1)[1]
# 统计测试集的大小
total += labels.size(0)
# 统计判断/预测正确的数量
if torch.cuda.is_available():
correct += (predict.cuda() == labels.cuda()).sum()
else:
correct += (predict == labels).sum()
# 计算
accuracy = correct / total * 100
# 保存accuracy, loss, iteration
loss_list.append(loss.data)
accuracy_list.append(accuracy)
iteration_list.append(iter)
# 打印信息
print("loop : {}, Loss : {}, Accuracy : {}".format(iter, loss.item(), accuracy))
if plot_loss==True:
# 可视化 loss
plt.plot(iteration_list, loss_list)
plt.xlabel('Number of Iteration')
plt.ylabel('Loss')
plt.title(model_name)
plt.show()
if plot_accuary==True:
# 可视化 accuracy
plt.plot(iteration_list, accuracy_list, color='r')
plt.xlabel('Number of Iteration')
plt.ylabel('Accuracy')
plt.title(model_name)
plt.savefig('{}_mnist.png'.format(model_name))
plt.show()
if __name__ == "__main__":
# 2. 下载mnist数据集
trainsets = datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor()) # 格式转换
testsets = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor())
print(trainsets.data.shape)
# 4.定义超参数
BATCH_SIZE = 32 # 每批读取的数据大小
EPOCHS = 10 # 训练10轮
# 5. 创建数据集的可迭代对象,也就是说一个batch一个batch的读取数据
train_loader = torch.utils.data.DataLoader(dataset=trainsets, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=testsets, batch_size=BATCH_SIZE, shuffle=True)
# 查看一批batch的数据
# 8. 初始化模型
input_dim = 28 # 输入维度
hidden_dim = 100 # 隐层的维度,神经元
layer_dim = 2 # 2层RNN
output_dim = 10 # 输出维度
model_rnn = RNN_Model(input_dim, hidden_dim, layer_dim, output_dim)
model_lstm=LSTM_Model(input_dim, hidden_dim, layer_dim, output_dim)
# 判断是否有GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model_lstm.to(device=device)
# 定义损失函数
criterion = nn.CrossEntropyLoss()
train(train_loader,test_loader,model_lstm,criterion,learning_rate=0.01,plot_loss=True,plot_accuary=True,model_name="lstm")
其数据维度如下:
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torchvision
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
trainsets = datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor()) # 格式转换
testsets = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor())
#print(trainsets.data.shape)
# 4.定义超参数
BATCH_SIZE = 32 # 每批读取的数据大小
EPOCHS = 1 # 训练10轮
# 5. 创建数据集的可迭代对象,也就是说一个batch一个batch的读取数据
train_loader = torch.utils.data.DataLoader(dataset=trainsets, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=testsets, batch_size=BATCH_SIZE, shuffle=True)
for epoch in range(EPOCHS):
for i, (images, labels) in enumerate(train_loader):
print(images.shape)
print(labels.shape)
images = images.view(-1, 28, 28)
labels = labels
print(images.shape)
print(labels.shape)
print(labels)
break