【机器学习】详解 BERT


目录

摘要

一、引言

二、原理 

2.1 模型架构 

2.2 输入/输出表示

2.3 预训练 BERT

2.3.1 任务一:Masked LM

2.3.1 任务二:Next Sentence Prediction (NSP)

2.4 微调 BERT   

三、实验

3.1 GLUE

四、附录

A BERT 的额外细节

A.1 预训练的阐述

A.2 预训练过程

A.3 微调过程

A.4 BERT,ELMO 和 OpenAI GPT 的比较

A.5 在不同任务上的微调

B 实验设置细节

B.1 GLUE 基准实验细节描述

C 额外的消融研究

C.1 训练步数的影响

C.2 不同 Masking 过程的消融

五、ELMO、BERT 与 GPT

六、Tokenization 方法归纳

七、BERT 知识点 Part1

八、BERT 知识点 Part2



摘要

        我们介绍了一个新的语言表示模型 BERT (Bidirectional Encoder Representations from Transformers)。BERT 旨在通过联合调节所有层中的左右上下文来预训练深度双向表示。因此,只需一个额外的输出层即可微调预训练的 BERT 表示,从而为各种任务创建 SOTA 模型 (例如问答和语言推理),而无需针对基本的特定任务修改架构。

        BERT 概念简单且经验丰富,在 11 项 NLP 任务中获得了 SOTA 结果,包括将 GLUE 基准推至 80.5% (7.7% 的绝对提升),MultiNLI 准确率达到 86.7% (5.6% 的绝对提升) 和 SQuAD v1.1 问题回答测试 F1 (Test F1) 到 93.2 (1.5% 的绝对提升),还有SQuAD v2.0 问题回答测试 F1 (Test F1) 到 83.1 (5.1% 的绝对提升)


一、引言

        语言模型 (LM) 的预训练已证明可有效改善许多 NLP 任务,包括 句子级 (sentence-level) 任务,例如 自然语言推断 (NLI, Natural Language Inference) (给定前提推断假设是否成立) 和 复述 (Paraphrasing),其旨在通过整体分析句子来预测句子间的关系;以及 词语级 (token-level) 任务,如 命名实体识别 (NER, Named Entity Recognition) 和 问题回答 (QA, Question Answering),其模型需生成词语级 (token-level) 的细粒度输出。

        将预训练语言表示应用于下游任务的现有策略有 2 种:(1) 基于特征 (feature-based) 的方法,如 ELMo,使用包括将预训练表示作为附加特征的任务特定架构。(2) 基于微调 (fine-tuning) 的方法,如 Generative Pre-trained Transformer (OpenAI GPT),引入了最小任务特定参数,并通过简单地微调预训练参数来完成下游任务。两种方法在预训练时共享相同的目标函数,并用 单向语言模型 来学习 通用语言表示

        我们认为当前的技术严重限制了预训练表示的能力,尤其是对于微调方法。主要限制在于 标准语言模型 (LM) 是单向的 (而非双向的),这限制了在预训练时对可用架构的选择。例如,OpenAI GPT 使用 从左到右 (left-to-right) 架构,其中 每个 token 只能处理 Transformer 自注意力层中先前出现过的 token (区别:BERT 基于 Transformer Encoder 构建,使用 Self Attention,允许一个位置关注到两侧的信息;GPT-2 基于 Transformer Decoder 构建,使用 Masked Self Attention,只允许一个位置看到左边/以前的信息,即右侧的 token 只能了解到左侧的 / 当前的 token 只能了解到过去的)。 这些 限制 对 sentence-level 任务 而言是 次优 的,且 在将基于微调的方法应用于 如 SQuAD 问答的 token-level 任务 时可能是 灾难性 的,因为 双向融合上下文信息 对这些任务是 至关重要 的。

        本文通过提出 BERT (Bidirectional Encoder Representations from Transformers) 来改善基于微调的方法。受完形任务 (Cloze) 的启发,BERT 通过使用 掩码语言模型 (Masked Language Model, MLM) 预训练目标 (objective) 来缓解上述的单向约束限制 (CV 中的掩码图像建模 MIM 正是受此启发设计的)MLM 从输入中随机地 mask 掉一些 tokens,目标是:仅基于其上下文来预测被 mask 掉的 tokens 的原始词表 (vocabulary) id。与从左到右的语言模型预训练不同,MLM 目标允许表示融合左右上下文,从而允许我们 预训练深度双向 Transformer。除了 MLM,我们还引入了 下句预测 (NSP, Next Sentence Prediction) 任务来联合预训练文本对表示。

        本文贡献如下:

  • 证明了 双向预训练对语言表示的重要性。不同于 Radford 等人使用单向语言模型预训练,BERT 使用掩码语言模型 (MLM) 实现预训练的深度双向表示,这也与使用 分别独立训练的从左到右和从右到左的语言模型的浅层进行拼接 的 Peters 等人形成对比。
  • 表明了 预训练表示减少了对许多工程量繁重的任务特定架构的需求。BERT 是第一个基于微调表示的模型,其在大量 sentence-level 和 token-level 任务上实现了 SOTA 性能,优于许多任务特定架构。
  • BERT 超越 11 项 NLP 任务的 SOTA。

