使用 TensorFlow Hub 的预处理模型简化 BERT
2020 年 12 月 9 日

作者:软件工程师 Arno Eigenwillig 和 Luiz GUStavo Martins,开发者倡导者

BERT 和其他 Transformer 编码器架构在自然语言处理 (NLP) 中取得了巨大成功,用于计算文本的向量空间表示,无论是在推动学术基准的最新技术还是在大型应用中,例如 Google 搜索。BERT 自创建以来就已在 TensorFlow 中可用,但最初依赖于非 TensorFlow Python 代码将原始文本转换为模型输入。

今天,我们很高兴宣布一种更简化的完全在 TensorFlow 中构建的 BERT 使用方法。该解决方案在 TensorFlow Hub 上提供了 **预训练的编码器** 和匹配的 **文本预处理** 模型。现在,只需几行代码即可在文本输入上运行 TensorFlow 中的 BERT

An animation of the preprocessing model that makes it easy for you to input text into BERT (described below).

预处理模型的动画,使您可以轻松地将文本输入到 BERT(如下所述)。

# Load BERT and the preprocessing model from TF Hub.
preprocess = hub.load('https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/1')
encoder = hub.load('https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3')

# Use BERT on a batch of raw text inputs.
input = preprocess(['Batch of inputs', 'TF Hub makes BERT easy!', 'More text.'])
pooled_output = encoder(input)["pooled_output"]
print(pooled_output)

tf.Tensor(
[[-0.8384154  -0.26902363 -0.3839138  ... -0.3949695  -0.58442086  0.8058556 ]
 [-0.8223734  -0.2883956  -0.09359277 ... -0.13833837 -0.6251748   0.88950026]
 [-0.9045408  -0.37877116 -0.7714909  ... -0.5112085  -0.70791864  0.92950743]],
shape=(3, 768), dtype=float32)

这些编码器和预处理模型是使用 TensorFlow 模型花园 的 NLP 库构建的,并以 SavedModel 格式 导出到 TensorFlow Hub。在幕后,预处理使用 TF.text 库中的 TensorFlow 操作来执行输入文本的标记化,使您能够构建自己的 TensorFlow 模型,该模型可以从原始文本输入到预测输出,而无需 Python 循环。这加快了计算速度、消除了样板代码、减少了错误,并支持完整文本到输出模型的序列化,从而使 BERT 更易于在生产中使用。

为了更详细地展示这些模型如何帮助您,我们发布了两个新的教程

  • 初学者 教程中,解决了一个 _情感分析_ 任务,不需要任何特殊的自定义就能实现出色的模型质量。这是使用 BERT 和预处理模型的最简单方法。
  • 高级 教程中,解决了来自 GLUE 基准 的 NLP 分类任务,并在 TPU 上运行。它还展示了如何在需要多段输入的情况下使用预处理模型。
BERT Model

选择 BERT 模型

BERT 模型是在大量文本语料库(例如维基百科文章的存档)上进行 **预训练** 的,使用 **自监督** 任务,例如从周围的上下文中预测句子中的单词。这种类型的训练使模型能够学习文本语义的强大表示,而无需标记数据。但是,它也需要大量的计算来训练 - 在 16 个 TPU 上需要 4 天(如 2018 年的 BERT 论文 中所述)。幸运的是,在完成这种昂贵的预训练后,我们可以有效地将这种丰富的表示重复用于许多不同的任务。

TensorFlow Hub 提供各种 BERT 和类似 BERT 的模型

  • 八个 BERT 模型 带有原始 BERT 作者发布的训练权重。
  • 24 个 小型 BERT 具有相同的通用架构,但 Transformer 块更少或更小,这使您可以探索速度、大小和质量之间的权衡。
  • ALBERT:这些是四种不同尺寸的“精简 BERT”,通过在层之间共享参数来减少模型大小(但不会减少计算时间)。
  • 8 个 BERT 专家 都具有相同的 BERT 架构和大小,但提供了不同的预训练领域和中间微调任务的选择,以便更 closely 与目标任务保持一致。
  • Electra 具有与 BERT 相同的架构(三种不同尺寸),但作为生成对抗网络 (GAN) 中的判别器进行预训练。
  • 带有 Talking-Heads 注意力和门控 GELU 的 BERT [基础大型] 对 Transformer 架构的核心进行了两项改进。
  • Lambert 已使用 LAMB 优化器和 RoBERTa 中的几种技术进行了训练。
  • MuRIL 是面向印度语言的多语言表示,在 17 种印度语言(包括英语)及其音译对应语言上进行预训练。
  • MobileBERT (英语多语言) 是 BERT 的精简版本,通过从教师 BERT 模型中蒸馏在维基百科、书籍语料库上进行训练。
  • ... 以及更多即将推出的模型。

这些模型是 BERT 编码器。上面的链接会带您到 TensorFlow Hub 上的文档,该文档会引用与每个模型一起使用的正确预处理模型。

我们鼓励开发者访问这些模型页面,以详细了解每个模型针对的不同应用程序。由于它们的通用接口,只需更改编码器模型及其预处理的 URL,便可以轻松地实验和比较不同编码器在特定任务上的性能。

预处理模型

对于每个 BERT 编码器,都有一个匹配的预处理模型。它使用 TF.text 库提供的 TensorFlow 操作将原始文本转换为编码器所期望的数字输入张量。与纯 Python 预处理不同,这些操作可以成为 TensorFlow 模型的一部分,以便直接从文本输入进行提供。来自 TensorFlow Hub 的每个预处理模型都已使用词汇表及其关联的文本规范化逻辑进行配置,不需要进一步设置。

我们已经看到了上面使用预处理模型的最简单方法。让我们再仔细看看

preprocess = hub.load('https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/1')
input = preprocess(["This is an amazing movie!"])
 
