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

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

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如下(暂时不考虑测试集)。

inputlabel
[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:

inputlabels
[-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(verse1)#诗句长度
    embedding_size=2#embedding后的词向量长度
    inputs,labels=make_data(voc_size,embedding_size)#产生数据
    hidden_size=3#模型中haddensize的长度
    hidden=torch.rand(hidden_size)
    output_size=len(verse2)
    criterion = nn.CrossEntropyLoss()#使用交叉熵
    rnn=RNN(hidden_size,embedding_size,output_size)
    optimizer = optim.Adam(rnn.parameters(),lr=0.001)#使用Adam优化算法更新参数
    #设置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)

3.2 N vs 1(多输入单输出)

结构如下图所示,此时输入序列与输出序列不等长,输出为一。相比于NvsN,我们将网络改造成只在最后一层进行输出即可。此模型常用于分类器。
在这里插入图片描述
以人名分类器为例,我们输入名字中的一个个字母,输入完成后对结果进行输出预测,并反向传播训练参数。
数据如下:

 {'Abrahams':'英国','Maksimov':'尔罗斯','Sam':'中国','Rushbrooke':'英国','Shen':'中国'}

生成国家字典,以备生成labels。
代码如下:

country_dict={x:i for i,x in enumerate(set(country))}

生成的字典如下:

{'中国': 0, '尔罗斯': 1, '英国': 2}

此时可将26个字母(大写可转为小写)embedding成长度为3的词向量,而人名中包含的字母序列刚好作为N输入,国家名字典映射的数字作为label。
代码如下:

name=[]
country=[]
for dic in name_and_country:
    name.append(dic)
    country.append(name_and_country[dic])
country_dict={x:i for i,x in enumerate(set(country))}
embedding = nn.Embedding(26, 3, sparse=True)#26表示英文字母,3表示embedding后的词向量尺寸
inputs=[]
labels=[]
for name_str in name:
    name_word=[]
    for word in name_str:
        name_word.append(embedding(torch.tensor(ord(word.lower())-ord('a'))))
    inputs.append(name_word)
    labels.append(country_dict[name_and_country[name_str]])

生成的部分inputs如图所示:
在这里插入图片描述
label如下:
在这里插入图片描述
此时数据集已经制作完成,相对于NvsN,Nvs1的变化是不是每一步输入都进行输出,而是最后一个输出作为关键点进行分类和模型反向传播训练。我们的模型并没有变更,只是改变了其训练方法,故训练和检测代码如下:

#设置30个epoch训练模型
    for epoch in range(30):
        for i,name_voc in enumerate(inputs):#name_voc:某一人名的全部词向量
            for word_vector in name_voc:#word_vector:某一人名的某一词向量
                output,hidden=rnn(word_vector,hidden)
            optimizer.zero_grad()
            loss = criterion(output.unsqueeze(0), labels[i].unsqueeze(0))
            loss.backward(retain_graph=True)
            optimizer.step()
    #效果检测
    result=[]
    for i,name_voc in enumerate(inputs):
        for word_vector in name_voc:
            output,hidden=rnn(word_vector,hidden)
        _,idx=output.max(0)
        result.append(list(set(country))[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(name_and_country,voc_size,embedding_size):
    name=[]
    country=[]
    for dic in name_and_country:
        name.append(dic)
        country.append(name_and_country[dic])
    country_dict={x:i for i,x in enumerate(set(country))}
    embedding = nn.Embedding(voc_size, embedding_size, sparse=True)#voc_size:26,表示26个字母。embedding_size:缩放后的词向量,此处为3
    inputs=[]
    labels=[]
    for name_str in name:
        name_word=[]
        for word in name_str:
            name_word.append(embedding(torch.tensor(ord(word.lower())-ord('a'))))
        inputs.append(name_word)
        labels.append(country_dict[name_and_country[name_str]])
    return inputs,Variable(torch.LongTensor(labels))
if __name__=="__main__":
    name_and_country={'Abrahams':'英国','Maksimov':'尔罗斯','Sam':'中国','Rushbrooke':'英国','Shen':'中国'}
    voc_size=26#字母个数
    embedding_size=3#embedding后的词向量长度
    inputs,labels=make_data(name_and_country,voc_size,embedding_size)#产生数据
    hidden_size=3#模型中haddensize的长度
    hidden=torch.rand(hidden_size)
    country_dict={x:i for i,x in enumerate(set(country))}#国家列表
    output_size=len(set(country_dict))#国家数量
    criterion = nn.CrossEntropyLoss()#使用交叉熵
    rnn=RNN(hidden_size,embedding_size,output_size)
    optimizer = optim.Adam(rnn.parameters(),lr=0.001)#使用Adam优化算法更新参数
    #设置30个epoch训练模型
    for epoch in range(30):
        for i,name_voc in enumerate(inputs):#name_voc:某一人名的全部词向量
            for word_vector in name_voc:#word_vector:某一人名的某一词向量
                output,hidden=rnn(word_vector,hidden)
            optimizer.zero_grad()
            loss = criterion(output.unsqueeze(0), labels[i].unsqueeze(0))
            loss.backward(retain_graph=True)
            optimizer.step()
    #效果检测
    result=[]
    for i,name_voc in enumerate(inputs):
        for word_vector in name_voc:
            output,hidden=rnn(word_vector,hidden)
        _,idx=output.max(0)
        result.append(list(set(country))[idx])
    print(result)

3.3 1 vs N(单输入多输出)

与NvsN的区别在于,其输入统一且需要一个开始信号量(BOS)、一个结束信号量(EOS)。模型常用于由图像生成相应的场景文字,即"看图说话"。机理介于1vsN和NvsM之间,这里的图片需要attention机制才能表现出更好的效果,不再进行代码演示。
在这里插入图片描述

3.4 N vs M(多输入多输出)

网络结构如下图所示,这是一种不限制输入输出长度的RNN结构,首先进行编码生成信息压缩量C,再由C解码生成相应的输出,也被称为seq2seq架构。因为不限制输入输出长度的优点,此模型常用于文本生成和机器翻译。
在这里插入图片描述
上述模型架构有一个缺点,编码后数据压缩量C对于所要进行生成的文本贡献量统一,不能体现原始文本和生成文本两者并行生成的特点。
我们以机器翻译的某个句子为例,原文本为"我爱中国",翻译成的文本为"I love china"。“我爱中国"分割四个输入"我”、“爱”、“中”、“国”,对应图片中的x1、x2、x3、x4;“I love china"分割成三个输出"I”、“love”、“china”,对应上图y1、y2、y3。根据翻译特点,此时"我"对应"I",“爱"对应"love”,“中"和"国"一起对应"china”,但这个重要的特征在网络结构中没有体现。网络编码生成C,由C统一解码生成翻译语句,“我”、“爱”、“中”、"国"对于"I"的贡献值相同,“我”、“爱”、“中”、"国"对于"love"的贡献值相同,“我”、“爱”、“中”、"国"对于"china"的贡献值相同,模型是不符合常规认知的,实际效果也比较差。
网络结构不合理,我们需要进行改造,使原始文本和翻译文本生成顺序关联。我们观察编码器hidden的h1、h2、h3、h4,发现可以利用该序列与翻译文本相嵌。使用h1、h2、h3、h4生成c的过程如下:
在这里插入图片描述
a1j的计算:
在这里插入图片描述
a2j的计算:
在这里插入图片描述
a3j的计算:
在这里插入图片描述
h和h’的合成可使用余弦相似度计算、向量拼接后使用全连接层拟合等方法,加入h进行运算的巧妙过程也被称为Attention机制。
我们进行演示代码编写。
首先我们进行编码:

source_word=["我","爱","中","国"]
target_word=["I","love","china"]
target_word_dict={x:i for i,x in enumerate(target_word)}
target_word_dict['EOS']=len(target_word_dict)#加入结束标志符

编码后的目标语句词典:

   {'I': 0, 'love': 1, 'china': 2, 'EOS': 3}

接下来我们生成数据集:

#产生数据
def make_data(source_word,target_word,voc_size,embedding_size):
    embedding = nn.Embedding(voc_size, embedding_size, sparse=True)
    inputs=[]
    labels=[]
    for i in range(len(source_word)):#我们的输入只有一个句子,可以按照句子单词序列进行编码。这里只是作为演示,后续大规模翻译需要修改
        inputs.append(embedding(torch.tensor(i)))
    for i in range(len(target_word)):#我们的输出也只有一个句子,可以按照句子序列进行编码
        labels.append(target_word_dict[target_word[i]])
    labels.append(target_word_dict["EOS"])
    return inputs,Variable(torch.LongTensor(labels))

数据集样式如下:

inputslabels
[[-0.9799, 2.0680],[ 0.7484, -0.6000],[1.5033, 1.0036], [-1.3108, 1.1188]]0(对应"I")
[[-0.9799, 2.0680],[ 0.7484, -0.6000],[1.5033, 1.0036], [-1.3108, 1.1188]]1(对应"love")
[[-0.9799, 2.0680],[ 0.7484, -0.6000],[1.5033, 1.0036], [-1.3108, 1.1188]]2(对应"China")
[[-0.9799, 2.0680],[ 0.7484, -0.6000],[1.5033, 1.0036], [-1.3108, 1.1188]]3(对应"EOS")

我们输入inputs产生c,再由c产生output(此处的c有编码器的hidden和解码器的hidden求余弦相似度求得)。
编码器用于生成并收集h1、h2、h3、h4,用于后续c的计算:

#编码器,用于生成编码器的hidden列表
    def encoder(self,inputs):
        self.hidden_list=[]#用于h1*a1+h2*a2+h3*a3+h4*a4的计算
        for i in range(len(inputs)):
            middle=torch.cat((inputs[i],self.hidden_encoder_value),-1)
            self.hidden_encoder_value=self.hidden_encoder(middle)
            self.hidden_list.append(self.hidden_encoder_value)

解码器部分直接生成翻译词,此处和传统rnn模块的输出几乎相同:

#解码器,用于生成翻译词
    def decoder(self,hidden):
        c=0
        for i in range(len(self.hidden_list)):
            similarity=torch.cosine_similarity(self.hidden_list[i],torch.tensor(hidden),dim=0)
            c+=similarity*self.hidden_list[i]
        middle=torch.cat((c,hidden),-1)
        self.hidden_decoder_value=self.hidden_decoder(middle)
        out=self.softmax(self.out(middle))
        return out

训练过程,我们先计算编码器的h1、h2、h3、h4值,再由h1、h2、h3、h4与译码器的h’值计算余弦相似度得出c,此后由c产生output(每生成一个output,c都要重新计算)。初始编译器的hidden为“BOS”(不以BOS开始,机器不知道应该从哪个词开始翻译),训练代码如下:

#训练模型
    def train(self,inputs,labels,epochs):
        criterion = nn.CrossEntropyLoss()#使用交叉熵
        optimizer = optim.Adam(model.parameters(), lr=0.001)#使用Adam优化算法更新参数
        for epoch in range(epochs):
            self.encoder(inputs)#encoder生成hidden列表,用于h1*a1+h2*a2+h3*a3+h4*a4的计算
            for i in range(len(labels)):
                if i==0:#刚开始翻译,此时输入序列为bos而不是hidden
                    output=self.decoder(self.bos)
                else:
                    output=self.decoder(self.hidden_decoder_value)
                optimizer.zero_grad()
                loss = criterion(output.unsqueeze(0), labels[i].unsqueeze(0))
                loss.backward(retain_graph=True)
                optimizer.step()

训练完成后进行效果检测:

model=RNN(hidden_size,embedding_size,output_size)
#设置150个epoch训练模型
model.train(inputs,labels,150)
#效果检测
result_list=model(inputs)
result=[]
print()
target_word.append("EOS")#为了简便,直接在原句中加入“EOS”作为结束标志
for i in range(len(result_list)):
    result.append(target_word[result_list[i]])
print("原始句:",source_word)
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_encoder_value=torch.rand(hidden_size)#编码器hidden值
        self.hidden_decoder_value=torch.rand(hidden_size)#解码器hidden值
        self.bos=torch.rand(hidden_size)#BOS:开始翻译标志
        self.hidden_encoder = nn.Linear(hidden_size+embedding_size, hidden_size)#编码器
        self.hidden_decoder = nn.Linear(hidden_size*2, hidden_size)#解码器
        self.out=nn.Linear(hidden_size*2, output_size)#用于输出翻译的词概率
        self.softmax = nn.Softmax(dim=-1)
    #编码器,用于生成编码器的hidden列表
    def encoder(self,inputs):
        self.hidden_list=[]#用于h1*a1+h2*a2+h3*a3+h4*a4的计算
        for i in range(len(inputs)):
            middle=torch.cat((inputs[i],self.hidden_encoder_value),-1)
            self.hidden_encoder_value=self.hidden_encoder(middle)
            self.hidden_list.append(self.hidden_encoder_value)
    #解码器,用于生成翻译词
    def decoder(self,hidden):
        c=0
        for i in range(len(self.hidden_list)):
            similarity=torch.cosine_similarity(self.hidden_list[i],torch.tensor(hidden),dim=0)
            c+=similarity*self.hidden_list[i]
        middle=torch.cat((c,hidden),-1)
        self.hidden_decoder_value=self.hidden_decoder(middle)
        out=self.softmax(self.out(middle))
        return out
    #前向传播层
    def forward(self,inputs):
        self.encoder(inputs)#encoder生成hidden列表,用于h1*a1+h2*a2+h3*a3+h4*a4的计算
        out_word_lst=[]
        for i in range(len(labels)):#设置最大翻译长度,防止翻译迟迟不结束
            if i==0:#刚开始翻译,此时输入序列为bos而不是hidden
                output=self.decoder(self.bos)
            else:
                output=self.decoder(self.hidden_decoder_value)
            _,idx=output.max(0)
            out_word_lst.append(idx)
            if idx==len(labels)-1:#最后一个词对应EOS,即碰到翻译结束符马上停止翻译
                break
        return out_word_lst
    #训练模型
    def train(self,inputs,labels,epochs):
        criterion = nn.CrossEntropyLoss()#使用交叉熵
        optimizer = optim.Adam(model.parameters(), lr=0.001)#使用Adam优化算法更新参数
        for epoch in range(epochs):
            self.encoder(inputs)#encoder生成hidden列表,用于h1*a1+h2*a2+h3*a3+h4*a4的计算
            for i in range(len(labels)):
                if i==0:#刚开始翻译,此时输入序列为bos而不是hidden
                    output=self.decoder(self.bos)
                else:
                    output=self.decoder(self.hidden_decoder_value)
                optimizer.zero_grad()
                loss = criterion(output.unsqueeze(0), labels[i].unsqueeze(0))
                loss.backward(retain_graph=True)
                optimizer.step()
#产生数据
def make_data(source_word,target_word,voc_size,embedding_size):
    embedding = nn.Embedding(voc_size, embedding_size, sparse=True)
    inputs=[]
    labels=[]
    for i in range(len(source_word)):#我们的输入只有一个句子,可以按照句子单词序列进行编码。这里只是作为演示,后续大规模翻译需要修改
        inputs.append(embedding(torch.tensor(i)))
    for i in range(len(target_word)):#我们的输出也只有一个句子,可以按照句子序列进行编码
        labels.append(target_word_dict[target_word[i]])
    labels.append(target_word_dict["EOS"])
    return inputs,Variable(torch.LongTensor(labels))
if __name__=="__main__":
    source_word=["我","爱","中","国"]
    target_word=["I","love","china"]
    target_word_dict={x:i for i,x in enumerate(target_word)}
    target_word_dict['EOS']=len(target_word_dict)#加入结束标志符
    voc_size=len(source_word)#输入文本词汇总数
    embedding_size=2#embedding后的词向量长度
    inputs,labels=make_data(source_word,target_word,voc_size,embedding_size)#产生数据
    hidden_size=3#模型中hidden的长度
    output_size=len(labels)#翻译词可能输出,此处为4,分别包含"I"、"love"、"china"、"EOS"的概率
    model=RNN(hidden_size,embedding_size,output_size)
    #设置150个epoch训练模型
    model.train(inputs,labels,150)
    #效果检测
    result_list=model(inputs)
    result=[]
    print()
    target_word.append("EOS")#为了简便,直接在原句中加入“EOS”作为结束标志
    for i in range(len(result_list)):
        result.append(target_word[result_list[i]])
    print("原始句:",source_word)
    print("翻译句:",result)

4.总结

本篇博客主要根据输入输出类型的区别,对基本模型进行了构建和演示代码编写。RNN由一开始的多输入单输出,到现在的多种输入输出结构,离不开基本模型的变型。我们在处理现实任务时,要因地制宜,选择或搭建属于我们自己的模型。

5.参考资料

1、https://www.bilibili.com/video/BV17y4y1m737?from=search&seid=16275505917373064546(黑马程序员视频,对自然语言处理的基础知识进行了讲解)
2、https://zhuanlan.zhihu.com/p/28054589(原理参考)
3、https://blog.csdn.net/sinat_28015305/article/details/109355828(原理参考)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值