二、原理 

        本节介绍 BERT 及其详细实现。框架中有两步:(1) 预训练,模型使用无标签数据在不同的预训练任务上进行训练。(2) 微调,BERT 首先用预训练参数进行初始化,所有参数使用来自下游任务的有标签数据进行微调。尽管使用相同的参数初始化,每个下游任务也都有各自不同的微调模型。图 1 的问答例子将作为本节的一个示例。

        BERT 的一个 显著特征 是其 跨不同任务的联合架构,而预训练架构和最终的下游任务架构则存在 少许区别。   

图 1: BERT 预训练和微调总体过程
除了输出层,预训练和微调使用相同的架构。同一预训练模型参数被用于初始化不同的下游任务模型。
微调时,所有参数都被微调。[CLS] 是一个加在每个输入样本前的特殊 token,[SEP] 则为一个特殊的分离 token (即分离问/答)

2.1 模型架构  

        BERT 的模型架构是一个 多层双向 Transformer 编码器。因为 Transforner 已被普遍应用,我们的实现 基本与原始实现相同,因此省略对模型架构的详尽背景描述,并向读者推荐出色的指南,如 The Annotated Transformer。当然,我整理的也还不错:【机器学习】详解 Transformer_何处闻韶的博客-CSDN博客_transformer是什么 机器学习【机器学习】详解 Transformerhttps://blog.csdn.net/qq_39478403/article/details/115172787

        在本工作中,我们定义 (Transformer block) 层数为 L,隐藏层大小为 H,自注意力头数为 A。主要报告在两种模型大小上的结果:

BERT_{BASE} (L=12, H=768, A=12, Total Param=110 M)

BERT_{LARGE} (L=24, H=1024, A=16, Total Param=340 M)

        BERT_{BASE} 被设为具有与 OpenAI GPT 相同的模型大小以便比较。然而重要的是,BERT Transformer 使用 双向的自注意力,可关注左右双向上下文;而 GPT Transformer 使用 受限的自注意力,每个 token 仅能关注其左侧单向上下文


