自然语言处理(三):传统RNN(NvsN,Nvs1,1vsN,NvsM)pytorch代码解析

本文详细介绍了深度神经网络(DNN)与RNN在处理序列数据时的转变,包括NvsN、Nvs1、1vsN和NvsM结构的应用,以及如何解决输入输出长度变化的问题。通过实例演示了RNN在温度预测、人名分类和机器翻译中的应用,展示了注意力机制在编码解码过程中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.预备知识:深度神经网络(DNN)

DNN输入固定数量(如下图中为3个)的数据,前向传播输出output,与真实值求loss后反向传播更新参数,进行模型训练。如下图所示,我们每次输入固定数量的X1、X2、X3数据,训练得到正确的output输出。在这里插入图片描述

2.RNN出现的意义与基本结构

假定我们正在做一个温度预测的时间序列任务,模型根据n-1天的历史温度数据,预测第n天的温度。
任务如下:

  1. 第一天温度为:26,此时通过该数据预测第二天温度
  2. 第二天温度为:27,此时用第一天和第二天的温度数据预测第三天温度,即通过数据序列[26,27]预测第三天温度
  3. 第三天温度为:29,参考上一条,此时通过数据序列[26,27,29]预测第四天温度。
  4. 第四天温度为:30,通过数据序列[26,27,29,30]预测第五天温度。
  5. 第五天温度为:32,通过数据序列[26,27,29,30,32]预测第六天温度。

我们只取前5天的数据作为训练样本进行解析,即我们拥有的训练数据为[26,27,29,30,32]。
传统的深度神经网络(DNN),输入尺寸大小固定。我们统一使用2天的温度数据预测第3天的温度,得到的训练数据inputs和labels如下(暂时不考虑测试集)。

input label
[26,27] 29
[27,29] 30
[29,30] 32

按照传统的DNN,我们已经完成训练数据的制作和神经网络大致模型的构建。但是这里要提出一个疑问,某一天的温度是否和两天前的环境温度不存在联系。
我们都知道温度是渐变的,每一天的温度都与该天温度的前m天温度息息相关(m为非固定值,需要我们去学习,所以更加不可以使用DNN这种输入数据量固定的模型)。

按照直观感受:

  1. 相较于使用数据[27,29]去拟合数据30,用前三天数据[26,27,29]去拟合第四天的温度(数据30)效果会更好。
  2. 相较于使用数据[29,30]去拟合数据32,用前四天数据[26,27,29,30]去拟合第五天的温度(数据32)效果会更好。

此时输入数据量不再固定,而是递增的,DNN不适应这种情况。我们提出一种新的模型,模型每次都只输入一个数据,数据量为n时输入n次,输入过程中进行信息积累,这样我们就解决了输入量不固定且数据间有序列关系的问题。
rnn网络结构:
一般单层神经网络架构:
在这里插入图片描述

rnn单层神经网络结构:
在这里插入图片描述
时间步展开的rnn网络结构:
在这里插入图片描述

3.根据输入和输出数量的网络结构分类

3.1 N vs N(输入和输出序列等长)

如下图所示,这个结构是rnn最基础的,每输入一个数据,输出一个对应的output。因为输入序列与输出序列等长,所以用途较为狭小,可用作生成等长度的诗句。
在这里插入图片描述
以“落木千山天远大,澄江一道月分明”诗句为例,进行解析。
首先进行分词,这里我们可以使用结巴分词。

import jieba
verse1=jieba.lcut("落木千山天远大", cut_all=False)
verse2=jieba.lcut("澄江一道月分明", cut_all=False)

分割后的内容为:

 verse1=['落木', '千山', '天', '远大']
 verse2=['澄江', '一道', '月', '分明']

编码后:

 {'落木': 0, '千山': 1, '天': 2, '远大': 3}
 {'澄江': 0, '一道': 1, '月': 2, '分明': 3}

我们使用pytorch的Embedding模块对verse1进行编码(verse2作为label,无需编码):

nn.Embedding(voc_size, embedding_size, sparse=True)

Embedding后生成的verse1的词向量为(pytorch的Embedding词向量是随机生成的,如果想要产生更有内联性的词向量,需要自己训练参数,再将其导入):

 '落木':[-0.0482, -0.9568,  0.7512]
 '一道':[ 0.0399,  0.1087, -2.0304]
 '月':[0.1200, 0.2021, 1.7677]
 '分明':[-0.4733, -0.7433,  2.7065]

此时我们已经得到输入数据和labels:

input labels
[-0.0482, -0.9568, 0.7512] 0(‘落木’对应’澄江’,'澄江’编码为0)
[ 0.0399, 0.1087, -2.0304] 1(‘千山’对应’一道’,'一道’编码为0)
[ 0.0399, 0.1087, -2.0304] 2(’ 天 ‘对应’月’ , '月’编码为0)
[-0.4733, -0.7433, 2.7065] 3(‘远大’对应’分明’,'分明’编码为0)

构建神经网络,此处关键点在于每次输入hidden后,我们输出新的一个hidden用于下一次的输入:

class RNN(nn.Module):
    #模型初始化
    def __init__(self,hidden_size,embedding_size,output_size):
        super(RNN,self).__init__()
        self.hidden = nn.Linear(hidden_size+embedding_size, hidden_size)
        self.out=nn.Linear(hidden_size+embedding_size, output_size)
        self.softmax = nn.Softmax(dim=-1)
    #前向传播层
    def forward(self,inputs,hidden):
        middle=torch.cat((inputs,hidden),-1)#拼接输入诗词和hidden
        hidden=self.hidden(middle)
        output=self.softmax(self.out(middle))
        return output,hidden

进行模型训练并检测结果:

#设置300个epoch训练模型
    for epoch in range(300):
        for j in range(voc_size):
            output,hidden=rnn(inputs[j],hidden)
            optimizer.zero_grad()
            loss = criterion(output.unsqueeze(0), labels[j].unsqueeze(0))
            loss.backward(retain_graph=True)
            optimizer.step()
    #效果检测
    result=[]
    for i in range(voc_size):
        output,hidden=rnn(inputs[i],hidden)
        _,idx=output.max(0)
        result.append(verse2[idx])
    print(result)

得出结果如下,可以看出模型预测结果正确(这里训练集和测试集统一,只是作为一个测试例子):

 ['澄江', '一道', '月', '分明']

完整代码如下:

import torch.nn as nn
import torch
import jieba
import torch.optim as optim#优化器
from torch.autograd import Variable
class RNN(nn.Module):
    #模型初始化
    def __init__(self,hidden_size,embedding_size,output_size):
        super(RNN,self).__init__()
        self.hidden = nn.Linear(hidden_size+embedding_size, hidden_size)
        self.out=nn.Linear(hidden_size+embedding_size, output_size)
        self.softmax = nn.Softmax(dim=-1)
    #前向传播层
    def forward(self,inputs,hidden):
        middle=torch.cat((inputs,hidden),-1)#拼接输入诗词和hidden
        hidden=self.hidden(middle)
        output=self.softmax(self.out(middle))
        return output,hidden
#产生数据单元
def make_data(voc_size,embedding_size):
    embedding = nn.Embedding(voc_size, embedding_size, sparse=True)
    inputs=[]
    labels=[]
    for i in range(voc_size):
        inputs.append(embedding(torch.tensor(i)))
        labels.append(i)
    return inputs,Variable(torch.LongTensor(labels))
if __name__=="__main__":
    verse1=jieba.lcut("落木千山天远大", cut_all=False)
    verse2=jieba.lcut("澄江一道月分明", cut_all=False)
    voc_size=len
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值