0


猿创征文|【深度学习前沿应用】文本生成

猿创征文|【深度学习前沿应用】文本生成


在这里插入图片描述


作者简介:在校大学生一枚,C/C++领域新星创作者,华为云享专家,阿里云专家博主,腾云先锋(TDP)成员,云曦智划项目总负责人,全国高等学校计算机教学与产业实践资源建设专家委员会(TIPCC)志愿者,以及编程爱好者,期待和大家一起学习,一起进步~
.
博客主页:ぃ灵彧が的学习日志
.
本文专栏:人工智能
.
专栏寄语:若你决定灿烂,山无遮,海无拦
.
在这里插入图片描述

文章目录


前言

什么是文本生成?

在自然语言处理领域,文本生成任务是指根据给定的输入,自动生成对应的输出,典型的任务包含:机器翻译、智能问答等。文本生成任务在注意力机制提出之后取得了显著的效果,尤其是在2018年基于多头注意力机制的Transformer(原理如下图1所示)在机器翻译领域取得当时最优效果时,基于Transformer的文本生成任务也进入了新的繁荣时期。

在这里插入图片描述

  1. 本实验的目的是演示如何使用经典的Transformer实现英-中机器翻译,实验平台为百度AI Studio,实验环境为Python3.7Paddle2.0

一、数据加载及预处理


(一)、数据加载

本实验选用开源的小型英-中翻译CMN数据集,该数据集中包含样本总数24360条,均为短文本,部分数据展示如下图2所示:

在这里插入图片描述

不同于图像处理,在处理自然语言时,需要指定文本的长度,便于进行批量计算,因此,在数据预处理阶段,应该先统计数据集中文本的长度,然后指定一个恰当的值,进行统一处理。


  1. 导入相关包
  1. import paddle
  2. import paddle.nn.functional as F
  3. import re
  4. import numpy as np
  5. print(paddle.__version__)# cpu/gpu环境选择,在 paddle.set_device() 输入对应运行设备。# device = paddle.set_device('gpu')

  1. 统计数据集中句子的长度等信息
  1. # 统计数据集中句子的长度等信息
  2. lines =open('data/data78721/cmn.txt','r',encoding='utf-8').readlines()print(len(lines))
  3. datas =[]
  4. dic_en ={}
  5. dic_cn ={}for line in lines:
  6. ll = line.strip().split('\t')iflen(ll)<2:continue
  7. datas.append([ll[0].lower().split(' ')[1:-1],list(ll[1])])# print(ll[0])iflen(ll[0].split(' '))notin dic_en:
  8. dic_en[len(ll[0].split(' '))]=1else:
  9. dic_en[len(ll[0].split(' '))]+=1iflen(ll[1])notin dic_cn:
  10. dic_cn[len(ll[1])]=1else:
  11. dic_cn[len(ll[1])]+=1
  12. keys_en =list(dic_en.keys())
  13. keys_en.sort()
  14. count =0# print('英文长度统计:')for k in keys_en:
  15. count += dic_en[k]# print(k,dic_en[k],count/len(lines))
  16. keys_cn =list(dic_cn.keys())
  17. keys_cn.sort()
  18. count =0# print('中文长度统计:')for k in keys_cn:
  19. count += dic_cn[k]# print(k,dic_cn[k],count/len(lines))
  20. en_length =10
  21. cn_length =10

(二)、构建词表

对于中英文,需要分别构建词表,进行词向量学习,除此之外,还需要在每个词表中加入开始符号、结束符合以及填充符号:

  1. # 构建中英文词表
  2. en_vocab ={}
  3. cn_vocab ={}
  4. en_vocab['<pad>'], en_vocab['<bos>'], en_vocab['<eos>']=0,1,2
  5. cn_vocab['<pad>'], cn_vocab['<bos>'], cn_vocab['<eos>']=0,1,2
  6. en_idx, cn_idx =3,3for en, cn in datas:# print(en,cn)for w in en:if w notin en_vocab:
  7. en_vocab[w]= en_idx
  8. en_idx +=1for w in cn:if w notin cn_vocab:
  9. cn_vocab[w]= cn_idx
  10. cn_idx +=1print(len(list(en_vocab)))print(len(list(cn_vocab)))'''
  11. 英文词表长度:6057
  12. 中文词表长度:3533
  13. '''