2.2 输入/输出表示

        为让 BERT 处理各种下游任务,我们的 输入表示能够在一个 token sequence 中明确表示单个 sentence 和一对 sentences (如 <Question, Answer>)。 在整个工作中,一个 句子 (sentence) 可以是一个具有任意跨度的连续文本,而非实际的语言中的句子。一个 序列 (sequence) 是指输入到 BERT 的 token sequence,可以是 单个 sentence(一对) 两个 pack 在一起的 sentences

        我们使用大小为 30000 的 token vocabulary 构造 WordPiece 嵌入 (基本过程:对 text 采用 subword 粒度的 WordPiece tokenization 得到一些列有意义的 tokens,再插入各种特殊 tokens,最后基于 vocabulary 将所有 tokens 编码转换为 id 构成输入嵌入)。每个 sequence 的首个 token 总为一个特殊的 分类 token ([CLS])。该 token 的最后隐藏层状态/向量 被用作 用于分类任务的聚合序列表示。而一对 sentence 则被打包 (packed) 为单个 sentence。用两种方式区分 sentences。首先,用一个 特殊 token ([SEP]) 分离二者。其次,对每个 token 加入一个 已学习的嵌入 来指示其属于 sentence A 还是 sentence B。

        如图 1 所示,我们将 输入嵌入 标记为 E,将 分类 token ([CLS]) 的 最后隐藏层向量 标记为 C \in \mathbb{R}^{H}第 i 个 (i^{th}) 输入 token 的 最后隐藏层向量 标记为 T_i \in \mathbb{R}^{H}

        例如,给定两个句子 sentence A:"my dog is cute" 和 sentence B:"he likes palying" 作为输入样本,BERT 会将其转换成一系列这样的 tokens:"[CLS] my dog is cute [SEP] he likes play ##ing [SEP]"。BERT 使用 WordPiece 分词方法 (针对英文),其将 token 拆成 子词单元 (subword),所以有的 token 会拆出 词根,如 "palying" 会变成 "paly" + "##ing"。

        对于一个给定的 token,其 输入表示 是通过 将对应的 token 嵌入、分割 (segment) 嵌入、位置 (position) 嵌入 求和 (不是拼接 concat,就是按元素相加) 构造而成的。这种构造的可视化表示如图 2 所示。

图 2: BERT 输入表示
输入 (input) 嵌入 = 词 (token) 嵌入 + 分割 (segmentation) 嵌入 + 位置 (position) 嵌入

        在实际中,先将输入 Input 转换为 token embedding + segment embedding + position embedding。当 输入 Input 是英文单词 时,还需通过 BERT 的 Tokenization 工具对每个单词进行 分词 (tokenize) (tokenization 旨在将输入文本切分成一个个 token,并与 vocabulary 配合以让机器认识文本,其难点在于如何切分使输入文本中所有的 tokens 都具有恰当合理的含义,且不会存在遗漏 (OOV) 问题)。例如,“Playing” 将转换成 “Play” + “# #ing”,因为英文词表是通过词根与词缀的组合来新增单词语义的,所以选择用分词方法可 减少整体的词表 (vocabulary) 长度。若 输入 Input 为中文字符,则输入 通常无需分词,整段话的每一个字用 “空格” 隔开即可 (主要看模型对文本是按词还是按字切分)。

        注意,BERT 无法直接处理文本字符,故不论中文英文,都需通过 词表/字典 vocab.txt 将 每一个字或单词转换成字典索引 (id) 输入

        此外,因为无法获得 word token 的位置信息,BERT 和 transformer 一样也加入了 绝对位置编码 (absolute position embedding),但 BERT 用的不是 transformer 的函数型 (functional) 编码,而是直接采用类似 word embedding 的方式 (Parametric) 直接获得 position embedding。

        因为模型可能有多个 sentence segments 的输入,所以也需加入 segment 的 embedding,例如 [CLS], A_1, A_2, A_3, [SEP], B_1, B_2, B_3, [SEP] 对应的 segment 输入是 [0, 0, 0, 0, 0, 1, 1, 1, 1],然后再根据 segment id 进行 embedding lookup 得到 segment embedding。示例如下:

# segment: [CLS], A_1, A_2, A_3, [SEP], B_1, B_2, B_3, [SEP]
# segment id: [0, 0, 0, 0, 0, 1, 1, 1, 1]

tokens.append("[CLS]")
segment_ids.append(0)

for token in tokens_a:
  tokens.append(token)
  segment_ids.append(0)

tokens.append("[SEP]")
segment_ids.append(0)

for token in tokens_b:
  tokens.append(token)
  segment_ids.append(1)

tokens.append("[SEP]")
segment_ids.append(1)

        通常,BERT 有两种输出,一是对应的 [CLS] 的 Pooler Output,二是 Sequence Output,对应 sequence 中所有 words 的最后隐藏层输出。因此,BERT 主要可以处理两种任务,一是使用 Pooler Output 的 分类 / 回归任务 (token-level),二是使用 Sequence Output 的 序列任务 (Sequence-level)。 


