Tic商业评论

关注微信公众号【站长自定义模块】,定时推送前沿、专业、深度的商业资讯。

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

  • QQ空间
  • 回复
  • 收藏

TensorFlow2 BERT和Transformer的例子

lijingle 深度学习框架 2021-12-15 13:15 2184人围观

作为TensorFlow系列的一部分,本文将重点介绍如何对BERT和Transformer进行编码。这些例子包括:
  1. IMDB文件:使用预先训练的TF Hub-BERT模型和AdamW进行情感分析,
  2. GLUE/MRPC BERT微调,
  3. 语言翻译的Transformer。
IMDB文件:使用预先训练的TF Hub-BERT模型和AdamW进行情感分析
在例子中,我们使用一个预训练的TensorFlow Hub模型来表示BERT和AdamW优化器。因为大部分工作都是由TF-Hub模型完成的,所以我们将对这个示例进行简单的解释。
首先,我们下载并准备IMDB文件。


接下来,我们准备数据集。


我们将创建一个包含预训练BERT预处理层和预训练BERT处理层的模型,然后,我们添加一个分类头,其中包含一个dropout和一个dense层。


接下来,我们实例化一个新模型,用AdamW优化器进行训练。安装后,我们使用它来评估测试数据。


导出模型

代码的最后一部分导出并重新加载SavedModel。


GLUE/MRPC BERT 微调

在本例中,我们为“glue/mrpc”数据集微调了一个BERT模型。该数据集标记两个句子是否语义等价。


在这个例子中,我们还使用了一个预先训练好的模型。其配置、词汇表和checkpoint存储在远程存储器gs_folder_bert中。下面是gs_folder_bert的目录列表。


gs_folder_bert包含在BERT中的预训练阶段训练的BERT模型。我们将对MRPC的BERT分类器进行微调。


在第25行中,我们将数据集加载到“glue”中。它是一个Python字典,包含加载后的训练、测试和验证数据.


接下来,我们将创建一个适应训练数据词汇表的标记器。我们将使用此标记器将文本转换为整数序列-每个标记一个整数标记索引。


每个样本包含两个句子。我们添加一个[CLS]标记(一个分类标记)来指示样本的开始,并在每个句子的结尾添加一个[SEP]标记。准备好的数据将一次输入一个BERT 模型。



在下面的bert_encode方法中,它从字典glue_dict中提取句子1和2,准备它们,并将它们编码成整数序列。最后,我们返回三个数据结构:

  1. input_word_id:整数序列,每个 token一个整数,
  2. input_mask:指示输入token是否包含填充值0(稍后详细介绍),以及
  3. input_type_id:指示标记i是属于句子1(值0)还是属于句子2(值1)。


给定一个文本输入,input_type_id相当于BERT文件中的段嵌入。在下面的示例中,前六个token属于句子1,并在input_type_ID中标记为0。其余的是1。


接下来,我们调用bert_encode对训练、验证和测试进行编码。


我们一次对整个数据集中的样本进行编码。因此,glue_train包含所有3688个样本,input_word_id的形状为(3668103),(样本数,序列长度)。


训练数据集中最长的样本有103个token。所有的训练样本都用0填充到这个最长的序列中。这允许将样本训练为张量。填充由to_tensor()完成。下面是此方法的工作原理示例。


input_mask表示token i是持有填充的0还是现在持有。应忽略填充标记并输出默认值,例如0,mask故意创建为单独的张量,以便可以传递到后续层,接下来,我们将创建一个BERT模型。配置存储在远程目录gs_folder_bert中。以下是配置文件的内容。


作为参考,这是创建的BERT模型(Transformer的编码)的模型摘要。


然后,我们使用该模型测试了10个训练样本作为乱序检查。


这是创建的最终模型。


该模型输出两个类(类相等和类不相等)的logit。因为这是一个二进制类,所以只需一个logit后跟一个sigmoid函数就可以完成。然而,使用两个logit是很常见的。选择哪一个并不重要。以下是10个样本的输出,每个样本有两个logit输出。


但是模型只是随机初始化的。接下来,我们将使用远程目录中的checkpoint来恢复它。我们将使用AdamW优化器再次对模型进行3个阶段的训练。


我们使用的AdamW优化器将有一个自定义的预热期,然后逐渐衰减。学习率如下所示:


作为最后一项任务,我们使用新样本测试模型。作为演示,我们再次保存并恢复模型。


TRecord

在现实数据集中,内存不够大,无法容纳所有样本。相反,在需要时从文件中读取数据。但是,为了更快地读取和处理文件,我们可以先将数据保存为TF设计的二进制TRecord格式。在下面的代码中,我们将示例保存为TFRecord文件,并从中创建数据集。


作为高级用户的参考,下面的代码对数据加载具有较低级别的控制。


这将是创建相应数据集的代码:


TF Hub

TF Hub还直接提供预先训练的TF Hub BERT模型。下面是创建BERT编码器的代码,不带分类头。然后,我们可以添加我们自己的分类器头。


或者我们可以直接使用分类器_模型得到一个BERT分类器。


Transformer语言翻译

下图是 Transformer 的一般架构。 它在深度学习中很复杂但很重要。 假设你对 Transformer 有基本的了解。 如果你看不懂,则应先阅读这篇文章(稍后添加连接)。 在本例中,我们使用Transformer将葡萄牙语翻译成英语。

