自然语言处理(Natural Language Processing, NLP)是指计算机通过分析文本,建立计算框架实现语言表示及应用的模型,从而使其获得对语言的理解及应用的能力。
从1950年Turing提出著名的“图灵测试”以来,让机器学会“听”和“说”,实现与人类间的无障碍交流成为人机交互领域的一大梦想。近年来随着深度学习技术的发展,自然语言处理领域也取得重要突破,发展成为人工智能领域的一个重要分支,涵盖语音识别、信息检索、信息提取、机器翻译、智能问答等众多应用场景。

在一些自然语言处理任务中,往往难以获得足够的训练数据,从而较难达到理想的训练效果。而预训练技术在计算机视觉领域的应用证实其可以极大改善下游任务模型对数据量的需求,并且可以大幅提升下游任务效果。

借鉴与此,自然语言处理开始尝试使用预训练实现迁移学习。2003年NNLM提出用神经网络实现语言模型,到2013年在此基础上发展出的Word2Vec在多数任务取得提升,使得词向量方法成为广泛应用的文本表征技术。2018年ELMo提出的上下文相关的表示方法在处理多义词方面表现惊艳;随后GPT引入Transformer结构使得预训练技术开始在自然语言处理领域大放异彩;随后BERT的横空出世,通过Masked-LM建立基于Transformer的双向预训练模型,横扫各大NLP任务,成为NLP发展史上的里程碑,从此将NLP的预训练研究推向一个高潮。

关于预训练技术在NLP领域的详细发展史,有兴趣的读者可以参考文献[1]或者知乎文章[2]。BERT开启了NLP的新纪元,此后出现了众多基于BERT的改进模型,MASS[3](Masked Sequence to Sequence Pre-training for Language Generation) 便是其中较为出类拔萃者。

MASS是一种Seq2Seq的学习框架,采用Transformer结构(如图1所示),由encoder和decoder组成,并且在二者之间引入attention,网络结构如图2所示。

图1. Transformer网络结构

图1. MASS网络的encoder-decoder结构

图2. BERT(a)及GPT(b)模型结构

在训练时,首先根据特定语言模型mask句子中的部分单词并将其作为encoder的输入,encoder对输入进行编码;将encoder的输出作为decoder的输入,同时mask源输入中未做mask处理的词,decoder根据源输入及先前的预测结果给出当前词的预测。

和BERT的区别在于,MASS加强了encoder和decoder之间的联系,可以同时训练encoder和decoder:遮盖部分词作为encoder的输入,在encoder中预测输入中被遮盖的词,使其更好地理解和编码未遮盖的词;在decoder的输入中,遮盖掉原始输入未被遮盖的词,使decoder的预测结果更依赖于原始输入,而不是上一次的预测结果。

同时,MASS之强大竟然一统BERT和GPT,两者分别是MASS网络中只mask一个词与mask所有词的边界条件,如图2所示为BERT和GPT在MASS世界观中的结构表示,如此对比,一目了然。可见,语言模型是MASS网络的重要组成部分,对于语言模型的mask处理,论文中给出的方法为:对于输入序列,随机选取一段连续位置(论文给出了50%的mask比例),将其中的80%做mask处理,10%随机替换为其他词,其余10%不作处理。

MindSpore中已经实现了MASS网络,这里将简要介绍如何使用Mindspore定义MASS网络以及进行训练及推理。Enjoy!

1)MindSpore中的MASS网络实现

MASS基本网络结构为Transformer

在MindSpore中的定义如下:

class Transformer(nn.Cell):"""Transformer with encoder and decoder.In Transformer, we define T = src_max_len, T' = tgt_max_len.Args:config (TransformerConfig): Model config.is_training (bool): Whether is training.use_one_hot_embeddings (bool): Whether use one-hot embedding.Returns:Tuple[Tensor], network outputs."""def __init__(self,config: TransformerConfig,is_training: bool,use_one_hot_embeddings: bool =False,use_positional_embedding: bool =True):super(Transformer,self).__init__()self.use_positional_embedding = use_positional_embeddingconfig = copy.deepcopy(config)self.is_training = is_trainingif notis_training:config.hidden_dropout_prob =0.0config.attention_dropout_prob =0.0self.input_mask_from_dataset = config.input_mask_from_datasetself.batch_size = config.batch_sizeself.max_positions = config.seq_lengthself.attn_embed_dim = config.hidden_sizeself.num_layers = config.num_hidden_layersself.word_embed_dim = config.hidden_sizeself.last_idx =self.num_layers -1self.embedding_lookup = EmbeddingLookup(vocab_size=config.vocab_size,embed_dim=self.word_embed_dim,use_one_hot_embeddings=use_one_hot_embeddings)if self.use_positional_embedding:self.positional_embedding = PositionalEmbedding(embedding_size=self.word_embed_dim,max_position_embeddings=config.max_position_embeddings)self.encoder = TransformerEncoder(attn_embed_dim=self.attn_embed_dim,encoder_layers=self.num_layers,num_attn_heads=config.num_attention_heads,intermediate_size=config.intermediate_size,attention_dropout_prob=config.attention_dropout_prob,initializer_range=config.initializer_range,hidden_dropout_prob=config.hidden_dropout_prob,hidden_act=config.hidden_act,compute_type=config.compute_type)self.decoder = TransformerDecoder(attn_embed_dim=self.attn_embed_dim,decoder_layers=self.num_layers,num_attn_heads=config.num_attention_heads,intermediate_size=config.intermediate_size,attn_dropout_prob=config.attention_dropout_prob,initializer_range=config.initializer_range,dropout_prob=config.hidden_dropout_prob,hidden_act=config.hidden_act,compute_type=config.compute_type)self.cast = P.Cast()self.dtype = config.dtypeself.cast_compute_type = SaturateCast(dst_type=config.compute_type)self.slice = P.StridedSlice()self.dropout = nn.Dropout(keep_prob=1- config.hidden_dropout_prob)self._create_attention_mask_from_input_mask = CreateAttentionMaskFromInputMask(config)self.scale = Tensor([math.sqrt(float(self.word_embed_dim))],dtype=mstype.float32)self.multiply = P.Mul()def construct(self,source_ids,source_mask,target_ids,target_mask):"""Construct network.In this method, T = src_max_len, T' = tgt_max_len.Args:source_ids (Tensor): Source sentences with shape (N, T).source_mask (Tensor): Source sentences padding mask with shape (N, T),where 0 indicates padding position.target_ids (Tensor): Target sentences with shape (N, T').target_mask (Tensor): Target sentences padding mask with shape (N, T'),where 0 indicates padding position.Returns:Tuple[Tensor], network outputs."""# Process source sentences.src_embeddings,embedding_tables =self.embedding_lookup(source_ids)src_embeddings =self.multiply(src_embeddings,self.scale)if self.use_positional_embedding:src_embeddings =self.positional_embedding(src_embeddings)src_embeddings =self.dropout(src_embeddings)# Attention mask with shape (N, T, T).enc_attention_mask =self._create_attention_mask_from_input_mask(source_mask)# Transformer encoder.encoder_output =self.encoder(self.cast_compute_type(src_embeddings),  # (N, T, D).self.cast_compute_type(enc_attention_mask)  # (N, T, T).)# Process target sentences.tgt_embeddings,_ =self.embedding_lookup(target_ids)tgt_embeddings =self.multiply(tgt_embeddings,self.scale)if self.use_positional_embedding:tgt_embeddings =self.positional_embedding(tgt_embeddings)tgt_embeddings =self.dropout(tgt_embeddings)# Attention mask with shape (N, T', T').tgt_attention_mask =self._create_attention_mask_from_input_mask(target_mask, True)# Transformer decoder.decoder_output =self.decoder(self.cast_compute_type(tgt_embeddings),  # (N, T', D)self.cast_compute_type(tgt_attention_mask),  # (N, T', T')encoder_output,  # (N, T, D)enc_attention_mask  # (N, T, T))return encoder_output,decoder_output,embedding_tables

对Transformer网络中的decoder输出的预测结果进行logSoftMax计算得到预测结果的归一化概率值,定义MASS的训练网络如下:

class TransformerTraining(nn.Cell):"""Transformer training network.Args:config (TransformerConfig): The config of Transformer.is_training (bool): Specifies whether to use the training mode.use_one_hot_embeddings (bool): Specifies whether to use one-hot for embeddings.Returns:Tensor, prediction_scores, seq_relationship_score."""def __init__(self,config,is_training,use_one_hot_embeddings):super(TransformerTraining,self).__init__()self.transformer = Transformer(config,is_training,use_one_hot_embeddings)self.projection = PredLogProbs(config)def construct(self,source_ids,source_mask,target_ids,target_mask):"""Construct network.Args:source_ids (Tensor): Source sentence.source_mask (Tensor): Source padding mask.target_ids (Tensor): Target sentence.target_mask (Tensor): Target padding mask.Returns:Tensor, prediction_scores, seq_relationship_score."""_,decoder_outputs,embedding_table = self.transformer(source_ids,source_mask,target_ids,target_mask)prediction_scores =self.projection(decoder_outputs,embedding_table)return prediction_scores

在MindSpore中还提供了封装交叉熵损失函数的网络TransformerNetworkWithLoss,以及封装优化器及反向训练的网络TransformerTrainOneStepWithLossScaleCell,详细请参考上文所提供代码仓地址。

2) 使用MindSpore训练MASS网络

在训练开始之前,需要配置必要的环境设置信息:

from mindspore import contextcontext.set_context(mode=context.GRAPH_MODE,device_target="Ascend",reserve_class_name_in_scope=False,device_id=device_id)

Mindspore支持多种数据集格式,可以调用dataset接口加载数据并进行一系列数据增强处理,同时可以配置循环下沉次数及数据集训练重复次数,这里以TFRecord格式为例:

import mindspore.dataset.engine as deds=de.TFRecordDataset(input_files,columns_list=["source_eos_ids","source_eos_mask","target_sos_ids","target_sos_mask",                   "target_eos_ids","target_eos_mask"],shuffle=shuffle,num_shards=rank_size,shard_id=rank_id,shard_equal_rows=True,num_parallel_workers=8)ori_dataset_size = ds.get_dataset_size()
print(f" | Dataset size:{ori_dataset_size}.")
repeat_count = epoch_count
ifsink_mode:ds.set_dataset_size(sink_step * batch_size)repeat_count = epoch_count * ori_dataset_size // ds.get_dataset_size()type_cast_op = deC.TypeCast(mstype.int32)
ds = ds.map(input_columns="source_eos_ids",operations=type_cast_op)
ds = ds.map(input_columns="source_eos_mask",operations=type_cast_op)
ds = ds.map(input_columns="target_sos_ids",operations=type_cast_op)
ds = ds.map(input_columns="target_sos_mask",operations=type_cast_op)
ds = ds.map(input_columns="target_eos_ids",operations=type_cast_op)
ds = ds.map(input_columns="target_eos_mask",operations=type_cast_op)ds = ds.batch(batch_size,drop_remainder=True)
ds = ds.repeat(repeat_count)

接下来,定义损失函数,优化器即可开始训练,如需使用loss scale功能,可以通过调用DynamicLossScaleManager接口实现。

这里我们使用交叉熵作为损失函数,选择adam优化器,使用TransformerNetworkWithLoss和TransformerTrainOneStepWithLossScaleCell

接口封装网络并构建Model模型,通过Model.train接口进行训练,训练结果可以通过MindSpore的回调接口ModelCheckpoint保存计算结果。

我们还提供了参数配置接口TransformerConfig,可以读取配置文件config.json中的网络配置参数。