{'input_word_ids': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=
  array([[ 101, 2023, 2003, 2019, 6429, 3185,  999,  102,    0,  ...]])>,
 'input_mask': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=
  array([[   1,    1,    1,    1,    1,    1,    1,    1,    0,  ...,]])>,
 'input_type_ids': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=
  array([[   0,    0,    0,    0,    0,    0,    0,    0,    0,  ...,]])>}
 

像这样调用 preprocess() 会将原始文本输入转换为 BERT 编码器的固定长度输入序列。您可以看到它包含一个张量 input_word_ids,其中包含每个标记化输入的数字 ID(包括起始、结束和填充标记),以及两个辅助张量:一个 input_mask(用于区分非填充标记和填充标记)以及每个标记的 input_type_ids(可以区分每个输入中的多个文本段,我们将在下面讨论)。

相同的预处理 SavedModel 还提供第二个更细粒度的 API,它支持将一个或两个不同的文本段放入一个输入序列中,用于编码器。让我们看看一个句子推断任务,其中 BERT 用于预测一个前提是否推断出一个假设。

text_premises = ["The fox jumped over the lazy dog.",
                 "Good day."]
tokenized_premises = preprocess.tokenize(text_premises)
 
<tf.RaggedTensor
  [[[1996], [4419], [5598], [2058], [1996], [13971], [3899], [1012]],
  [[2204], [2154], [1012]]]>
 
 
text_hypotheses = ["The dog was lazy.",  # Entailed.
                   "Axe handle!"]        # Not entailed.
tokenized_hypotheses = preprocess.tokenize(text_hypotheses)
 
<tf.RaggedTensor
  [[[1996], [3899], [2001], [13971], [1012]],
  [[12946], [5047], [999]]]>

每个标记化的结果都是一个 RaggedTensor,它包含数字标记 ID,表示每个文本输入的完整内容。如果某些前提和假设对在下一步中为 BERT 输入创建 seq_length 太长,您可以在此处进行额外的预处理,例如修剪文本段或将其拆分为多个编码器输入。

然后,标记化的输入会被打包到一个固定长度的输入序列中,用于 BERT 编码器

encoder_inputs = preprocess.bert_pack_inputs(
   [tokenized_premises, tokenized_hypotheses],
   seq_length=18)  # Optional argument, defaults to 128.
 
{'input_word_ids': <tf.Tensor: shape=(2, 18), dtype=int32, numpy=
  array([[  101,  1996,  4419,  5598,  2058,  1996, 13971,  3899,  1012,
            102,  1996,  3899,  2001, 13971,  1012,   102,     0,     0],
         [  101,  2204,  2154,  1012,   102, 12946,  5047,   999,   102,
              0,     0,     0,     0,     0,     0,     0,     0,     0]])>,
 'input_mask': <tf.Tensor: shape=(2, 18), dtype=int32, numpy=
  array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
         [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]])>,
 'input_type_ids': <tf.Tensor: shape=(2, 18), dtype=int32, numpy=
  array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
         [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]])>}

打包的结果是已经熟悉的 input_word_idsinput_maskinput_type_ids 字典(分别为 0 和 1)。所有输出都具有一个通用的 seq_length(默认情况下为 128)。在打包过程中,超过 seq_length 的输入会被截断为近似相等的大小。

加速模型训练

TensorFlow Hub 将 BERT 编码器和预处理模型作为独立的部分提供,以便能够加速训练,尤其是在 TPU 上。

Tensor Processing Units (TPUs) 是 Google 自行开发的加速器硬件,擅长处理大型机器学习计算,例如微调 BERT 所需的计算。TPU 在密集张量上运行,并期望像字符串这样的可变长度数据已由主机 CPU 转换为固定大小的张量。

BERT 编码器模型及其关联的预处理模型之间的分离支持将编码器微调计算分布到 TPU 上作为模型训练的一部分,而预处理模型则在主机 CPU 上执行。可以使用 tf.data.Dataset.map() 在数据集上异步运行预处理计算,并将密集输出准备好在 TPU 上由编码器模型使用。像这样的异步预处理还可以提高使用其他加速器的性能。

我们的 高级 BERT 教程可以在使用 TPU 工作器的 Colab 运行时中运行,并演示了这种端到端的流程。

总结

在 TensorFlow 中使用 BERT 和类似模型变得更加简单。TensorFlow Hub 提供了大量的 集合,包括 **预训练的 BERT 编码器** 和 **文本预处理模型**,只需几行代码即可轻松使用。

查看我们交互式的 初学者高级 教程,详细了解如何使用这些模型进行句子和句子对分类。请告知您使用这些新的 BERT 模型构建的内容,并在您的帖子中添加 #TFHub 标签。

致谢

我们要感谢许多同事对这项工作的贡献。

新的预处理模型是与 Chen Chen、Terry Huang、Mark Omernick 和 Rajagopal Ananthanarayanan 合作创建的。

在此次发布中,Sebastian Ebert(Small BERTs)、Le Hou 和 Hongkun Yu(Lambert,Talking Heads)发布了更多 BERT 模型到 TF Hub。

Mark DaoustJosh GordonElizabeth Kemp 极大地改进了本文和相关教程的材料展示。Tom Small 为美丽的 BERT 动画贡献了力量。

下一篇文章
Making BERT Easier with Preprocessing Models From TensorFlow Hub

作者:Arno Eigenwillig,软件工程师,以及 Luiz GUStavo Martins,开发者倡导者BERT 和其他 Transformer 编码器架构在自然语言处理 (NLP) 中取得了巨大成功,用于计算文本的向量空间表示,无论是在学术基准测试中取得最先进水平,还是在像 Google 搜索 这样的大型应用中。BERT 已经可用…