2.3 预训练 BERT

        我们不使用 从左向右 或 从右向左 的语言模型 (LM) 分别预训练 BERT,而是用本节所述的 两个无监督任务 同时 预训练 BERT,该步骤如图 1 左侧 或 下图 所示:

BERT 预训练示意图

        注意,NLP 预训练有别于早期的 CV 预训练:NLP 预训练可以采用无需样本标签的无监督学习,而 CV 预训练则通常是需要样本标签的有监督学习 (注意,现在诸如 对比学习、受掩码语言建模 MLM 启发的掩码图像建模 MIM 等很多方法都可实施无监督 CV 预训练了)。因为 NLP 预训练只是预测被 masked 的 word,及判断是两段 sentences 是否有顺序关系,故所需标签只需通过简单的代码实现,而无需大量昂贵的人工标注 (当然,相应的代价就是大量来自网络的无监督语料存在 noise,不如人工标注那样精细准确)。 


2.3.1 任务一:Masked LM

        直觉上,我们有理由相信 深度双向模型从左到右模型 从左到右和从右到左模型的浅层拼接 (concat) 更强大。不幸的是,标准条件语言模型 (standard conditional language model) 只能从左到右或从右到左训练,因为 双向条件 会允许每个词直接 “看到自己”,并且模型可在一个 多层次上下文 (multi-layered context) 中轻松地预测到目标词。(原句:since bidirectional conditioning would allow each word to indirectly “see itself”, and the model could trivially predict the target word in a multi-layered context)

        为训练一个深度双向表示,我们简单地随机 mask 掉一定比例的输入 tokens,然后预测这些被 masked 掉的 tokens。我们将该过程称为 masked LM (MLM) —— 尽管其在文献中被常称为 完型填空 (Cloze) 任务。在本例中,对应于 masked tokens 的最后隐藏层向量被馈入一个关于词表的输出 Softmax,如同在标准 LM 一样。所有实验中,随机将每个序列中所有 WordPiece tokens 的 15% mask 掉。与去噪自编码器相比,我们只预测被 mask 掉的 tokens 而非 重建整个输入。

        尽管这允许我们获得双向预训练模型,但其带来的 负面影响 是 构成了预训练和微调之间的不匹配,因为 [MASK] token 不会出现在微调阶段。为缓解这种 不匹配,我们 不总是用 [MASK] token 来替换被 masked 掉的 tokens。训练数据生成器随机选择 15% 的 token 位置用来做预测。若第 i 个 token 被选中,则 按以下方式处理该 token

  1. 80% 的概率:用 [MASK] token 替换
  2. 10% 的概率:用 随机 token 替换
  3. 10% 的概率:保持不变

        代码示例: 

for index in cand_indexes:
  if len(masked_lms) >= num_to_predict: # 15% of total tokens
    break
  ...
  masked_token = None
  # 80% of the time, replace with [MASK]
  if rng.random() < 0.8:
    masked_token = "[MASK]"
  else:
    # 10% of the time, keep original
    if rng.random() < 0.5:
      masked_token = tokens[index]
    # 10% of the time, replace with random word
    else:
      masked_token = vocab_words[rng.randint(0, len(vocab_words) - 1)]

  output_tokens[index] = masked_token

        该过程的变体比较详见附录 C.2。      


2.3.1 任务二:Next Sentence Prediction (NSP)