(三)、创建指定数据格式

需要将输入英文与输出中文封装为指定格式,即为编码器端输入添加结束符号并填充至固定长度,为解码器输入添加开始、结束符号并填充至固定长度,解码器端输出的正确答案应该只添加结束符号并且填充至固定长度。

  1. padded_en_sents =[]
  2. padded_cn_sents =[]
  3. padded_cn_label_sents =[]for en, cn in datas:iflen(en)>en_length:
  4. en = en[:en_length]iflen(cn)>cn_length:
  5. cn = cn[:cn_length]
  6. padded_en_sent = en +['<eos>']+['<pad>']*(en_length -len(en))
  7. padded_en_sent.reverse()
  8. padded_cn_sent =['<bos>']+ cn +['<eos>']+['<pad>']*(cn_length -len(cn))
  9. padded_cn_label_sent = cn +['<eos>']+['<pad>']*(cn_length -len(cn)+1)
  10. padded_en_sents.append(np.array([en_vocab[w]for w in padded_en_sent]))
  11. padded_cn_sents.append(np.array([cn_vocab[w]for w in padded_cn_sent]))
  12. padded_cn_label_sents.append(np.array([cn_vocab[w]for w in padded_cn_label_sent]))
  13. train_en_sents = np.array(padded_en_sents)
  14. train_cn_sents = np.array(padded_cn_sents)
  15. train_cn_label_sents = np.array(padded_cn_label_sents)print(train_en_sents.shape)print(train_cn_sents.shape)print(train_cn_label_sents.shape)

二、模型配置


(一)、定义网络超参数

  1. embedding_size =128
  2. hidden_size =512
  3. num_encoder_lstm_layers =1
  4. en_vocab_size =len(list(en_vocab))
  5. cn_vocab_size =len(list(cn_vocab))
  6. epochs =20
  7. batch_size =16

(二)、定义编码器

  1. # encoder: simply learn representation of source sentenceclassEncoder(paddle.nn.Layer):def__init__(self,en_vocab_size, embedding_size,num_layers=2,head_number=2,middle_units=512):super(Encoder, self).__init__()
  2. self.emb = paddle.nn.Embedding(en_vocab_size, embedding_size,)"""
  3. d_model (int) - 输入输出的维度。
  4. nhead (int) - 多头注意力机制的Head数量。
  5. dim_feedforward (int) - 前馈神经网络中隐藏层的大小。
  6. """
  7. encoder_layer = paddle.nn.TransformerEncoderLayer(embedding_size, head_number, middle_units)
  8. self.encoder = paddle.nn.TransformerEncoder(encoder_layer, num_layers)defforward(self, x):
  9. x = self.emb(x)
  10. en_out = self.encoder(x)return en_out

(三)、定义解码器

  1. classDecoder(paddle.nn.Layer):def__init__(self,cn_vocab_size, embedding_size,num_layers=2,head_number=2,middle_units=512):super(Decoder, self).__init__()
  2. self.emb = paddle.nn.Embedding(cn_vocab_size, embedding_size)
  3. decoder_layer = paddle.nn.TransformerDecoderLayer(embedding_size, head_number, middle_units)
  4. self.decoder = paddle.nn.TransformerDecoder(decoder_layer, num_layers)# for computing output logits
  5. self.outlinear =paddle.nn.Linear(embedding_size, cn_vocab_size)defforward(self, x, encoder_outputs):
  6. x = self.emb(x)# dec_input, enc_output,self_attn_mask, cross_attn_mask
  7. de_out = self.decoder(x, encoder_outputs)
  8. output = self.outlinear(de_out)
  9. output = paddle.squeeze(output)return output