from mindspore.nn.optim import Adam
from mindspore.train.model import Model
from mindspore.train.callback import CheckpointConfigfrom config import TransformerConfig
from src.transformer import TransformerNetworkWithLoss,TransformerTrainOneStepWithLossScaleCellconfig = TransformerConfig.from_json_file(“config.json”)net_with_loss = TransformerNetworkWithLoss(config,is_training=True)
net_with_loss.init_parameters_data()lr = Tensor(polynomial_decay_scheduler(lr=config.lr,min_lr=config.min_lr,decay_steps=config.decay_steps,total_update_num=update_steps,warmup_steps=config.warmup_steps,power=config.poly_lr_scheduler_power),dtype=mstype.float32)optimizer = Adam(net_with_loss.trainable_params(),lr,beta1=0.9,beta2=0.98)scale_manager = DynamicLossScaleManager(init_loss_scale=config.init_loss_scale,scale_factor=config.loss_scale_factor,scale_window=config.scale_window)net_with_grads = TransformerTrainOneStepWithLossScaleCell(network=net_with_loss,optimizer=optimizer,scale_update_cell=scale_manager.get_update_cell())net_with_grads.set_train(True)
model = Model(net_with_grads)
loss_monitor = LossCallBack(config)ckpt_config = CheckpointConfig(save_checkpoint_steps=config.save_ckpt_steps,                              keep_checkpoint_max=config.keep_ckpt_max)
ckpt_callback = ModelCheckpoint(prefix=config.ckpt_prefix,directory=os.path.join(config.ckpt_path,'ckpt_{}'.format(os.getenv('DEVICE_ID'))),config=ckpt_config)
callbacks= [loss_monitor,ckpt_callback]
model.train(epoch_size,pre_training_dataset,callbacks=callbacks,dataset_sink_mode=config.dataset_sink_mode)

3) MASS网络推理

训练完成之后,可以通过MindSpore中定义的load_checkpoint接口加载保存的checkpoint模型参数,通过TransformerInferModel构建MASS的推理网络模型,调用Model.predict接口完成推理。最后通过get_score接口可以计算推理评分。

import pickle
frommindspore.trainimportModel
frommindspore.train.serializationimportload_checkpoint,load_param_into_net
fromconfigimportTransformerConfig
from.transformer_for_inferimportTransformerInferModel
fromsrc.utilsimportget_scoreconfig=TransformerConfig(config.path)
tfm_model = TransformerInferModel(config=config,use_one_hot_embeddings=False)
tfm_model.init_parameters_data()
weights = load_infer_weights(checkpoint.path)
load_param_into_net(tfm_model, weights)
tfm_infer = TransformerInferCell(tfm_model)
model = Model(tfm_infer)predictions = []
probs = []
source_sentences = []
target_sentences = []
forbatchindataset.create_dict_iterator():source_sentences.append(batch["source_eos_ids"])target_sentences.append(batch["target_eos_ids"])source_ids = Tensor(batch["source_eos_ids"],mstype.int32)source_mask = Tensor(batch["source_eos_mask"],mstype.int32)start_time = time.time()predicted_ids,entire_probs = model.predict(source_ids,source_mask)print(f" | Batch size:{config.batch_size}, "f"Time cost:{time.time() - start_time}.")predictions.append(predicted_ids.asnumpy())probs.append(entire_probs.asnumpy())output = []
forinputs,ref,batch_out,batch_probsinzip(source_sentences,target_sentences,predictions,probs):foriinrange(config.batch_size):ifbatch_out.ndim ==3:batch_out = batch_out[:,0]example = {"source": inputs[i].tolist(),"target": ref[i].tolist(),"prediction": batch_out[i].tolist(),"prediction_prob":batch_probs[i].tolist()}output.append(example)score = get_score(output,vocab=args.vocab,metric=args.metric)

至此关于MASS的基本结构以及如何使用Mindspore进行MASS网络训练和推理已经介绍完毕,感兴趣的朋友不妨亲自动手试一下哦~


[1] 李舟军, 范宇, 吴贤杰. 面向自然语言处理的预训练技术研究综述[J].计算机科学. 2020.

[2] 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史. https://zhuanlan.zhihu.com/p/49271699

[3] Song K , Tan X , Qin T , et al. MASS: Masked Sequence to Sequence Pre-training for Language Generation[J]. 2019.