下句预测任务 (NSP) 示意图

        大部分重要的下游任务例如问答 (QA) 和自然语言推断 (NLI) 都是 基于对两个 sentences 之间的关系的理解,这并非是直接通过语言建模捕获的。为训练一个能理解 sentences 间关系的模型,我们预训练了一个 二元下句预测任务 (binarized next sentence prediction),所用到的 sentence 对可从任何单语语料库中生成。特别地,当为每个预训练实例选择一个 sentence 对 AB,50% 的情况 B后的下句 (标记为 IsNext), 50% 的情况 B 是语料库中的一个随机句子 (标记为 NotNext)。图 1 中,C 用于下句预测 (NSP)。尽管该方法十分简单,我们仍在 5.1 节论证了面向该任务的预训练对 QA 和 NLI 是十分有效的 (The vector C is not a meaningful sentence representation without fine-tuning, since it was trained with NSP)。

        NSP 任务与 Jernite 等 (2017) 和 Logeswaran 与 Lee (2018) 等人使用的表示学习目标密切相关。然而,之前的工作 中,只有 sentence 嵌入 被迁移到下游任务,而 BERT 则迁移 所有参数 来初始化末端任务的模型参数。

        预训练数据:预训练过程很大程度上遵循着现存的语言模型预训练文献。对于预训练语料库,我们使用了 BooksCorpus (800M words) 和 English Wikipedia (2500M words)。对于 Wikipedia,我们只提取 Wikipedia 的文本段落、忽略列表、表格和标题。为 提取长连续序列,关键是使用 文档级 (document-level) 语料库,而非如 Billion Word Benchmark 这样的 无序/打乱 (shuffled) 句子级 (sentence-level) 语料库


2.4 微调 BERT   

        微调很直观/直截了当,因为 Transformer 中的 自注意力机制 允许 BERT 通过 交换合适的输入输出 来建模许多下游任务 —— 无论他们是否包含单文本还是文本对。对于涉及文本对的应用,常见的模式是在应用 双向交叉注意力 (Bidirectional Bross Attention) 前 分别独立编码文本对。取而代之地,BERT 用自注意力机制来统一 (编码+注意力) 这两个阶段,因为 使用自注意力机制编码一个拼接的文本对,将有效包含两个句子间的双向交叉注意力

        对于每个任务,我们简单地将任务特定的输入和输出插入到 BERT,并端到端地微调所有参数。关于输入,来自预训练的 sentence A 和 sentence B 类似于:

  1. 释义中的句子对 (sentence pairs in paraphrasing)
  2. 蕴含中的假设-前提对 (hypothesis-premise pairs in entailment)
  3. 问答中的问题-段落句子对 (question-passage pairs in question answering)
  4. 文本分类或序列标注中的退化文本-∅对 (a degenerate text-∅ pair in text classifification or sequence tagging)

        关于输出,token 表示 被馈入一个 输出层 以执行 token-level 任务,例如序列标记或问答,而 [CLS] 表示 被馈入一个 分类器输出层,例如蕴含或情感分析 (entailment or sentiment analysis)。

        相比于预训练,微调的代价小得多。论文中的很多结果都可以在 TPU 上花费约 1 小或在 GPU 花费几个小时,从一个完全相同的预训练模型开始复现。我们将在第 4 节的相应小节中描述任务特定细节。更多细节详见附录 A.5。


三、实验

3.1 GLUE

        通用语言理解评估 (The General Language Understanding Evaluation, GLUE) 基准 是各种自然语言理解任务的集合。 GLUE 数据集的说明详见附录 B.1。

  在 GLUE 上 微调 时,我们按第 3 节中的描述来 表示输入序列 (针对单句或句对),并使用与第一个输入 token [CLS] 相对应的 最终隐藏向量 C \in \mathbb{R}^{H}(即 模型输出 / 嵌入表示) 作为 聚合表示 (aggregate representation)。在微调中唯一引入的新参数是 分类层权重 W \in {\mathbb{R}^{K \times H}}(即 全连接层分类头),其中 K 是 标签数 (类别数)。我们用嵌入表示 C 和全连接层权重 W的矩阵乘法运算得到分类预测结果 softmax(CW^T) \in \mathbb{R}^{K},并计算标准的分类损失 \log (softmax (C{W^T}))

        在所有的 GLUE 任务数据上,我们用 batch size = 32 微调 3 个 epoch。对于每个任务,我们在开发集上选择最佳微调学习率(在 5e- 5, 4e-5, 3e -5, 2e−5 间)。此外,对于 BERT_{LARGE},我们发现在小数据集上微调有时不稳定,所以随机重启了几次,并选择了开发集上表现最佳的模型。随机重启 (Random Start) 时,使用相同的 Checkpoint,但执行不同的 微调数据 shuffling 分类器层初始化

