Pytorch利用RNNCell实现字符串转变——并利用Embedding层进行修改

RNN(循环神经网络)当中主要的是有RNN Cell构成的,RNN Cell是同一个Linear层,是各个阶段共享的;RNN Cell主要将输入的Xt和ht-1经过线性变化后,然后再融合,并通过激活函数得到ht,从而将ht作为下一个RNN Cell的输入,然后一直到最后输出hidden结果。

使用RNN Cell训练ohlol——>hello的模型:
(1)首先应该注意,RNN Cell的输入必须是由数字构成的向量
ps:
一般在做自然语言处理的时候,比如遇到字符级别的数据,需要先根据所得的字符,构造一个词典,这里出现哪些字符或词,然后给每一个字符或者词分配一个索引(索引可以按照字典的顺序,从0依次开始;也可以随机分配)
(2)构造完词典后,将所得字符串的每一个字符都分配完索引,然后将该结果转换成向量;即除了索引的地方为1之外,其余词的地方都为0,构造一个多维向量。(构造的词典有几个词,这里的向量就有几维
(3)然后将所得结果,经过Softmax之后预测出每一个词所得到的概率,并于最终想要的结果之间计算损失。这里采用交叉熵损失。

Pytorch实现:

# -*- coding: utf-8 -*-
# @Time : 2022/2/2 14:27
# @Author : CH339
# @FileName: Test2_2_1.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_56068397/article/

'''
RNNCell:ohlol——>hello
'''

import torch
# 参数准备
input_size = 4
hidden_size = 4
batch_size = 1
# 准备数据
# 提供词典,按照字典顺序排序
data = ['e','h','l','o']
# ohlol输入数据的下标
input_data = [3,1,2,3,2]
# 输出的下标:hello
out_data = [1,0,2,2,3]
# 定义独热编码
one_hot = [[1,0,0,0],
           [0,1,0,0],
           [0,0,1,0],
           [0,0,0,1]]
# 将输入的数据转化成独热编码的形式(取出下标)
x_one_hot = [one_hot[x] for x in input_data]
inputs = torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
labels = torch.LongTensor(out_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
        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

    # 初始化h0
    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.1)

for epoch in range(100):
    loss = 0
    # 梯度清零
    optimizer.zero_grad()
    # 定义h0
    hidden = net.init_hidden()
    print("预测的结果:",end=' ')
    for input,label in zip(inputs,labels):
        # RNN进行训练
        hidden = net(input,hidden)
        # 这里输出时有多个结果,所以这里是张量进行计算
        loss += criterion(hidden,label)
        # 获得概率最大的索引
        _,idx = hidden.max(dim=1)
        print(data[idx.item()],end=' ')

    # 反向传播
    loss.backward()
    # 权重更新
    optimizer.step()
    print('Epoch[%d/15] loss=%.4f'%(epoch+1,loss.item()))

经过100个Epoch,我们可以看到,到所有样本迭代到10次时,已经能实现hello字符的转化;也可以通过增加迭代的次数使得loss降低。
在这里插入图片描述

注意:
本次实现采用的是将所得字符转化的数字向量转换成one-hot编码;但是one-hot编码却有缺点:(1)当数据较多时向量维度较大(2)向量中多为0,向量较为稀疏(3)硬编码;
因此我们可以通过增加Embedding层(嵌入层),设法将向量改变成(1)低维度(2)稠密(3)可以从数据当中学习到。

使用Embedding代码实现:

# -*- coding: utf-8 -*-
# @Time : 2022/2/2 16:18
# @Author : CH339
# @FileName: Test2_2_2.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_56068397/article/

'''
使用Embedding层实现RNN
'''

import torch
# 参数准备
num_class = 4
input_size = 4
hidden_size = 8
embedding_size = 10
# RNN层数
num_layers = 2
batch_size = 1
seq_len = 5
# 准备数据
# 提供词典,按照字典顺序排序
data = ['e','h','l','o']
# ohlol输入数据的下标
input_data = [[3,1,2,3,2]]
# 输出的下标:hello
out_data = [1,0,2,2,3]
inputs = torch.LongTensor(input_data)
labels = torch.LongTensor(out_data)

# 定义模型类
class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        # 嵌入层
        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)
        x,_ = self.rnn(x,hidden)
        x = self.fc(x)
        return x.view(-1,num_class)

net = Model()
# 损失函数
criterion = torch.nn.CrossEntropyLoss()
# 优化器
optimizer = torch.optim.Adam(net.parameters(),lr=0.05)

for epoch in range(100):
    # 梯度清零
    optimizer.zero_grad()
    outputs = net(inputs)
    loss = criterion(outputs,labels)
    # 反向传播
    loss.backward()
    # 权重更新
    optimizer.step()
    _,idx = outputs.max(dim=1)
    idx = idx.data.numpy()
    print("预测结果:",''.join([data[x] for x in idx]),end=' ')
    print('Epoch[%d/15] loss=%.3f'%(epoch+1,loss.item()))

从训练结果就可以看出,通过将one-hot编码改成使用embedding层后,不仅在少量Epoch就可以得到最终结果,同时也可以降低预测时的loss。
在这里插入图片描述
如上图所示,经过5轮就可以得出结果。

在这里插入图片描述
并且经过60轮后,loss降低至0.001。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值