三、模型训练

  1. encoder = Encoder(en_vocab_size, embedding_size)
  2. decoder = Decoder(cn_vocab_size, embedding_size)
  3. opt = paddle.optimizer.Adam(learning_rate=0.0001,
  4. parameters=encoder.parameters()+ decoder.parameters())for epoch inrange(epochs):print("epoch:{}".format(epoch))# shuffle training data
  5. perm = np.random.permutation(len(train_en_sents))
  6. train_en_sents_shuffled = train_en_sents[perm]
  7. train_cn_sents_shuffled = train_cn_sents[perm]
  8. train_cn_label_sents_shuffled = train_cn_label_sents[perm]# print(train_en_sents_shuffled.shape[0],train_en_sents_shuffled.shape[1])for iteration inrange(train_en_sents_shuffled.shape[0]// batch_size):
  9. x_data = train_en_sents_shuffled[(batch_size*iteration):(batch_size*(iteration+1))]
  10. sent = paddle.to_tensor(x_data)
  11. en_repr = encoder(sent)
  12. x_cn_data = train_cn_sents_shuffled[(batch_size*iteration):(batch_size*(iteration+1))]
  13. x_cn_label_data = train_cn_label_sents_shuffled[(batch_size*iteration):(batch_size*(iteration+1))]
  14. loss = paddle.zeros([1])for i inrange( cn_length +2):
  15. cn_word = paddle.to_tensor(x_cn_data[:,i:i+1])
  16. cn_word_label = paddle.to_tensor(x_cn_label_data[:,i])
  17. logits = decoder(cn_word, en_repr)
  18. step_loss = F.cross_entropy(logits, cn_word_label)
  19. loss += step_loss
  20. loss = loss /(cn_length +2)if(iteration %50==0):print("iter {}, loss:{}".format(iteration, loss.numpy()))
  21. loss.backward()
  22. opt.step()
  23. opt.clear_grad()

输出结果如下图3所示:

在这里插入图片描述


四、模型预测

  1. encoder.eval()
  2. decoder.eval()
  3. num_of_exampels_to_evaluate =10
  4. indices = np.random.choice(len(train_en_sents), num_of_exampels_to_evaluate, replace=False)
  5. x_data = train_en_sents[indices]
  6. sent = paddle.to_tensor(x_data)
  7. en_repr = encoder(sent)
  8. word = np.array([[cn_vocab['<bos>']]]* num_of_exampels_to_evaluate
  9. )
  10. word = paddle.to_tensor(word)
  11. decoded_sent =[]for i inrange(cn_length +2):
  12. logits = decoder(word, en_repr)
  13. word = paddle.argmax(logits, axis=1)
  14. decoded_sent.append(word.numpy())
  15. word = paddle.unsqueeze(word, axis=-1)
  16. results = np.stack(decoded_sent, axis=1)for i inrange(num_of_exampels_to_evaluate):print('---------------------')
  17. en_input =" ".join(datas[indices[i]][0])
  18. ground_truth_translate ="".join(datas[indices[i]][1])
  19. model_translate =""for k in results[i]:
  20. w =list(cn_vocab)[k]if w !='<pad>'and w !='<eos>':
  21. model_translate += w
  22. print(en_input)print("true: {}".format(ground_truth_translate))print("pred: {}".format(model_translate))

输出结果如下图4所示:

在这里插入图片描述


总结

本系列文章内容为根据清华社出版的《机器学习实践》所作的相关笔记和感悟,其中代码均为基于百度飞桨开发,若有任何侵权和不妥之处,请私信于我,定积极配合处理,看到必回!!!

最后,引用本次活动的一句话,来作为文章的结语~( ̄▽ ̄~)~:

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。

ps:更多精彩内容还请进入本文专栏:人工智能,进行查看,欢迎大家支持与指教啊~( ̄▽ ̄~)~

在这里插入图片描述


本文转载自: https://blog.csdn.net/m0_54754302/article/details/126733603
版权归原作者 ぃ灵彧が 所有, 如有侵权,请联系我们删除。

“猿创征文|【深度学习前沿应用】文本生成”的评论:

还没有评论