`
wx1568037608
  • 浏览: 33504 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

[实现] 利用 Seq2Seq 预测句子后续字词 (Pytorch)

 
阅读更多

最近有个任务:利用 RNN 进行句子补全,即给定一个不完整的句子,预测其后续的字词。
本文使用了 Seq2Seq 模型,输入为5个中文字词,输出为一个中文字词。

目录

  1. 关于RNN

  2. 语料预处理

  3. 搭建数据集

  4. 搭建模型

  5. 训练模型

  6. 测试模型

  7. 保存/加载模型

 

1.关于RNN

自被提出以来,循环神经网络(Recurrent Neural Networks,RNN) 在 NLP 领域取得了巨大的成功与广泛的应用,也由此催生出了许多新的变体与网络结构。由于网上有众多资料,在此我也只做简单的讲解了。
首先,讲讲 RNN cell 及其变体:
(1) vallina RNN cell

不同于常见的神经网络结构,RNN 的输入为时序输入,每一时刻的输入对神经元的隐状态产生影响,从而影响后续所有时刻的输出。
其中,隐藏层的公式如下所示:
O_{t} = g(V* S_t), S_t = f(U*X_t+W*S_{t-1})Ot=g(V∗St),St=f(U∗Xt+W∗St−1)

(2) LSTM cell

LSTM(Long short-term memory,长短期记忆)极大程度的解决了长序列训练过程中的梯度消失和梯度爆炸问题。

(3) GRU cell
GRU(Gate Recurrent Unit)与 LSTM 一样,也极大程度的解决了长序列训练过程中的梯度消失和梯度爆炸问题。但是,与 LSTM 相比,GRU 所需要的计算资源更小,往往工程实现时更倾向于使用 GRU。

接着,讲讲网络结构:

(1) 常见结构:

(2) Bi-directional RNN

(3) Deep Bi-directional RNN

(4) Seq2Seq

(5) Attention

参考资料:

 

2.语料预处理

由于这次使用的语料为中文语料,自然需要对其进行分词,并构造词典。
首先,收集所用的句子,利用 jieba 库,对每个句子进行分词,并将所得结果加入 word_set 中。
接着,对 word_set 中的所有字词构建统计词典。

代码:

import osimport jsonimport jiebaimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimfrom torch.autograd import Variableimport torchvisionimport torchvision.datasets as datasetsimport torchvision.transforms as transformsfrom torch.utils.data import DataLoader,Dataset# Set Hyper ParametersLR = 0.005EPOCH = 100BATCH_SIZE = 1Sentence_Num = 100Embedding_Dim = None# Bulid Vocabsentence_set = []								# 收集所用到的文本句子for index in range(Sentence_Num):
    with open('../../Corpus/CAIL2018/'+str(index)+'.txt','r',encoding='UTF-8') as f:
        sentence_set.append(f.read().replace('\n', '').replace('\r', '').replace(',', ' ').replace('。', ' ').replace(':', ' ').replace('  ', ' ').lower())
        word_set = set()								# 利用jieba库进行中文分词for sentence in sentence_set:
    words = jieba.lcut(sentence)
    word_set.update(words)
    word_to_ix = {'SOS':0, 'EOS':1, 'UNK':2}		# 'SOS': start of sentencexix_to_word = {0:'SOS', 1:'EOS', 2:'UNK'}		# 'EOS': end of sentence
												# 'UNK': unknown tokenfor word in word_set:							# 构建词典,注意:word_to_ix用于对字词进行编号,ix_to_word用于将模型的输出转化为字词
    if word not in word_to_ix:
        word_to_ix[word] = len(word_to_ix)
        ix_to_word[len(ix_to_word)] = word

Embedding_Dim = len(word_to_ix)        
        with open('./Vocab.txt','w',encoding='UTF-8') as f: # 保存词典
    for vocab in word_to_ix.items():
        f.write(vocab[0]+'   '+str(vocab[1])+'\n')

参考资料:

 

3.搭建数据集

由于所使用的中文文本并无数据集格式,故我们需要自己制作数据集。
注意,代码中的 bulid_one_hot 并非生成 one-hot 向量。这是因为模型中使用了 nn.Embedding() ,它会初始一个矩阵,相当于我们模型再训练过程中,顺便训练了一个 word embedding matrix。
至于如何使用该函数进行 word embedding ,大家可以查阅本小节的参考资料。

代码:

# Bulid Datasetdef bulid_one_hot(word,word_dict):
    if word in word_dict:
        return torch.LongTensor([word_dict[word]])
    return torch.LongTensor([word_dict['UNK']])

   class MyDataset(Dataset):
    def __init__(self, words, labels, transform=None, target_transform=None): 
        self.words = words
        self.labels = labels
        self.transform = transform
        self.target_transform = target_transform        
    def __getitem__(self, index):
        words, labels = self.words[index], self.labels[index]
        if self.transform is not None:
            words = [self.transform(word) for word in words]
        if self.target_transform is not None:
            labels = self.target_transform(labels)
        return words, labels    def __len__(self): 
        return len(self.labels)train_words, train_labels, test_words, test_labels = [], [], [], []for i in range(int(0.9*Sentence_Num)):
    sentence = sentence_set[i] 
    words =  jieba.lcut(sentence)
    words.insert(0,'SOS')
    words.append('EOS')
    words = [bulid_one_hot(word,word_to_ix) for word in words]

    for j in range(0,len(words),6):
        if j+6 >= len(words):
            break
        train_words.append(words[j:j+5])
        train_labels.append(words[j+5])
    for i in range(int(0.9*Sentence_Num),Sentence_Num):
    sentence = sentence_set[i]
    words =  jieba.lcut(sentence)
    words.insert(0,'SOS')
    words.append('EOS')
    words = [bulid_one_hot(word,word_to_ix) for word in words]
    
    for j in range(0,len(words),6):
        if j+6 >= len(words):
            break
        test_words.append(words[j:j+5])
        test_labels.append(words[j+5])
    trans, target_trans = None, None # transforms.ToTensor(), transforms.ToTensor()train_set = MyDataset(train_words, train_labels, trans, target_trans)train_loader = DataLoader(dataset=train_set, batch_size=BATCH_SIZE)test_set = MyDataset(test_words, test_labels, trans, target_trans)test_loader = DataLoader(dataset=test_set, batch_size=BATCH_SIZE)

参考资料:

 

4.搭建模型

采用 GRU 结构构建 Seq2Seq 模型,其中,loss function 为 nn.CrossEntropyLoss(), optimizer 为 optim.SGD()。
注意,pytorch 中采用 nn.CrossEntropyLoss(),对输入与输出有格式要求,请查阅本小节的参考资料。

代码:

# Bulid Seq2Seq Modelclass Encoder(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(Encoder, self).__init__()
        self.hidden_size = hidden_size
        self.embedding = nn.Embedding(input_size, hidden_size)     # 将one-hot向量embedding为词向量
        self.gru = nn.GRU(hidden_size, hidden_size)                # GRU的hidden layer的size与词向量的size一样,并非必须 

    def forward(self, input, hidden):
        embedded = self.embedding(input).view(1, 1, -1)            # RNN的输入格式为 (seq_len, batch, input_size)
        output = embedded
        output, hidden = self.gru(output, hidden)
        return output, hidden    def initHidden(self):
        return torch.zeros(1, 1, self.hidden_size)                 # 初始化Encoder的隐状态 class Decoder(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Decoder, self).__init__()
        self.hidden_size = hidden_size
        self.embedding = nn.Embedding(input_size, hidden_size)
        self.gru = nn.GRU(hidden_size, hidden_size)
        self.out = nn.Linear(hidden_size, output_size)

    def forward(self, input, hidden):
        output = self.embedding(input).view(1, 1, -1)
        output = F.relu(output)
        output, hidden = self.gru(output, hidden)
        output = self.out(output[0])
        return output, hidden    def initHidden(self):
        return torch.zeros(1, 1, self.hidden_size)class Seq2Seq(nn.Module):
    def __init__(self, encoder, decoder):
        super(Seq2Seq, self).__init__()
        self.encoder = encoder 
        self.decoder = decoder    def forward(self, inputs):
        encoder_hidden = self.encoder.initHidden()
        if torch.cuda.is_available():
            encoder_hidden = encoder_hidden.cuda()

        # encode
        for word in inputs:
            encoder_out, encoder_hidden = self.encoder(word, encoder_hidden)
        
        # decode
        decoder_hidden = encoder_hidden
        pred, decoder_hidden = self.decoder(inputs[-1], decoder_hidden)
        
        return pred

    
encoder = Encoder(Embedding_Dim,1000)decoder = Decoder(Embedding_Dim,1000,Embedding_Dim)if torch.cuda.is_available():
    encoder = encoder.cuda()
    decoder = decoder.cuda()
    seq2seq = Seq2Seq(encoder,decoder)if torch.cuda.is_available():
    seq2seq = seq2seq.cuda()
    # Bulid loss function and optimizer loss_func = nn.CrossEntropyLoss()#encoder_optimizer = optim.SGD(encoder.parameters(), lr=LR, momentum=0.9)#decoder_optimizer = optim.SGD(decoder.parameters(), lr=LR, momentum=0.9)seq2seq_optimizer = optim.SGD(seq2seq.parameters(), lr=LR, momentum=0.9)

参考资料:

 

5.训练模型

代码:

# Train Seq2Seq Modelfor epoch in range(EPOCH):  
    loss_sum = 0
    for step, (inputs, labels) in enumerate(train_loader):   
        # encoder_hidden = encoder.initHidden()
        label = torch.LongTensor((1,))
        label[0] = int(labels.data.numpy()[0])

        if torch.cuda.is_available():
            inputs = [word.cuda() for word in inputs]
            label = label.cuda()
            # encoder_hidden = encoder_hidden.cuda() 
            
        # forward
        pred = seq2seq(inputs)
        loss = loss_func(pred,label)
        
        # backward
        seq2seq_optimizer.zero_grad()
        loss.backward()
        seq2seq_optimizer.step()
        
        '''
        for word in inputs:
            encoder_out, encoder_hidden = encoder(word, encoder_hidden)
        decoder_hidden = encoder_hidden
        decoder_out, decoder_hidden = decoder(inputs[-1], decoder_hidden)

        loss = loss_func(decoder_out,label)
        
        #backward
        encoder_optimizer.zero_grad()
        decoder_optimizer.zero_grad()   
        loss.backward()                     
        encoder_optimizer.step()                  
        decoder_optimizer.step()
        '''
    
        loss_sum+= loss.data[0]
    print('Epoch: %2d train loss: %.4f' % (epoch, loss_sum))

结果:

 

6.测试模型

代码:

# Test Seq2Seq Modelfor step, (inputs, labels) in enumerate(test_loader):   
    # encoder_hidden = encoder.initHidden()
    label = torch.LongTensor((1,))
    label[0] = int(labels.data.numpy()[0])
    
    if torch.cuda.is_available():
        inputs = [word.cuda() for word in inputs]
        label = label.cuda()
        # encoder_hidden = encoder_hidden.cuda() 
        
    decoder_output = seq2seq(inputs)
    
    '''
     # forward
    for word in inputs:
        encoder_out, encoder_hidden = encoder(word, encoder_hidden)
    decoder_hidden = encoder_hidden
    decoder_out, decoder_hidden = decoder(inputs[-1], decoder_hidden)
    '''        
        
    # output
    ans = ''
    pred = ''
        
    for word in inputs:
        ix = word.cpu().data.numpy()[0][0]
        ans+=ix_to_word[ix]
        pred+=ix_to_word[ix]

    ans+=ix_to_word[int(labels.data.numpy()[0])]
    pred+=ix_to_word[np.argmax(decoder_output.cpu().data.numpy())]
        
    print('Answer: %s' % ans)
    print('Prediction: %s' % pred)

结果:

上述结果是全部结果中效果不错的,可以观察到:虽然模型无法完全预测后续字词,但是能依照句子的前部分继续生成意思完整的句子。
不过,整体来看模型效果较差,我认为有以下几个原因:

  1. 所用文本数量少,仅用了100个句子进行训练。

  2. 构造的词库小,词典中仅有3000+字词,其中包括许多无意义的字词。

  3. 未对超参数进行微调。

 

7.保存/加载模型

往往大家保存和加载模型都是用的最简单的方法:torch.save(model,path),torch.load(path)
这样的方法不仅将模型的参数保存了下来,还将模型的结构保存了下来。

有时我们只需要保存模型的参数,我们可以采用这样的方法:torch.save(model.state_dict(),path),torch.load_state_dict(torch.load(path))

当然,还有许多复杂的方法可以选择,大家可以查阅参考资料进一步了解。

代码:

# Save Seq2Seq Model'''
torch.save(encoder.state_dict(),'../../Model/Seq2Seq/encoder_params.pkl')
torch.save(decoder.state_dict(),'../../Model/Seq2Seq/decoder_params.pkl')

torch.save(encoder,'../../Model/Seq2Seq/encoder.pkl')
torch.save(decoder,'../../Model/Seq2Seq/decoder.pkl')
'''torch.save(seq2seq.state_dict(),'../../Model/Seq2Seq/seq2seq_params.pkl')torch.save(seq2seq,'../../Model/Seq2Seq/seq2seq.pkl')# Load Seq2Seq Model# encoder.load_state_dict(torch.load('../../Model/Seq2Seq/encoder_params.pkl'))# decoder.load_state_dict(torch.load('../../Model/Seq2Seq/decoder_params.pkl'))seq2seq = torch.load('../../Model/Seq2Seq/seq2seq.pkl')
分享到:
评论

相关推荐

    seq2seq—pytorch实现

    《PyTorch实现Seq2Seq模型详解》 Seq2Seq(Sequence to Sequence)模型是深度学习领域中的一个重要概念,尤其在自然语言处理(NLP)任务中占据着核心地位。这个模型由Sutskever等人在2014年的论文《Sequence to ...

    pytorch实现seq2seq和transformer机器翻译

    在本文中,我们将深入探讨如何使用PyTorch实现Seq2Seq和Transformer架构,这两种方法都是在机器翻译领域中广泛使用的深度学习技术。首先,我们来理解这两个概念。 **Seq2Seq(Sequence to Sequence)模型**: Seq2...

    Python-PyTorch实现的轻量seq2seq文本摘要

    本篇将深入探讨如何利用Python和PyTorch实现轻量级的seq2seq(sequence-to-sequence)模型进行文本摘要。 **一、seq2seq模型基础** seq2seq模型是一种基于RNN(循环神经网络)或Transformer架构的机器学习模型,常...

    RNN+Attention实现Seq2Seq中英文机器翻译(pytorch)实现

    本项目使用RNN(循环神经网络)与Attention机制结合实现Seq2Seq(Sequence to Sequence)模型,以进行中英文之间的翻译。PyTorch是一个流行的深度学习框架,它提供灵活的API来构建和训练复杂模型,这里我们将详细...

    Python-在PyTorch中关注神经机器翻译的最小Seq2Seq模型

    在PyTorch框架中,我们可以构建一个简单的Seq2Seq模型来实现这一功能。Seq2Seq模型由两个主要部分组成:编码器(Encoder)和解码器(Decoder),它们协同工作以捕捉源语言的语义并生成目标语言的对应翻译。 1. **...

    Seq2Seq-PyTorch:使用PyTorch的序列到序列实现

    Seq2Seq-PyTorch 使用PyTorch的序列到序列实现安装克隆项目,进入项目目录并执行python setup.py install 或者pip install ./ 或简单地复制源代码。 推荐使用pip install ./ ,因为您可以先激活虚拟环境,然后再在该...

    pytorch-chatbot:使用PyTorch的Seq2Seq聊天机器人实现

    使用PyTorch的Seq2Seq聊天机器人实现功能:Seq2Seq +光束搜索+ antiLM 要求 Python3 火炬0.3 语料库 用法 训练 python train . py 测试 python console python console . py . / ckpt model 光束搜索示例: me: ...

    pytorch实现seq2seq和transformer字符级中英机器翻译

    在PyTorch中实现Seq2Seq(Sequence to Sequence)架构和Transformer模型是自然语言处理(NLP)领域的重要任务,特别是在机器翻译(Machine Translation, MT)中。Seq2Seq模型通常由一个编码器(Encoder)和一个解码...

    Python-PyTorch中seq2seq模型的一个框架

    在"IBM-pytorch-seq2seq-fede876"这个项目中,可能包含了完整的Seq2Seq模型实现,包括编码器、解码器和注意力模块的代码。这个框架可能还提供了训练和评估模型的功能,以及数据预处理和后处理的工具。通过阅读和理解...

    pytorch采用LSTM实现文本翻译,序列到序列学习Seq2Seq

    下面将详细阐述如何使用PyTorch的LSTM实现Seq2Seq模型,以及在Multi30k数据集上进行德语到英语的文本翻译。 **1. Seq2Seq模型概述** Seq2Seq模型由两部分组成:编码器(Encoder)和解码器(Decoder)。编码器负责...

    chatbot_seq2seq:pytorch实现对话系统,参考官网项目

    《基于PyTorch实现的Chatbot_seq2seq对话系统详解》 在当今信息化社会,人工智能技术正在逐步渗透到我们生活的方方面面,其中对话式聊天机器人(Chatbot)作为人机交互的重要载体,扮演着愈发重要的角色。本文将...

    中文歌词生成, Pytorch, Seq2Seq, Luong注意力, 按不同歌手风格生成歌词

    中文歌词生成, Pytorch, Seq2Seq, Luong注意力, 按不同歌手风格生成歌词 基于Pytorch、Seq2Seq、Luong注意力机制的 中文歌词生成研究, 按不同歌手风格生成歌词 训练数据集来自我收集整理的中文歌词数据库: ...

    基于python的知识库的问答seq2seq模型代码实现

    实现Seq2Seq模型需要一些Python库,如TensorFlow、Keras或PyTorch。这些库提供了构建和训练深度学习模型的便利工具。本项目可能使用了其中的一种,具体依赖于项目文件。 **3. 数据预处理** 在训练模型之前,首先...

    Seq2Seq-PyTorch, 使用PyTorch序列序列序列.zip

    Seq2Seq-PyTorch, 使用PyTorch序列序列序列 带PyTorch的序列序列的序列这个库包含了PyTorch中序列( Seq2Seq ) 模型序列的实现目前它具有以下实现:* Vanilla Sequence to Sequence models* Attention

    基于Pytorch的seq2seq机器翻译深度学习网络模型训练和测试实现

    在提供的"基于Pytorch的seq2seq机器翻译深度学习网络模型训练和测试实现.py"文件中,你可以找到以上步骤的具体实现。文件会详细展示如何加载数据、构建模型、定义损失函数和优化器,以及如何执行训练和测试。阅读和...

    Pytorch-seq2seq-Beam-Search:带有注意力和贪婪搜索束搜索的Seq2Seq模型的PyTorch实现,用于神经机器翻译

    Pytorch-seq2seq-光束搜索 带有注意力和贪婪搜索/波束搜索的Seq2Seq模型,用于在PyTorch中进行神经机器翻译。 此实现着重于以下功能: 用于其他项目的模块化结构 最少的代码以提高可读性 充分利用批处理和GPU。 ...

    seq2seq:基于RNN的序列到序列架构的PyTorch实现

    seq2seq-pytorch是一个框架,用于在实现的基于注意力的序列到序列模型。 该框架具有用于seq2seq模型,训练,推理,检查点等的模块化和可扩展组件。 介绍 Seq2seq将一个序列转换为另一序列。 它通过使用递归神经网络...

    基于pytorch的LSTM多变量多输出时间序列预测使用例

    使用pytorch搭建的简单的LSTM多变量多输出时间序列预测的使用例。 生成了多个以sinx、cosx、tanx构成的序列,使用[i:i+50]的数据预测[i+51]的数据。x是步长为0.1的等差数列

    pytorch-seq2seq-example:基于实用pytorch和更多额外功能的完全批处理的seq2seq示例

    项目“pytorch-seq2seq-example”不仅提供了一个实际的Seq2Seq模型实现,还涵盖了从数据预处理到模型训练、评估和可视化的全过程,对于想要深入理解和应用Seq2Seq模型的PyTorch开发者来说,是一个宝贵的资源。...

    seq2seq:PyTorch中的Seq2Seq代码

    PyTorch中的Seq2seq代码 根据和 数据预处理: 我使用以下步骤 > config/WMT14/download.sh # download WMT14 data into raw_data/WMT14 > config/WMT14/prepare.sh # preprocess the data, and copy the files to ...

Global site tag (gtag.js) - Google Analytics