美文网首页自然语言处理
T5(Transfer Text-to-Text Transfo

T5(Transfer Text-to-Text Transfo

作者: 晓柒NLP与药物设计 | 来源:发表于2022-06-12 06:48 被阅读0次

论文链接:https://arxiv.org/abs/1910.10683

代码链接:https://github.com/google-research/text-to-text-transfer-transformer

导言:一个统一框架,靠着大力出奇迹,将所有 NLP 任务都转化成 Text-to-Text(文本到文本)任务

T5多任务概述图

比如英德翻译任务,只需将训练数据集的输入部分前加上translate English to German即可。假设需要翻译That is good,那么先转换成translate English to German:That is good.输入模型,之后就可以直接输出德语翻译Das ist gut.。对于需要输出连续值的STS(文本语义相似度任务),也是直接输出文本。通过这样的方式就能将NLP任务都转换成Text-to-Text形式,也就可以用同样的模型,同样的损失函数,同样的训练过程,同样的解码过程来完成所有NLP任务


1.1 模型结构

T5模型采用Transformer的encoder-decoder结构,GPT采用的是Transformer的decoder结构,BERT采用的是Transformer的encoder结构
T5模型图

T5模型和原始的Transformer结构基本一致,具体的做了如下几点改动:

  • 编码器和解码器仍保留在模型中。编码器和解码器层成为块(block),子层为包含自注意层和前馈网络的子组件(subcomponent)。像乐高一样,可以组装块和子组件来建立模型,例如图2中的ENCODER #1

  • Layer normalization层归一化应用于每个子组件的输入,使用一个简化版本的Layer normalization,其中激活只是重新调整,没有附加偏差被应用

    • 常规的Layer\_Normalization的计算公式为:y=\frac{x-\mu}{\sqrt{Var(x)+\varepsilon}},这里\mu为期望,Var(x)+\varepsilon为方差。

    • 而此处的Layer\_Normalization的计算公式为y=weight*\frac{x}{\sqrt{Var(x)+\varepsilon}},这里对应的weight参数初始化的时候全为1

  • Layer normalization之后,将一个residual的skip connection将每个子组件的输入添加到其输出中

  • 此处使用了简化的相对位置embedding,即每个位置对应一个数值而不是向量,原来的Transformer采用sin/cos习得position embeddings,而T5将(key和query)相对位置的数值加在attention softmax之前的logits上,每个head的有自己的position embeddings,所有的层共享一套position embeddings,每一层都计算一次,让模型对位置更加敏感

1.2 数据来源:Colossal Clean Crawled Corpus (C4)

T5作者选取了Common Crawl数据集,这个数据集每周大约爬取20TB的WEB数据。虽然数据集已经抽取了文本,但实际上并不干净,里面还包含了很多非自然语言的东西,比如错误消息、菜单、重复文本,于是对数据进行了比较细致的处理:
  • 只取结尾有标点的句子

  • 去掉包含脏话的网页

  • 有很多页面包含"enable Javascript"的提示,去掉包含Javascript的句子

  • "lorem ipsum"是一个测试网页排版的拉丁文,去掉包含这个占位符的网页

  • 去掉包含代码片段的网页

  • 以三句为一个片段进行去重

  • 去掉非英文的网页

经过上述处理后最终生成了750GB的数据集C4,并且在TensorFlow Datasets进行开源

1.3 任务以及训练格式

1.3.1 输入输出模型

  • 输入:参考GPT2,直接把任务名称当作prefix和输入拼在一起,例如:"translate English to German: That is good."

  • 输出:分类任务(如推断),需要输出"entailment", "neutral", "contradiction"这三种文本,否则都算错;回归任务输出str(序列)类型的浮点数。还有其他任务,可前往附录A参考

  • 这里每个任务前缀的选择可以认为是一种超参,即通过人为设计前缀样式。作者发现不同的前缀对模型的影响有限,因此没有做大量实验比较选择不同前缀的结果。

1.3.2 预训练过程

之后是对预训练目标的大范围探索,具体做了哪些实验,下面这张图就能一目了然

预训练模型的预训练范式总览

总共从四个层面来进行比较:

  • 第一个方面,高层次方法(自监督的预训练方法)对比,总共三种方法:

    • 语言模型式,就是 GPT-2 那种方式,从左到右预测

    • BERT-style式,就是像BERT一样将一部分给破坏掉,然后还原出来,其效果最好

    • Deshuffling(顺序还原)式,就是将文本打乱,然后还原出来

  • 第二方面,对文本一部分进行破坏时的策略,也分三种方法:

    • Mask法,如现在大多模型的做法,将被破坏token换成特殊符如[M]

    • Replace span法,可以当作是把上面 Mask 法中相邻 [M] 都合成了一个特殊符,每一小段替换一个特殊符,提高计算效率,其效果最好

    • Drop法,没有替换操作,直接随机丢弃一些字符

  • 第三方面,对文本进行多大程度的破坏,挑了 4 个值:10%,15%,25%,50%,最后发现 BERT 的 15%效果最好

  • 第四方面,Replace Span需要决定对大概多长的小段进行破坏,于是对不同长度进行探索:2,3,5,10这四个值,最后发现3效果最好

预训练模式输入输出样式举例

1.3.3 模型参数量

最后就是结合上面所有实验结果,训练了不同规模几个模型,由小到大:

T5模型参数量表

1.3.4 训练结论

  • Architectures

    • 原始的Transformer结构表现最好

    • encoder-decoder结构和BERT、GPT的计算量差不多

    • 共享encoderdecoder的参数没有使效果差太多

  • Unsupervised objectives

    • 自编码和自回归的效果差不多

    • 推荐选择更短目标序列的目标函数,提高计算效率

  • Datasets

    • 在领域内进行无监督训练可以提升一些任务的效果,但在一个小领域数据上重复训练会降低效果

    • Large、diverse的数据集效果最好

  • Training strategies

    • 精调时更新所有参数 > 更新部分参数

    • 在多个任务上预训练之后微调 = 无监督预训练

  • Scaling

    • 在小模型上训练更多数据 < 用少量步数训练更大的模型

    • 从一个预训练模型上微调多个模型后集成 < 分开预训练+微调后集成

在本文中所有的实验,作者列出了一个给定实验的压缩结果的表格

2.1 T5模型的使用

  • 首先安装需要的包:
pip install transformers==4.2.0
pip install sentencepiece==0.1.94
  • 下载并加载模型和分词器:
model = T5ForConditionalGeneration.from_pretrained('t5-large')
tokenizer = T5Tokenizer.from_pretrained('t5-large')</pre>
  • T5模型参数打印:
# print(model.config)
T5Config {
  "_name_or_path": "t5-large",
  "architectures": [
    "T5WithLMHeadModel"
  ],
  "d_ff": 4096,                      # 每个T5Block中feed forward layer的size
  "d_kv": 64,                        # 每个attention head的key、query、value的size。d_kv必须等于d_model/num_heads
  "d_model": 1024,                   # 每个encoder layers和pooler layer的大小
  "decoder_start_token_id": 0,       # 模型根据标签自动创建decoder_start_token_id,方法是将标签向右移动一个位置,并加上前缀
  "dropout_rate": 0.1,               # 所有dropout layers的比例
  "eos_token_id": 1,                 # eos_token的id
  "feed_forward_proj": "relu",       # 所有要使用的feed_forward类型
  "initializer_factor": 1.0,         # 初始化所有权重矩阵的系数
  "is_encoder_decoder": true,        # 同时使用encoder与decoder
  "layer_norm_epsilon": 1e-06,       # layer_norm使用的epsilon
  "model_type": "t5",                # 模型类型
  "n_positions": 512,                # positions数量
  "num_decoder_layers": 24,          # decoder中的隐藏层数。如果未设置,将使用与num_layers相同的值
  "num_heads": 16,                   # 每个attention layer的attention heads
  "num_layers": 24,                  # 每个encoder中的hidden layers
  "relative_attention_max_distance": 128, # bucket separation较长序列的最大距离
  "relative_attention_num_buckets": 32,   # 每个attention layers要使用的bucket数
  "task_specific_params": {
    "summarization": {
      "early_stopping": true,
      "length_penalty": 2.0,
      "max_length": 200,
      "min_length": 30,
      "no_repeat_ngram_size": 3,
      "num_beams": 4,
      "prefix": "summarize: "
    },
    "translation_en_to_de": {
      "early_stopping": true,
      "max_length": 300,
      "num_beams": 4,
      "prefix": "translate English to German: "
    },
    "translation_en_to_fr": {
      "early_stopping": true,
      "max_length": 300,
      "num_beams": 4,
      "prefix": "translate English to French: "
    },
    "translation_en_to_ro": {
      "early_stopping": true,
      "max_length": 300,
      "num_beams": 4,
      "prefix": "translate English to Romanian: "
    }
  },
  "transformers_version": "4.19.2",  # tranformers包支持版本
  "use_cache": true,                 # 模型是否应返回最后一个key/values attentions
  "vocab_size": 32128                # T5模型的词汇表
}
  • T5模型结构打印(第N个block):
T5Block(
    (layer): ModuleList(
      (0): T5LayerSelfAttention(
        (SelfAttention): T5Attention(
          (q): Linear(in_features=1024, out_features=1024, bias=False)
          (k): Linear(in_features=1024, out_features=1024, bias=False)
          (v): Linear(in_features=1024, out_features=1024, bias=False)
          (o): Linear(in_features=1024, out_features=1024, bias=False)
        )
        (layer_norm): T5LayerNorm()
        (dropout): Dropout(p=0.1, inplace=False)
      )
      (1): T5LayerCrossAttention(
        (EncDecAttention): T5Attention(
          (q): Linear(in_features=1024, out_features=1024, bias=False)
          (k): Linear(in_features=1024, out_features=1024, bias=False)
          (v): Linear(in_features=1024, out_features=1024, bias=False)
          (o): Linear(in_features=1024, out_features=1024, bias=False)
        )
        (layer_norm): T5LayerNorm()
        (dropout): Dropout(p=0.1, inplace=False)
      )
      (2): T5LayerFF(
        (DenseReluDense): T5DenseReluDense(
          (wi): Linear(in_features=1024, out_features=4096, bias=False)
          (wo): Linear(in_features=4096, out_features=1024, bias=False)
          (dropout): Dropout(p=0.1, inplace=False)
          (relu_act): ReLU()
        )
        (layer_norm): T5LayerNorm()
        (dropout): Dropout(p=0.1, inplace=False)
      )
    )
)
  • 使用T5模型并创建prefix实现摘要任务:
def summarize(text, max_length):
  '''
  text: 要生成摘要的文本
  max_length: 摘要的最大长度
  '''
  # 去掉多余的空格和换行符
  preprocess_text = text.strip().replace('\n','')
  # 准备前缀+文本
  t5_prepared_text = 'summarize: ' + preprocess_text
  print("Preprocessed and prepared text: \n", t5_prepared_text)
  # 分词
  tokenized_text = tokenizer.encode(t5_prepared_text, return_tensors="pt").to(device)
  # 进行文本摘要
  summary_ids = model.generate(tokenized_text,
                  num_beams=4,
                  no_repeat_ngram_size=2,
                  min_length=30,
                  max_length=max_length,
                  early_stopping=True)
  # 将id转换为输出 summary_ids.shape = [1, 50]
  output = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
  return output

相关文章

网友评论

    本文标题:T5(Transfer Text-to-Text Transfo

    本文链接:https://www.haomeiwen.com/subject/uocgmrtx.html