第十二讲循环神经网络 (基础篇)学习与代码
B站 刘二大人 视频教学 传送门: 循环神经网络(基础篇)
课堂截图分析:
一、前言知识
1、全连接网络,又称DNN(Dense,Deep)如图所示:
2、RNN Cell原理
实际上h0与x1经过某种运算,生成h1,然后将h1输出得同时将h1送到下一个地方与x2进行某种运算,同理如下图所示:
注意:我认为,相当于每次输入输出给到下一个,写代码的时候就是写一个循环,实际上权重是一个,所以叫循环神经网络。
实际算法公式:
这里内部计算过程如果还不懂,可以看一下另一位小伙伴的写的比较详细。
3、RNNCell构造数据满足要求
4、RNN的到使用方法
输入input就是整个输入序列x 输入hidden就是h0,实输出序列就是out,输出的最后一个hn就是hiddn。
5、RNN-numlayers
每一层都有一个输入ho输出hn,左边的圈是输入,右边和上面是输出
二、小例子:将"hello"----->"ohlol" 使用RNNCell
规则过程:用独热向量和字典对应进行转换。
将来需要的结构如下
过程和以前差不多 大概是这个过程,里面是CrossEntropyLoss:
源码:
import torch
import matplotlib.pyplot as plt
import os
os.environ["KMP_DUPLICATE_LIB_OK"]='True'
input_size=4
hidden_size=4
batch_size=1
idx2char=['e','h','l','o']
#The input sequence is 'hello'
x_data=[1,0,2,2,3]
#The output sequence is 'ohlol'
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]
]
#Convert indices into one-hot vector
x_one_hot=[one_hot_lookup[x] for x in x_data]
#Reshape the inputs to(seqlen,batchsize,inputsize) 将输入重塑
inputs=torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
#Reshape the labels to(sqlen,1), 重塑标签 (sqlen,1)
labels=torch.LongTensor(y_data).view(-1,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
#shape of inputs:batchsize,inputsize 和 shape of hidden:batchsize,hiddensize
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):
#构造全0的初始隐层
return torch.zeros(self.batch_size,self.hidden_size)
net=Model(input_size,hidden_size,batch_size)
criterion=torch.nn.CrossEntropyLoss()
optimizor=torch.optim.Adam(net.parameters(),lr=0.1)
epoch_list=[]
loss_list=[]
#Training steps
for epoch in range(20):
loss=0
optimizor.zero_grad()
hidden=net.init_hidden()
print('Predicted string:',end='')
for input,label in zip(inputs,labels):
#RNN Cell
hidden=net(input,hidden)
loss +=criterion(hidden,label)
#输出预测
_,idx=hidden.max(dim=1)
print(idx2char[idx.item()],end='')
loss.backward()
optimizor.step()
loss_list.append(loss.item())
epoch_list.append(epoch)
print(',Epoch [%d/20] loss=%.4f' %(epoch+1,loss.item()))
plt.plot(epoch_list,loss_list)
plt.xlabel("epoch")
plt.ylabel("loss")
plt.show()
输出结果:
Predicted string:lollo,Epoch [1/20] loss=6.5078
Predicted string:loloo,Epoch [2/20] loss=5.7462
Predicted string:loloo,Epoch [3/20] loss=5.1991
Predicted string:ooloo,Epoch [4/20] loss=4.7271
Predicted string:oolol,Epoch [5/20] loss=4.1912
Predicted string:ohlol,Epoch [6/20] loss=3.5281
Predicted string:ohlol,Epoch [7/20] loss=3.1395
Predicted string:ohlol,Epoch [8/20] loss=2.9390
Predicted string:ohlol,Epoch [9/20] loss=2.7793
Predicted string:ohlol,Epoch [10/20] loss=2.6439
Predicted string:ohlol,Epoch [11/20] loss=2.5298
Predicted string:ohlol,Epoch [12/20] loss=2.4391
Predicted string:ohlol,Epoch [13/20] loss=2.3757
Predicted string:ohlol,Epoch [14/20] loss=2.2852
Predicted string:ohlol,Epoch [15/20] loss=2.1728
Predicted string:ohlol,Epoch [16/20] loss=2.0895
Predicted string:ohlol,Epoch [17/20] loss=2.0440
Predicted string:ohlol,Epoch [18/20] loss=2.0164
Predicted string:ohlol,Epoch [19/20] loss=1.9913
Predicted string:ohlol,Epoch [20/20] loss=1.9640
进程已结束,退出代码为 0
运行效果:
三、通过更改模型RNN 实现小例子
代码:
import torch
input_size=4
hidden_size=4
batch_size=1
num_layers=1
seq_len=5
idx2char=['e','h','l','o']
#The input sequence is 'hello'
x_data=[1,0,2,2,3]
#The output sequence is 'ohlol'
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]
]
#Convert indices into one-hot vector
x_one_hot=[one_hot_lookup[x] for x in x_data]
#Reshape the inputs to(seqlen,batchsize,inputsize) 将输入重塑
inputs=torch.Tensor(x_one_hot).view(seq_len,batch_size,input_size)
#shape of labels(sqlenXbatchsize,1)
labels=torch.LongTensor(y_data)
class Model(torch.nn.Module):
def __init__(self,input_size,hidden_size,batch_size,num_layers):
super(Model,self).__init__()
#初始化参数
self.num_layers=num_layers
self.batch_size=batch_size
self.input_size=input_size
self.hidden_size=hidden_size
#shape of inputs:batchsize,inputsize 和 shape of hidden:batchsize,hiddensize
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)
net=Model(input_size,hidden_size,batch_size,num_layers)
criterion=torch.nn.CrossEntropyLoss()
optimizor=torch.optim.Adam(net.parameters(),lr=0.06)
#Training steps
for epoch in range(15):
optimizor.zero_grad()
outputs=net(inputs)
loss=criterion(outputs,labels)
loss.backward()
optimizor.step()
#输出预测
_,idx=outputs.max(dim=1)
idx=idx.data.numpy()
print('Predicted string:',''.join([idx2char[x] for x in idx]),end='')
print(',Epoch [%d/15] loss=%.3f' %(epoch+1,loss.item()))
运行结果:
Predicted string: ooooe,Epoch [1/15] loss=1.453
Predicted string: ooool,Epoch [2/15] loss=1.278
Predicted string: ooool,Epoch [3/15] loss=1.151
Predicted string: ooool,Epoch [4/15] loss=1.057
Predicted string: oolll,Epoch [5/15] loss=0.982
Predicted string: oolol,Epoch [6/15] loss=0.918
Predicted string: ohlol,Epoch [7/15] loss=0.863
Predicted string: ohlol,Epoch [8/15] loss=0.817
Predicted string: ohlol,Epoch [9/15] loss=0.781
Predicted string: ohlol,Epoch [10/15] loss=0.750
Predicted string: ohlol,Epoch [11/15] loss=0.721
Predicted string: ohlol,Epoch [12/15] loss=0.692
Predicted string: ohlol,Epoch [13/15] loss=0.663
Predicted string: ohlol,Epoch [14/15] loss=0.635
Predicted string: ohlol,Epoch [15/15] loss=0.610
进程已结束,退出代码为 0
四、改用embedding替换one-hot
1、one-hot 有三个缺点:1、高维、2、稀疏 3、硬编码的
2、embedding 1、低维 2、 稠密 3、有学习性的
把高维稀疏的样本映射到低维稠密的空间里面, 是常说的数据降维
3、将模型改变成下面这种
4、模型层即变成这样:
使用了PyTorch中的Embedding层将输入字符的数字索引转换为固定长度的向量表示,该向量表示将在RNN中传递。使用RNN层将Embedding向量作为输入,计算RNN的输出。最后,通过一个全连接层fc将RNN的输出映射到每个字符的概率分布。在这个模型中,全连接层的作用是对RNN的输出做一个线性变换,从而将输出的维度从隐藏状态的维度变为每个字符的数量。
5、源码:
import torch
num_class=4
input_size=4
hidden_size=8
embedding_size=10
num_layers=2
batch_size=1
seq_len=5
idx2char=['e','h','l','o']
#The input sequence is 'hello'
x_data=[[1,0,2,2,3]]
#The output sequence is 'ohlol'
y_data=[3,1,2,3,2]
#Reshape the inputs to(seqlen,batchsize,inputsize) 将输入重塑
inputs=torch.LongTensor(x_data)
#Reshape the labels to(sqlen,1), 重塑标签 (sqlen,1)
labels=torch.LongTensor(y_data)
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
#查找矩阵Embedding,Lookup matrix of Embedding:
self.emb =torch.nn.Embedding(input_size,embedding_size)
self.rnn=torch.nn.RNN(input_size=embedding_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True)
self.fc=torch.nn.Linear(hidden_size,num_class)
def forward(self,x):
hidden=torch.zeros(num_layers,x.size(0),hidden_size)
#输入应该位长张量
x=self.emb(x) #(batch,seqlen,embeddingsize)
x,_=self.rnn(x,hidden)
x=self.fc(x)
return x.view(-1,num_class)
net=Model()
criterion=torch.nn.CrossEntropyLoss()
optimizor=torch.optim.Adam(net.parameters(),lr=0.05)
#Training steps
for epoch in range(15):
optimizor.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizor.step()
# 输出预测
_, idx = outputs.max(dim=1)
idx = idx.data.numpy()
print('Predicted string:', ''.join([idx2char[x] for x in idx]), end='')
print(',Epoch [%d/15] loss=%.3f' % (epoch + 1, loss.item()))
结果展示:
Predicted string: lllll,Epoch [1/15] loss=1.301
Predicted string: ollol,Epoch [2/15] loss=0.979
Predicted string: ollol,Epoch [3/15] loss=0.702
Predicted string: ohlol,Epoch [4/15] loss=0.474
Predicted string: ohlol,Epoch [5/15] loss=0.319
Predicted string: ohlol,Epoch [6/15] loss=0.215
Predicted string: ohlol,Epoch [7/15] loss=0.145
Predicted string: ohlol,Epoch [8/15] loss=0.100
Predicted string: ohlol,Epoch [9/15] loss=0.070
Predicted string: ohlol,Epoch [10/15] loss=0.049
Predicted string: ohlol,Epoch [11/15] loss=0.035
Predicted string: ohlol,Epoch [12/15] loss=0.025
Predicted string: ohlol,Epoch [13/15] loss=0.018
Predicted string: ohlol,Epoch [14/15] loss=0.014
Predicted string: ohlol,Epoch [15/15] loss=0.011
进程已结束,退出代码为 0
五、LSTM与GRU
6、LSTM
这里其实比较抽象,但是如果学懂了RNN可以开始理解,这里有一篇写的比较好的文章,可以从这里链接过去看一看
1、模型图
2、实际上什么什么门,他都是一堆公式如下图所示:
3、LSTM输入输出规定
4、GRU
因为在LSTM虽然效果比RNN好得多,但是计算量大,运算时间长。 那我们可以折中构成GRU
如下:
由于GRU和LSTM理解不深,所以这里贴的大概是个过程,如有需要文中有些链接,可供学习。
文中大多理解和截图都来源B站刘二大人 老师的教学视频,代码由自己手动实现。
完结。若有任何错误,敬请指正,谢谢!