表 1:GLUE 测试结果

        结果如表 1 所示,可见在所有任务中,BERT_{LARGE} 都显著超越 BERT_{BASE},尤其是在很小的训练集中。关于模型大小的影响,在 5.2 节有更透彻的探索。


四、附录

A BERT 的额外细节

A.1 预训练的阐述

        我们提供了预训练任务的例子如下。

        Masked LM and the Masking Procedure

        假定无标签 sentence 为:my dog is hairy,且我们在随机 mask 过程 (占 token 总数的 15%) 中选择第 4 个 token (即 hairy),则 mask 过程可表示为:

        该过程的优点在于,Transformer 编码器不知道它将被要求预测哪些 words,或哪些 words 已被随机 words 替换,因此它 被迫保留每个输入 token 的分布式上下文表示。此外,因为随机替换只发生在所有 token 的 1.5% (即 15% 中的的 10%),这似乎 不会损害模型的语言理解能力。在 C.2 节中,我们评估了此过程的影响。

        与标准语言模型 (LM) 训练相比,masked LM 仅对每个 batch 中 15% 的 token 进行预测,这表明模型可能需要更多的预训练步骤才能收敛。在第 C.1 节中,我们证明了 MLM 的收敛速度确实比从左到右模型 (预测每个 token) 稍慢,但是 MLM 模型的 经验提升/改善 (empirical improvements) 远超所增加的训练成本

        Next Sentence Prediction

         下句预测 可阐述为下例:


A.2 预训练过程

        为生成每个训练输入序列,我们从语料库中采样了两段文本,并称之为 “句子 (sentences)”,尽管它们通常比单个 sentence 长得多(但也可以更短)。第一个 sentence 接收 A 嵌入,第二个 sentence 接收 B 嵌入。50% 的时间 BA 后的实际下句,50% 的时间 是一个随机句子,这是为 “下句预测” 任务设计的。它们被采样以便于 组合长度 ≤ 512 个 token。在 WordPiece tokenization 后应用 掩码率统一为 15% 的 LM masking,且未对 部分词块 (partial word pieces) 予以特殊考虑。

        我们采用 batch size = 256 个序列 (256 个句子 * 512 tokens = 12,8000 tokens/batch) 训练 100,0000 steps,大约在 33 亿词的语料上训练 40 epochs。我们使用学习率为 1e-4,\beta_1 = 0.9\beta_2 = 0.999,L2 权重衰减为 0.01 的 Adam 优化器,在前 10000 步采用学习率 warmup,使用 学习率线性衰减。我们在所有层使用 概率为 0.1 的 Dropout。我们遵循 OpenAI GPT 使用 GeLU 激活函数 而非标准 ReLU。训练损失 是 平均 masked LM 似然 (likelihood) 和 平均下句预测似然 (likelihood)

        使用更长序列会不成比例地增加训练成本,因为注意力是序列长度的二次方。为在我们的实验中加速预训练,我们在 90% 的步中预训练长度为 128 的序列,然后在其余 10% 的步中训练长度为 512 的序列以学习位置嵌入。


A.3 微调过程

        微调时,除 batch size、学习率 和 训练 epochs 外,大部分模型超参数与预训练时相同。Dropout 概率始终为 0.1。

        最优超参数值是特定于任务的,但我们发现以下范围的值 在所有任务上都表现较好

        我们还观察到,与小数据集相比,大型数据集 (例如 10 万多个带标签的训练样本) 对超参数选择的敏感度要低得多。微调通常非常快,因此合理的做法是,只需对上述参数进行彻底搜索,并选择在开发集上表现最佳的模型。


A.4 BERT,ELMO 和 OpenAI GPT 的比较

        此处,我们研究了最近流行的表示学习模型 (包括 ELMo、OpenAI GPT 和 BERT) 的差异。模型架构之间的比较如图 3 所示。注意,除架构差异外,BERT 和 OpenAI GPT 是基于微调方法,而 ELMo 则是基于特征的方法。