数据集准备

首先,我们下载用于将葡萄牙语翻译成英语的数据集文件。 我们还分别为英语和葡萄牙语样本准备了两个分词器。 分词器的词汇量有限。 如果单词不在词汇表中,分词器会将其分解为可识别的子词,并将每个子词或词分词为一个整数(标记索引)。 这是“Transformer is awesome.”的整数序列


接下来,我们添加每个样本的开始和结束标记。


然后,我们创建数据集。 但作为演示,我们丢弃token长度超过 40 的样本。在本示例中,将缩小许多配置以加快训练速度。。


Word Embedding + Position Embedding

Transformer 使用学习嵌入将token索引转换为向量表示。 为了改进模型,词的位置也被嵌入(添加)到词嵌入中。 为了将标量位置 pos 转换为 128 维向量,我们分别对向量中的偶数和奇数元素使用下面的 sin 和 cosine 函数。 (注意,论文使用了 512 维向量)。



这是 512 维向量中前 50 个位置值的可视化。 这些值根据右侧的颜色条着色。 如图所示,向量的早期元素中的位置值被更频繁地回收。


Padding

Padding通常用于将输入序列扩展到特定的固定长度。 对于应该忽略的输入,mask值为 1,否则为 0。并且此mask可以传递给其他层以帮助它们生成输出。

此外,与时间序列模型不同,Transformer 在训练期间同时进行所有预测。 但在推理中,它仍然一次预测一个词/子词。 在训练期间,为了避免注意力模块窥视未来的序列,我们创建了一个mask来掩盖这些信息。


Scaled Dot-Product Attention

接下来,我们创建一个 Scaled Dot-Product Attention。 等式是


左图是模型设计。


这是代码。


Multi-head attention

接下来,我们使用scaled dot-product attention实现多头注意力。


但是,我们不会创建 8 个缩放点积注意力的实例。 相反,下面的代码将正确地 reshape q、k、v,这样所有 8 个头都可以通过scaled dot-product attention作为单个实体进行处理。


位置前馈网络

接下来,我们在每个token位置实现一个相同且可共享的位置前馈网络。


编码器层

每个编码器层将如下所示:


但是下面的代码在两个归一化层之前都有一个 dropout 层。


解码层

解码器层如下图所示。 它有 2 个多头注意力模块。 第二个使用编码器的输出来生成密钥 K 和值 V。


这是代码,它再次在层归一化层之前添加了一个 dropout 层。


编码器

接下来,我们堆叠编码器层以创建编码器。


我们将词嵌入结果与位置嵌入一起添加为编码器的输入。 该代码还在编码器之前添加了一个 dropout。


解码器

现在,我们准备堆叠解码器层来创建解码器。


Transformer

最后,我们将编码器和解码器放在一起,创建了一个 Transformer。


这个编码器和解码器分别有四个堆叠的编码器层和四个解码器层。 每个单词都由 Transformer 编码器编码为 128 维向量。 注意模块每个使用 8 个头。 我们使用 dropout 为0.1。


Training

训练将使用 Adam 优化器和一个自定义调度器来计算学习率。


其余步骤看起来与许多其他 DL 代码相似。 所以我会快速略过。 以下是损失函数和性能指标。


接下来,我们将创建 Transformer、CheckpointManager 和一个函数,用于根据输入为编码器和解码器创建不同的mask。


这是训练步骤。 Transformer 不是顺序模型。 有了源句和目标句,我们可以在一个时间步内预测整个输出序列。 我们只需要确保对于每个解码器的标记位置,注意力模块都创建了正确的掩码,这样它就无法看到未来的输入序列。


和训练循环。


验证

训练后,我们使用 Transformer 进行翻译。 在推理中,我们一次只预测一个词/子词。 我们需要到目前为止预测的单词来预测下一个单词。 所以让我们用下面的输入句子来追踪它。

input: este é um problema que temos que resolver

prediction: so this is a problem that we have to solve the global challenges

分词器将输入句子转换为整数标记索引序列,然后我们将开始和结束标记添加到该序列中。这是 Transformer 编码器的输入。 Transformer 解码器的第一个输入将是英文开始标记。现在,我们调用 Transformer 进行预测。转换器将为分词器中使用的词汇表中的每个单词预测一个分数。我们将使用 argmax 从这些预测中选择下一个最有可能的词。返回值是下一个词/子词的标记索引。

现在我们将这个整数附加到我们到目前为止预测的单词上。预测序列现在包含 <s> 和“so”的整数序列。在下一个时间步中,我们将此序列作为新的输入提供给解码器。解码器将有两个输出,一个用于每个解码器的输入token。我们选择最后一个词的预测并再次使用 argmax。这次我们选择“这个”这个词。我们将其附加到预测序列中,现在是 <s>、“so”、“this”。


我们在下一个时间步中使用这个序列作为解码器。 这次解码器将有三个输出。 同样,我们使用最后一个位置的预测来选择我们的下一个单词。 我们继续迭代,直到预测到结束标记</s>。 这是对输入进行预测的代码。


这就是我们所说的将葡萄牙语句子翻译成英语的方式。

到此结束



路过

雷人

握手

鲜花

鸡蛋
我有话说......

TA还没有介绍自己。

电话咨询: 135xxxxxxx
关注微信