基于MindSpore的MASS网络实现相关推荐

  1. 基于MindSpore实现X3D网络

    X3D是一篇发表在CVPR2020上的关于视频动作分类的文章 原论文链接 notebook可执行案例 Code 官方实现 MindSpore实现 算法原理 X3D的工作受机器学习中特征选择方法的启发, ...

  2. resnet50网络结构_Resnet50详解与实践(基于mindspore)

    1. 简述 Resnet是残差网络(Residual Network)的缩写,该系列网络广泛用于目标分类等领域以及作为计算机视觉任务主干经典神经网络的一部分,典型的网络有resnet50, resne ...

  3. 技术干货 | 基于MindSpore更好的理解Focal Loss

    [本期推荐专题]物联网从业人员必读:华为云专家为你详细解读LiteOS各模块开发及其实现原理. 摘要:Focal Loss的两个性质算是核心,其实就是用一个合适的函数去度量难分类和易分类样本对总的损失 ...

  4. MindSpore21天实战营丨基于MindSpore的ResNet-50蘑菇“君”的识别应用体验

    借助全新的设计理念,华为云推出了 MindSpore深度学习实战营,帮助小白更快的上手高性能深度学习框架,快速训练ResNet-50,实现你的第一个手机App开发,学会智能新闻分类.篮球检测和「猜你喜 ...

  5. 【深度学习】基于MindSpore和pytorch的Softmax回归及前馈神经网络

    1 实验内容简介 1.1 实验目的 (1)熟练掌握tensor相关各种操作: (2)掌握广义线性回归模型(logistic模型.sofmax模型).前馈神经网络模型的原理: (3)熟练掌握基于mind ...

  6. 基于MindSpore复现Deeplabv3—语义分割

    基于MindSpore复现Deeplabv3-语义分割 实验介绍 本实验主要介绍使用MindSpore深度学习框架在PASCAL VOC2012数据集上训练Deeplabv3网络模型.本实验使用了Mi ...

  7. 基于MindSpore框架的室内场景图像分割方法研究

    基于MindSpore框架的室内场景图像分割方法研究 概述 本文以华为最新国产深度学习框架Mindspore为基础,研究室内场景语义分割方法.本文基于注意力机制改进U-Net网络,并选取VGG16与R ...

  8. 用C#实现基于TCP协议的网络通讯

    TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实 ...

  9. 基于交换技术的网络中,全双工主要运行在?( 内有答案与详解)

    基于交换技术的网络中,全双工主要运行在?( ) A. 站点与站点之间 B. 交换机与服务器之间 C. 站点与服务器之间 D. 站点与交换机之间 答案: b 网站就是站点的意思,交换机实际是与数据打交道 ...

最新文章

  1. 面向对象的设计原则最终篇
  2. 网络爬虫流程与注意事项
  3. JSONObject、JSONArray区别
  4. CodeForces - 1301C Ayoub's function(数学)
  5. linux下svn常用指令
  6. Android Studio之Instant Run requires ‘Tools | Android | Enable ADB integration‘ to be enabled解决办法
  7. LIB和DLL的区别与使用
  8. oracle用户密码规则,使用Oracle自带profile以及函数简单设定Oracle用户名密码规则...
  9. Spring事务管理2----编程式事务管理
  10. Asp.Net MVC 模型(使用Entity Framework创建模型类)1
  11. 冒死曝光这个软件,希望不要被封杀!
  12. 【实用技巧】文件MD5修改方法
  13. pdffactory字体模糊如何处理
  14. springboot分层构建Docker镜像实践,统统都会!
  15. 5G 核心网 Quality of Service Model (QoS Model)
  16. Java List转Map时发生Duplicate key
  17. hadoop分布式安装部署具体视频教程(网盘附配好环境的CentOS虚拟机文件/hadoop配置文件)...
  18. vs2010安装失败(如下图)的解决方法
  19. VC++ WCHAR,CHAR,TCHAR的区别
  20. 树莓派3 中文输入法安装教程

热门文章

  1. 3D打印机开源项目遭克隆或成开源拐点
  2. matlab中ct值直方图,【CT值与灰度值的总结】
  3. Codeforces Round #617 (Div. 3)
  4. java 非法的表达式_Java运行 显示非法的表达式开始 这是为什么呀?
  5. PC端阴阳师 加长百鬼夜行舞台 如何简单修改分辨率
  6. 【前端知识之CSS】CSS3新增特性
  7. HaaS UI小程序解决方案基础教学之二: 搭建第一个UI页面
  8. 嵌入式软件开发工程师面试指南_总结
  9. xargs 如何使用?
  10. 专车新规或下周发布,估计有大量司机流失