图 3: 预训练模型架构的差异。​​​​BERT 使用双向 Transformer。OpenAI GPT 使用从左到右的 Transformer。ELMo 使用独立训练的从左到右和从右到左 LSTM 的串联来为下游任务生成特征。三者中,只有 BERT 表示在所有层的左右上下文中共同条件化。除架构上的差异,BERT 和 OpenAI GPT 是微调方法,而 ELMo 是基于特征的方法。

        与 BERT 最具可比性的现有预训练方法是 OpenAI GPT,它在大型文本语料库上训练 从左到右的 Transformer LM。事实上,BERT 中的许多设计和决策都是有意使其尽可能接近 GPT 以便比较。这项工作的核心论点是第 3.1 节中介绍的 双向性 和 促进大部分经验改进的两个预训练任务,但我们确实注意到 BERT 和 GPT 的训练方式差异

        为分离这些差异的影响,在第 5.1 节中进行了消融实验,实验表明大部分改进实际上来自两个预训练任务及其启用的双向性。


A.5 在不同任务上的微调

        在不同任务上微调 BERT 的图示可以在图 4 中看到。我们的任务特定模型是通过将 BERT  一个额外的输出层 结合而形成的,因此只需从头学习最少量的 (输出层) 参数。

        其中, (a) (b) 是 sequence-level 任务,(c) (d) 是 token-level 任务。图中,E 是输入嵌入,T_i 是 token i 的上下文表示,[CLS] 是用于分类输出的特殊符号,[SEP] 是分离非连续 token 序列的特殊符号。

图 4: 不同任务的 BERT 微调示意图

B 实验设置细节

B.1 GLUE 基准实验细节描述

        表 1 中的 GLUE 结果是从 https://gluebenchmark.com/leaderboard 和 https://blog.openai.com/language-unsupervised 获得的。GLUE 基准测试包括以下数据集:

        MNLI —— 多体裁自然语言推断 (Multi-Genre Natural Language Inference) 是一项大规模的、众包 (crowdsourced) 的蕴含分类 (entailment classification) 任务。给定一对句子,目标是预测第二个句子对于第一个句子是蕴含 (entailment)、矛盾 (contradiction) 还是中性 (neutral) 的关系。

        QQP  —— Quora 问题对 (Quora Question Pairs) 是一个二分类任务,旨在判断两个 Quora 上的问题是否在语义上等价。

        QNLI —— 问题自然语言推断 (Question Natural Language Inference) 是 斯坦福问题回答数据集 (Stanford Question Answering Dataset) 的一个转换为二分类任务的版本。 正样本 为包含了正确回答的 (问题-句子) 对,负样本 则为来自同一段落的不包含答案的 (问题-句子) 对。

        SST-2 —— 斯坦福情感树库 (Stanford Sentiment Treebank) 是一个二元单句分类任务,由从电影评论中提取的句子和他们情感的人工注释组成。

        CoLA —— 语言可接受性语料库 (Corpus of Linguistic Acceptability) 是一个二元单句分类任务,其目标是预测一个英语句子在语言上是否 “可接受”。

        STS-B —— 语义文本相似性基准 (Semantic Textual Similarity Benchmark) 是从新闻标题和其他来源中提取的句子对的集合。它们用 1 到 5 的分数进行注释,表示两个句子在语义方面的相似程度。

        MRPC —— 微软研究释义语料库 (Microsoft Research Paraphrase Corpus) 由自动从在线新闻来源中提取的句子对组成,并带有人工注释,用于判断句子对中的句子在语义上是否相同。

        RTE —— 识别文本蕴涵 (Recognizing Textual Entailment) 是一个类似于 MNLI 的二元蕴涵任务,但训练数据要少得多。

        WNLI —— Winograd NLI 是一个小型自然语言推理数据集。GLUE 网页指出,该数据集的构建存在问题,并且提交给 GLUE 的每个训练系统的性能都低于预测多数类的 65.1 基线准确度。 因此,为了对 OpenAI GPT 公平,我们排除了这个集合。对于我们的 GLUE 提交,我们总是预测多数类。


C 额外的消融研究

