第十二讲循环神经网络(基础篇)

第十二讲循环神经网络 (基础篇)学习与代码

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可以开始理解,这里有一篇写的比较好的文章,可以从这里链接过去看一看

如何从RNN起步,一步步通俗理解LSTM

1、模型图

 

2、实际上什么什么门,他都是一堆公式如下图所示:

3、LSTM输入输出规定

 4、GRU

因为在LSTM虽然效果比RNN好得多,但是计算量大,运算时间长。 那我们可以折中构成GRU

如下:


由于GRU和LSTM理解不深,所以这里贴的大概是个过程,如有需要文中有些链接,可供学习。

文中大多理解和截图都来源B站刘二大人 老师的教学视频,代码由自己手动实现。


完结。若有任何错误,敬请指正,谢谢! 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值