微软亚洲研究院于2019在ICML发表《MASS: Masked Sequence to Sequence Pre-training for Language Generation》,其借鑑了Bert的Masked Language Model预训练任务,提出了MAsked Sequence to Sequence Pre-training(MASS)模型,为自然语言生成任务联合预训练编码器和解码器。
MASS的编码器-解码器结构示例,图中“_”表示被屏蔽的词。
编码器: 以被随机屏蔽掉连续片段的句子作为输入,BERT的做法是随机屏蔽掉15%的词,而MASS为了解决编码与解码之间的平衡,做法为屏蔽掉句子总长50%的片段。模型中使用特殊符号
解码器:输入为与编码器同样的序列,但是会屏蔽掉剩馀的词,然后解码器只预测编码器端屏蔽掉的词。以上图为例,只给定
encoder input (source): [x1, x2, x3, x4, x5, x6, x7, x8, </eos>]
masked encoder input: [x1, x2, x3, _, _, _, x7, x8, </eos>]
decoder input: [ -, x3, x4, x5]
| | | |
V V V V
decoder output: [x3, x4, x5, x6]
MASS预训练有以下几大优势:
(1) 编码器被强制去抽取未被屏蔽掉的词的含义,可以提升编码器理解源序列文本的能力。
(2) 通过在解码器端预测连续的标记,解码器可以比仅预测离散标记拥有更好的语言建模能力。
(3) 通过在解码器端进一步屏蔽在编码器端未被屏蔽掉的词, 以鼓励解码器从编码器端提取更多有用的信息来做预测,而不是依赖于前面预测出的单词,这样能促进编码器-解码器结构的联合训练。
其模型基础结构可以使用任何Seq2Seq的结构,由于Transformer的优越性,故论文中使用Transformer模型作为基础结构,Transformer整体架构由编码器和解码器两个部分组成,不依赖任何RNN和CNN结构来生成输出,而是使用了Attention注意力机制,自动学习输入序列中每个单词和其他单词的关联,可以更好的处理长文本,且该模型可以高效的并行工作,训练速度较快。
Transformer 的整体架构如下:
- 编码器和解码器分别由
$N=6$ 个相同的编码器/解码器层组成。 - 在 Transformer 架构的左半部分,编码器的任务是将输入序列映射到一系列连续表示,然后将其馈送到解码器。
- 架构右半部分的解码器接收编码器的输出以及前一个时间步的解码器输出,以生成输出序列。
- 解码器的输出最终通过一个全连接层,然后是一个 softmax 层,以生成对输出序列下一个单词的预测。
给定一个未配对的源句子
注:
MASS 有一个重要的超参数
当
当
MASS脚本及代码结构如下:
├── mass
├── config
│ ├──config.py // 参数配置
├── src
│ ├──model_utils
│ ├──config.py // 参数配置
│ ├──device_adapter.py // 设备配置
│ ├──local_adapter.py // 本地设备配置
│ ├──moxing_adapter.py // modelarts设备配置
├──src
│ ├──dataset
│ ├──bi_data_loader.py // 数据集加载器,用于微调或推理
│ ├──mono_data_loader.py // 预训练数据集加载器
│ ├──language_model
│ ├──noise_channel_language_model.p // 数据集生成噪声通道语言模型
│ ├──mass_language_model.py // 基于MASS论文的MASS语言模型
│ ├──loose_masked_language_model.py // 基于MASS发布代码的MASS语言模型
│ ├──masked_language_model.py // 基于MASS论文的MASS语言模型
│ ├──transformer
│ ├──create_attn_mask.py // 生成屏蔽矩阵,除去填充部分
│ ├──transformer.py // Transformer模型架构
│ ├──encoder.py // Transformer编码器组件
│ ├──decoder.py // Transformer解码器组件
│ ├──self_attention.py // 自注意块组件
│ ├──multi_head_attention.py // 多头自注意组件
│ ├──embedding.py // 嵌入组件
│ ├──positional_embedding.py // 位置嵌入组件
│ ├──feed_forward_network.py // 前馈网络
│ ├──residual_conn.py // 残留块
│ ├──beam_search.py // 推理所用的波束搜索解码器
│ ├──transformer_for_infer.py // 使用Transformer进行推理
│ ├──transformer_for_train.py // 使用Transformer进行训练
│ ├──utils
│ ├──byte_pair_encoding.py // 使用subword-nmt应用字节对编码(BPE)
│ ├──dictionary.py // 字典
│ ├──loss_moniter.py // 训练步骤中损失监控回调
│ ├──lr_scheduler.py // 学习速率调度器
│ ├──ppl_score.py // 基于N-gram的困惑度评分
│ ├──rouge_score.py // 计算ROUGE得分
│ ├──load_weights.py // 从检查点或者NPZ文件加载权重
│ ├──initializer.py // 参数初始化器
├── vocab
│ ├──all.bpe.codes // 字节对编码表
│ ├──all_en.dict.bin // 已学习到的词汇表
├── scripts
│ ├──run_ascend.sh // Ascend处理器上训练&评估模型脚本
│ ├──run_gpu.sh // GPU处理器上训练&评估模型脚本
│ ├──learn_subword.sh // 学习字节对编码
│ ├──stop_training.sh // 停止训练
├── requirements.txt // 第三方包需求
├── train.py // 训练API入口
├── eval.py // 推理API入口
├── default_config.yaml // 参数配置
├── tokenize_corpus.py // 语料标记化
├── apply_bpe_encoding.py // 应用BPE进行编码
├── weights_average.py // 将各模型检查点平均转换到NPZ格式
├── news_crawl.py // 创建预训练所用的News Crawl数据集
├── gigaword.py // 创建Gigaword语料库