C.1 训练步数的影响

        图 5 展示了在 MNLI 开发集上微调已预训练 k 步的模型后得到的 acc。这允许我们回答如下问题:

  • 问题 1:BERT 确实需要如此大规模的预训练 (12,8000 words/batch * 100,0000 steps) 来实现微调的高准确率吗?
  • 回答 1:是的,相比于 500k 步训练,BERT_{BASE} 在 MNLI 上的 1M 步训练实现了约 1.0% 的准确率提升。
  • 问题 2:MLM 预训练的收敛慢于 LTR 预训练的原因在于每个 batch 中仅有 15% 而非所有 words 被预测?
  • 回答 2:MLM 模型的收敛确实慢于 LTR 模型。然而,MLM 模型的绝对准确率几乎立即开始超越了 LTR 模型。

C.2 不同 Masking 过程的消融

        在第 3.1 节中提到,在使用 掩码语言模型 (MLM) 目标预训练时,BERT 使用混合策略来 mask 目标 token。以下是评估不同 masking 策略效果的消融研究。

        注意,masking 策略旨在 减少预训练和微调之间的不匹配 (mismatch),因为 [MASK] 符号在微调阶段永远不会出现

        我们报告了 MNLI 和 NER 的开发结果。对于 NER,我们报告了微调和基于特征的方法,因为我们预计基于特征的方法的不匹配将被放大,因为模型将没有机会调整表示。

        结果如表 8 所示。在表中,MASK 表示将目标 token 替换为 MLM 的 [MASK] 符号;SAME 意味着保持目标 token 不变;RND 意味着用另一个随机 token 替换目标 token。 

        表格左侧的数字代表了 MLM 预训练期间使用的特定策略的概率 (BERT 使用了 80%、10%、10%),右侧部分代表了开发集结果。对于基于特征的方法,我们 将 BERT 的最后 4 层拼接 (concat) 起来作为特征,这在 5.3 节中被证明是最好的方法。 

        从表中可见,微调对不同的 masking 策略具有惊人的鲁棒性。然而,正如预期的那样,在将基于特征的方法应用于 NER 时,仅使用 MASK 策略是有问题的。有趣的是,仅使用 RND 策略的性能也比我们的策略差得多。 


五、ELMO、BERT 与 GPT


六、Tokenization 方法归纳

{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w e s t </w>': 6, 'w i d e s t </w>': 3}

{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w es t </w>': 6, 'w i d es t </w>': 3}

{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w est </w>': 6, 'w i d est </w>': 3}

>>> import sentencepiece as spm
>>> s = spm.SentencePieceProcessor(model_file='spm.model')
>>> for n in range(5):
...     s.encode('New York', out_type=str, enable_sampling=True, alpha=0.1, nbest=-1)
...
['▁', 'N', 'e', 'w', '▁York']
['▁', 'New', '▁York']
['▁', 'New', '▁Y', 'o', 'r', 'k']
['▁', 'New', '▁York']
['▁', 'New', '▁York']

from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.pre_tokenizers import Whitespace
from tokenizers.trainers import BpeTrainer

tokenizer = Tokenizer(BPE())
tokenizer.pre_tokenizer = Whitespace()

trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
tokenizer.train(trainer, ["wiki.train.raw", "wiki.valid.raw", "wiki.test.raw"])

output = tokenizer.encode("Hello, y'all! How are you 😁 ?")
print(output.tokens)
# ["Hello", ",", "y", "'", "all", "!", "How", "are", "you", "[UNK]", "?"]


七、BERT 知识点 Part1


八、BERT 知识点 Part2


参考资料:

彻底理解 Google BERT 模型彻底理解 Google BERT 模型

https://www.baidu.com/link?url=M9gs_xve-DBWqZmQjWlB5ybOX_larnfP0PTfBRrq9u5laj95jcCAGb4dx8ep0nux&wd=&eqid=805336bb000088f1000000026131c6f0

飞桨AI Studio - 人工智能学习与实训社区

机器如何认识文本 ?NLP中的Tokenization方法总结

BERT 是如何分词的 · Alan Lee

请问各位知乎大佬,bert适用于所有文本NLP业务吗?中文bert模型所用的分词工具是什么? - 知乎

关于BERT,面试官们都怎么问

常用预训练语言模型(PTMs)总结

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值