精通 Transformers(三)(3)

本文涉及的产品
NLP 自学习平台,3个模型定制额度 1个月
NLP自然语言处理_基础版,每接口每天50万次
NLP自然语言处理_高级版,每接口累计50万次
简介: 精通 Transformers(三)

精通 Transformers(三)(2)https://developer.aliyun.com/article/1510706

使用高效的自注意力

高效的方法限制了注意机制以实现有效的Transformers模型,因为Transformers的计算和存储复杂度大部分都是由自注意机制导致的。关于输入序列长度的注意机制以二次方式进行缩放。对于短输入,二次复杂度可能不是一个问题。但是,要处理更长的文件,我们需要改进能够与序列长度线性缩放的注意机制。

我们大致可以将高效的注意力解决方案分为三种类型:

  • 使用固定模式的稀疏注意力
  • 可学习的稀疏模式
  • 低秩因式分解/核函数

接下来,让我们以基于固定模式的稀疏注意力开始。

使用固定模式的稀疏注意力

回想一下,注意力机制由查询、键和值组成,可能如此粗略地表述:

在这里,Score函数,大多数情况下是 softmax,执行 QKT 乘法,需要 O(n2)的内存和计算复杂度,因为一个标记位置在完全自注意力模式下会关注所有其他标记位置以构建其位置嵌入。我们对所有标记位置重复相同的过程以获取它们的嵌入,从而导致了二次复杂性问题。这是一种非常昂贵的学习方式,特别是对于长文本 NLP 问题。自然而然地会问,我们是否需要如此密集的交互,或者是否有更廉价的方法来进行计算?许多研究人员已经解决了这个问题,并采用了各种技术来缓解复杂性负担,并降低自注意机制的二次复杂性。他们在性能、计算和内存之间进行了权衡,特别是对于长文档。

减少复杂性的最简单方法是使完全自注意力矩阵稀疏化,或者找到另一种更廉价的方式来近似完全注意力。稀疏注意力模式制定了如何在不干扰层间信息流的情况下连接/断开某些位置,这有助于模型跟踪长期依赖关系并构建句子级编码。

完全自注意力和稀疏注意力依次在图 8.4中描述,其中行对应输出位置,列对应输入位置。完全自注意力模型会直接在任意两个位置之间传递信息。另一方面,在局部滑动窗口注意力中,也就是稀疏注意力,如图右侧所示,空白单元格意味着相应的输入-输出位置之间没有交互。图中的稀疏模型基于特定手动设计的规则,也就是固定模式。更具体地说,它是局部滑动窗口注意力,是最早提出的方法之一,也被称为基于本地固定模式的方法。其背后的假设是有用的信息位于每个位置的相邻位置。每个查询标记都会关注到其位置左侧和右侧窗口/2 个关键标记。在下面的示例中,窗口大小选为 4。这个规则在 transformer 的每一层中都适用。在一些研究中,随着向更深层移动,窗口大小会增加。

以下图简要描述了完全注意力和稀疏注意力之间的区别:

图 8.4 - 完全注意力与稀疏注意力

在稀疏模式下,信息通过模型中的连接节点(非空单元格)传输。例如,稀疏注意力矩阵的输出位置 7 不能直接关注输入位置 3(请参见Figure 8.4右侧的稀疏矩阵),因为单元格(7,3)被视为空。但是,位置 7 间接关注位置 3 通过标记位置 5,即(7->5, 5->3 => 7->3)。该图还说明了,虽然全自注意会产生 n2 个活动单元格(顶点),但稀疏模型大致为5×n

另一个重要类型是全局注意力。少量选定的标记或少量注入的标记被用作全局注意力,可以关注所有其他位置,并被它们关注。因此,任意两个标记位置之间的最大路径距离等于 2。假设我们有一个句子*[GLB, the, cat, is, very, sad],其中GlobalGLB)是一个注入的全局标记,窗口大小为 2,这意味着一个标记只能关注其直接的左右标记以及 GLB。 catsad 之间没有直接交互。但我们可以遵循 cat-> GLB, GLB-> sad 交互,这通过 GLB 标记创建了一个超链接。全局标记可以从现有标记中选择或像(CLS)*那样添加。如下截图所示,前两个标记位置被选为全局标记:

图 8.5 – 全局注意力

顺便说一句,这些全局标记也不必在句子开头。例如,longformer 模型除了前两个标记外,还会随机选择全局标记。

有四种更常见的模式。随机注意力Figure 8.6中的第一个矩阵)用于通过从现有标记中随机选择来促进信息流动。但大多数情况下,我们将随机注意力作为组合模式(左下角矩阵)的一部分,该模式由其他模型的组合组成。扩张注意力类似于滑动窗口,但在窗口中加入了一些间隙,如Figure 8.6右上方所示:

图 8.6 – 随机、扩张、组合和分块

分块模式Figure 8.6右下角)为其他模式提供了基础。它将标记分块成固定数量的块,这对于长文本问题特别有用。例如,当使用块大小为 512 来分块 4096x4096 的注意力矩阵时,就形成了 8 个(512x512)查询块和键块。许多高效的模型,如 BigBird 和 Reformer,大多数将标记分块以减少复杂性。

需要注意的是,提出的模式必须得到加速器和库的支持。一些注意力模式,如扩张模式,需要特殊的矩阵乘法,在撰写本章时,当前的深度学习库,如 PyTorch 或 TensorFlow,不直接支持。

我们已经准备好进行一些高效 transformer 的实验。我们将使用 Transformers 库支持的模型,并具有 HuggingFace 平台上的检查点。Longformer是使用稀疏注意力的模型之一。它使用滑动窗口和全局注意力的组合。它还支持扩张的滑动窗口注意力:

  1. 在开始之前,我们需要安装py3nvml包进行基准测试。请记住,我们已经讨论过如何在第二章对主题的实际介绍中应用基准测试:
!pip install py3nvml
  1. 我们还需要检查我们的设备,以确保没有正在运行的进程:
!nvidia-smi
  1. 输出如下:

    图 8.7 – GPU 使用情况
  2. 目前,Longformer 的作者分享了一些检查点。以下代码片段加载了 Longformer 检查点allenai/longformer-base-4096并处理了一个长文本:
from transformers import LongformerTokenizer, LongformerForSequenceClassification
import torch
tokenizer = LongformerTokenizer.from_pretrained(
    'allenai/longformer-base-4096')
model=LongformerForSequenceClassification.from_pretrained(
    'allenai/longformer-base-4096')
sequence= "hello "*4093
inputs = tokenizer(sequence, return_tensors="pt")
print("input shape: ",inputs.input_ids.shape)
outputs = model(**inputs)
  1. 输出如下:
input shape:  torch.Size([1, 4096])
  1. 如图所示,Longformer 可以处理长度达4096的序列。当我们传递长度超过4096的序列时,这是限制时,您将收到错误IndexError: index out of range in self

Longformer 的默认attention_window512,这是每个标记周围的关注窗口的大小。通过以下代码,我们实例化了两个 Longformer 配置对象,第一个是默认 Longformer,第二个是一个更轻量级的 Longformer,我们将窗口大小设置为较小的值,例如 4,这样模型就变得更轻:

  1. 请注意以下示例。我们将始终调用XformerConfig.from_pretrained()。这个调用不会下载模型检查点的实际权重,而是仅从 HuggingFace Hub 下载配置。在本节中,由于我们不会进行微调,我们只需要配置:
from transformers import LongformerConfig, \
PyTorchBenchmark, PyTorchBenchmarkArguments
config_longformer=LongformerConfig.from_pretrained(
    "allenai/longformer-base-4096")
config_longformer_window4=LongformerConfig.from_pretrained(
    "allenai/longformer-base-4096", 
     attention_window=4)
  1. 有了这些配置实例,您可以将配置对象传递给 Longformer 模型,使用自己的数据集训练您的 Longformer 语言模型,如下所示:
from transformers import LongformerModel
model = LongformerModel(config_longformer)
  1. 除了训练 Longformer 模型,您还可以将训练过的检查点微调到下游任务。要这样做,您可以继续应用第三章中所示的代码进行语言模型训练,以及第 05-06 章进行微调。
  2. 现在我们将利用PyTorchBenchmark比较这两种配置在各种输入长度[128, 256, 512, 1024, 2048, 4096]下的时间和内存性能,如下所示:
sequence_lengths=[128,256,512,1024,2048,4096]
models=["config_longformer","config_longformer_window4"]
configs=[eval(m) for m in models]
benchmark_args = PyTorchBenchmarkArguments(
    sequence_lengths= sequence_lengths, 
    batch_sizes=[1], 
    models= models)
benchmark = PyTorchBenchmark(
    configs=configs, 
    args=benchmark_args)
results = benchmark.run()
  1. 输出如下:

图 8.8 – 基准结果

一些关于PyTorchBenchmarkArguments的提示:如果你想看到训练和推断的性能,你应该将参数training设置为True(默认为False)。你可能还想看到您当前的环境信息。您可以通过设置no_env_printFalse来做到这一点;默认为True

让我们通过可视化性能来使其更易解释。为此,我们定义了一个plotMe()函数,因为我们将来在进一步的实验中也将需要该函数。该函数默认情况下绘制推断性能,以及正确限制的运行时间复杂性或内存占用:

  1. 这里是函数定义:
import matplotlib.pyplot as plt 
def plotMe(results,title="Time"):
    plt.figure(figsize=(8,8))
    fmts= ["rs--","go--","b+-","c-o"]
    q=results.memory_inference_result
    if title=="Time": 
        q=results.time_inference_result
    models=list(q.keys())
    seq=list(q[models[0]]['result'][1].keys())
    models_perf=[list(q[m]['result'][1].values()) \
        for m in models] 
    plt.xlabel('Sequence Length') 
    plt.ylabel(title) 
    plt.title('Inference Result') 
    for perf,fmt in zip(models_perf,fmts):
        plt.plot(seq, perf,fmt)
    plt.legend(models) 
    plt.show()
  1. 让我们看看两个 Longformer 配置的计算性能,如下所示:
plotMe(results)
  1. 这绘制了以下图表:

    图 8.9 – 随序列长度的速度性能(Longformer)
    在这个和后面的例子中,我们看到重型模型和轻型模型之间的主要差异是从长度 512 开始。前图显示了长子模型(窗口长度为 4)在时间复杂度方面如预期的表现更好。我们还看到两个 Longformer 模型用线性时间复杂度处理输入。
  2. 让我们从内存性能的角度评估这两个模型:
plotMe(results, "Memory")
  1. 这绘制了以下内容:

    图 8.10 – 随序列长度的内存性能(Longformer)
    再次强调,直到长度 512,没有实质性的差异。从长度 512 开始,我们看到与时间性能类似的内存性能。显然,Longformer 自注意力的内存复杂性是线性的。另一方面,我要提醒你的是,我们尚未对模型任务性能做出任何评论。
    非常感谢PyTorchBenchmark脚本,我们已经交叉检验了这些模型。当我们选择应该用哪种配置来训练语言模型时,这个脚本非常有用。这在开始真正的语言模型训练和微调之前将是至关重要的。
    另一个利用稀疏注意力的表现最佳模型是 BigBird(Zohen 等,2020)。作者声称他们的稀疏注意力机制(他们将其称为广义注意力机制)在线性时间内保留了香草Transformers的全自注意机制的所有功能。作者将注意力矩阵视为有向图,因此他们利用了图论算法。他们从图稀疏化算法中汲取灵感,该算法用较少的边或顶点逼近给定图G的图G'
    BigBird 是一个分块注意力模型,可以处理长度达 4096 的序列。它首先通过打包查询和密钥一起将注意力模式分块化,然后对这些块定义注意力。他们利用了随机、滑动窗口和全局注意力。
  2. 让我们加载并使用与 Longformer Transformers模型相似的 BigBird 模型检查点配置。HuggingFace Hub 的开发人员共享了几个 BigBird 检查点。我们选择了原始的 BigBird 模型,google/bigbird-roberta-base,它从一个 RoBERTa 检查点开始预热。再次强调,我们不是下载模型检查点权重,而是下载配置。BigBirdConfig实现允许我们比较完全自注意和稀疏注意。因此,我们可以观察和检查稀疏化是否将完全注意的 O(n²)复杂性降低到更低的水平。再次强调,最多达到 512 的长度,我们并没有清楚地观察到二次复杂性。我们可以从这个级别开始观察复杂性。将注意类型设置为原始全功能将为我们提供完全自注意模型。为了比较,我们创建了两种类型的配置:第一个是 BigBird 的原始稀疏方法,第二个是使用完全自注意模型的模型。
  3. 我们依次称它们为sparseBirdfullBird
from transformers import BigBirdConfig
# Default Bird with num_random_blocks=3, block_size=64
sparseBird = BigBirdConfig.from_pretrained(
    "google/bigbird-roberta-base")
fullBird = BigBirdConfig.from_pretrained(
    "google/bigbird-roberta-base", 
    attention_type="original_full")
  1. 请注意,对于最多 512 个序列长度,由于块大小和序列长度不一致,BigBird 模型将作为完全自注意模式运行:
sequence_lengths=[256,512,1024,2048, 3072, 4096]
models=["sparseBird","fullBird"]
configs=[eval(m) for m in models]
benchmark_args = PyTorchBenchmarkArguments(
    sequence_lengths=sequence_lengths,
    batch_sizes=[1],
    models=models)
benchmark = PyTorchBenchmark(
    configs=configs, 
    args=benchmark_args)
results = benchmark.run()
  1. 输出如下:

    图 8.11 – 基准结果(BigBird)
  2. 再次,我们将时间性能绘制如下:
plotMe(results)
  1. 这绘制了以下内容:

    图 8.12 – 速度性能(BigBird)
    在一定程度上,完全自注意模型的性能优于稀疏模型。然而,我们可以观察到fullBird的二次时间复杂性。因此,在一定程度上,当接近尾声时,我们也看到稀疏注意模型突然超越它。
  2. 让我们按如下方式检查内存复杂性:
plotMe(results,"Memory")
  1. 这是输出:

图 8.13 – 内存性能(BigBird)

在上图中,我们可以清楚地看到线性和二次内存复杂性。再次强调,在某一点(本例中长度为 2,000),我们无法说出清晰的区别。

接下来,让我们讨论可学习模式,并使用可以处理更长输入的模型。

可学习模式

基于学习的模式是固定(预定义)模式的替代方案。这些方法以无监督数据驱动的方式提取模式。它们利用一些技术来衡量查询和键之间的相似性,以正确地对它们进行聚类。这个Transformers家族首先学习如何对令牌进行聚类,然后限制交互以获得注意矩阵的最佳视图。

现在,我们将对 Reformer 进行一些实验,作为基于可学习模式的重要高效模型之一。在此之前,让我们先了解 Reformer 模型对 NLP 领域的贡献,如下所示:

  1. 它采用了[a,b,c][d,e,f],标记d无法参与到其直接上下文c中。为了解决这个问题,Reformer 会用参数增加每个块的前面相邻块的数量。
  2. Reformer 最重要的贡献是利用局部敏感哈希LSH)函数,它将相似的查询向量分配相同的值。通过仅比较最相似的向量来近似注意力,可以帮助我们减少维度,然后将矩阵稀疏化。这是一个安全的操作,因为 softmax 函数受大值的影响很大,可以忽略不相似的向量。此外,与其查找给定查询的相关键,只查找相似的查询并进行桶分配。也就是说,查询的位置只能参与到其他具有高余弦相似度的查询的位置。
  3. 为了减少内存占用,Reformer 使用可逆残差层,避免了需要存储所有层的激活以便后续反向传播的需要,遵循可逆残差网络RevNet)的方式,因为任意层的激活都可以从后续层的激活中恢复。
    需要注意的是,Reformer 模型和许多其他高效的 transformer 在实践中被批评为,只有当输入长度非常长时才比普通 transformer 更高效(REF:Efficient Transformers:A Survey,Yi Tay,Mostafa Dehghani,Dara Bahri,Donald Metzler)。我们在早期的实验中也有类似的观察(请参见 BigBird 和 Longformer 实验)。
  4. 现在我们将对 Reformer 进行一些实验。再次感谢 HuggingFace 社区,Transformers 库为我们提供了 Reformer 的实现及其预训练检查点。我们将加载原始检查点google/reformer-enwik8的配置,并调整一些设置以使其在完全自注意模式下工作。当我们将lsh_attn_chunk_lengthlocal_attn_chunk_length设置为16384时,这是 Reformer 可以处理的最大长度,Reformer 实例将没有进行局部优化的机会,而是自动以完全注意力的方式工作,我们称之为fullReformer。至于原始的 Reformer,我们使用来自原始检查点的默认参数实例化它,并称之为sparseReformer如下:
from transformers import ReformerConfig
fullReformer = ReformerConfig\
    .from_pretrained("google/reformer-enwik8",  
        lsh_attn_chunk_length=16384, 
        local_attn_chunk_length=16384)
sparseReformer = ReformerConfig\
    .from_pretrained("google/reformer-enwik8")
sequence_lengths=[256, 512, 1024, 2048, 4096, 8192, 12000]
models=["fullReformer","sparseReformer"]
configs=[eval(e) for e in models]
  1. 请注意,Reformer 模型可以处理长度最长为16384的序列。但是对于完全自注意模式,由于我们环境的加速器容量限制,注意力矩阵无法适应 GPU,并且我们会收到 CUDA 内存不足的警告。因此,我们将最大长度设置为12000。如果您的环境适合,您可以增加它。
  2. 让我们进行基准实验如下:
benchmark_args = PyTorchBenchmarkArguments(
    sequence_lengths=sequence_lengths,
    batch_sizes=[1],
    models=models)
benchmark = PyTorchBenchmark(
    configs=configs, 
    args=benchmark_args)
result = benchmark.run()
  1. 输出如下:

    图 8.14 – 基准结果
  2. 让我们将时间性能结果可视化如下:
plotMe(result)
  1. 输出如下:

    图 8.15 – 速度性能(Reformer)
  2. 我们可以看到模型的线性和二次复杂度。通过运行以下行,我们可以观察到内存占用的类似特征:
plotMe(result,"Memory Footprint")
  1. 它绘制了以下内容:

图 8.16 – 内存使用(Reformer)

正如预期的那样,具有稀疏注意力的 Reformer 产生了一个轻量级模型。然而,正如之前所说的,我们在某个长度上难以观察到二次/线性复杂度。正如所有这些实验所指示的,高效Transformers可以减轻长文本的时间和内存复杂度。那么任务性能呢?它们在分类或摘要任务中的准确性如何?为了回答这个问题,我们将开始一个实验或查看相关模型的性能报告中的性能。对于实验,您可以通过实例化一个高效模型而不是一个普通的Transformers来重复chapter 04chapter 05中的代码。您可以使用我们将在Chapter 11中详细讨论的模型跟踪工具来跟踪模型性能并对其进行优化,注意可视化和实验跟踪

低秩分解、核方法和其他方法

高效模型的最新趋势是利用完整自注意力矩阵的低秩近似。这些模型被认为是最轻量级的,因为它们可以将自注意力的复杂度从O(n2)降低到O(n),无论是在计算时间还是内存占用上。选择一个非常小的投影维度k,使得k << n,那么内存和空间复杂度会大大降低。Linformer 和 Synthesizer 是能够通过低秩分解高效近似完整注意力的模型。它们通过线性投影来分解原始Transformers的点积* N×N* 注意力。

核关注是另一种最近我们看到的方法家族,通过核化来改善效率。核是一个将两个向量作为参数并返回它们的投影与特征映射的乘积的函数。它使我们能够在高维特征空间中操作,甚至不需要计算数据在该高维空间中的坐标,因为在该空间内的计算变得更加昂贵。这就是核技巧发挥作用的时候。基于核化的高效模型使我们能够重写自注意力机制,以避免显式计算N×N矩阵。在机器学习中,我们最常听到的有关核方法的算法是支持向量机,其中径向基函数核或多项式核被广泛使用,特别是用于非线性。对于Transformers,最引人注目的例子是Performer线性Transformers

摘要

本章的重要性在于我们学会了如何在有限的计算能力下减轻运行大型模型的负担。我们首先讨论并实施了如何使用蒸馏、剪枝和量化使训练模型变得高效的方法。预训练一个较小的通用语言模型,比如 DistilBERT,是很重要的。这样的轻量化模型可以与非蒸馏的模型相比,在各种问题上都能够取得良好的性能。

其次,我们了解了如何使用近似技术,例如 Linformer、BigBird、Performer 等,将完整的自注意力矩阵替换为稀疏矩阵的高效稀疏 Transformer。我们已经看到它们在各种基准测试中的性能表现,如计算复杂度和内存复杂度。这些例子向我们展示了这些方法能够将二次复杂度降低到线性复杂度,而不损害性能。

在下一章中,我们将讨论其他重要主题:跨语言/多语言模型。

参考文献

  • Sanh, V., Debut, L., Chaumond, J., & Wolf, T. (2019). DistilBERT,BERT 的精简版:更小、更快、更便宜、更轻量化. arXiv 预印本 arXiv:1910.01108。
  • Choromanski, K., Likhosherstov, V., Dohan, D., Song, X., Gane, A., Sarlos, T., & Weller, A. (2020). 重新思考注意力机制:表演者方法. arXiv 预印本 arXiv:2009.14794。
  • Wang, S., Li, B., Khabsa, M., Fang, H., & Ma, H. (2020). Linformer:具有线性复杂性的自注意力机制. arXiv 预印本 arXiv:2006.04768。
  • Zaheer, M., Guruganesh, G., Dubey, A., Ainslie, J., Alberti, C., Ontanon, S., … & Ahmed, A. (2020). 大鸟:针对更长序列的 Transformer. arXiv 预印本 arXiv:2007.14062。
  • Tay, Y., Dehghani, M., Bahri, D., & Metzler, D. (2020). 高效 Transformer:一项调查. arXiv 预印本 arXiv:2009.06732。
  • Tay, Y., Bahri, D., Metzler, D., Juan, D. C., Zhao, Z., & Zheng, C. (2020). 合成器:重新思考 Transformer 模型中的自注意力机制. arXiv 预印本 arXiv:2005.00743。
  • Kitaev, N., Kaiser, Ł., & Levskaya, A. (2020). Reformer:高效 Transformer. arXiv 预印本 arXiv:2001.04451。
  • Fournier, Q., Caron, G. M., & Aloise, D. (2021). 关于更快、更轻量化 Transformer 的实用调查. arXiv 预印本 arXiv:2103.14636。

第九章:跨语言和多语言语言建模

到目前为止,你已经学习了很多关于基于 transformer 的架构的知识,从仅编码器模型到仅解码器模型,从高效的 transformers 到长上下文的 transformers。你还学习了基于 Siamese 网络的语义文本表示。然而,我们讨论了所有这些模型都是从单语问题的角度出发的。我们假设这些模型只是理解单一语言,并且无法对文本进行通用的理解,无论语言本身如何。事实上,其中一些模型具有多语言变体;多语言双向编码器表示模型mBERT),多语言文本到文本转换 transformermT5),以及多语言双向和自回归 transformermBART),仅举几例。另一方面,一些模型专门设计用于多语言目的,采用跨语言目标进行训练。例如,跨语言语言模型XLM)就是这样一种方法,本章将详细介绍。

在本章中,将介绍语言之间的知识共享概念,以及Byte-Pair 编码BPE)对分词部分的影响,也是另一个重要的主题,为了实现更好的输入。将详细说明使用跨语言自然语言推理XNLI)语料库进行跨语言句子相似性的任务。将通过实际的现实问题的具体例子,如多语言意图分类等自然语言处理NLP)中的跨语言分类和跨语言句子表示利用另一种语言进行训练和测试的任务。

简而言之,你将在本章学习以下主题:

  • 翻译语言建模和跨语言知识共享
  • XLM 和 mBERT
  • 跨语言相似性任务
  • 跨语言分类
  • 跨语言零-shot 学习
  • 多语言模型的基本局限性

技术要求

本章的代码在该书的 GitHub 仓库中的github.com/PacktPublishing/Mastering-Transformers/tree/main/CH09下找到。我们将使用 Jupyter Notebook 来运行我们的编码练习,需要 Python 3.6.0+,并且需要安装以下软件包:

  • tensorflow
  • pytorch
  • transformers >=4.00
  • datasets
  • sentence-transformers
  • umap-learn
  • openpyxl

查看以下链接,观看《代码实战》视频:

bit.ly/3zASz7M

翻译语言建模和跨语言知识共享

迄今为止,你已经了解了遮罩语言建模MLM)作为填空任务。然而,基于神经网络的语言建模根据方法本身和其实际用途分为三类,如下所示:

  • MLM
  • 因果语言建模CLM
  • 翻译语言建模TLM

也很重要的是,还有其他预训练方法,例如下一句预测NSP)和句子顺序预测SOP),但我们只考虑了基于令牌的语言建模。这三种方法是文献中使用的主要方法。如前几章中描述和详细介绍的MLM,与语言学习中的填空任务非常接近。

CLM的定义是预测下一个令牌,后面跟着一些前面的令牌。例如,如果你看到以下上下文,你可以轻松预测下一个令牌:

Transformers改变了自然语言…

正如你所看到的,只有最后一个令牌被屏蔽,前面的令牌都给了模型,让它预测最后一个。这个令牌将会是processing,如果再次给你这个令牌的上下文,你可能会以一个*“”*令牌结束。为了在这种方法上进行良好的训练,需要不屏蔽第一个令牌,因为模型只有一个句子的开始令牌来组成一个句子。这个句子可以是任何东西!下面是一个例子:

你会预测出什么?可以是任何东西。为了更好的训练和更好的结果,需要至少给出第一个令牌,如下所示:

Transformers…

而模型需要预测变化;在给出Transformers改变…后,需要预测the,依此类推。这种方法非常类似于 N-grams 和P(wn|wn-1, wn-2 ,…,w0),其中wn是要预测的令牌,而其余令牌是它前面的令牌。具有最大概率的令牌是预测的令牌。

这些是用于单语模型的目标。那么,对于跨语言模型可以做些什么?答案是TLM,它与 MLM 非常相似,但有一些变化。不是给定一个单一语言的句子,而是给模型一个包含不同语言的句子对,用一个特殊的令牌分隔开。模型需要预测这些语言中任意一个中的随机屏蔽的令牌。

下面的句子对就是这样一个任务的例子:

图 9.1 - 土耳其和英语之间的跨语言关系示例

给定这两个屏蔽的句子,模型需要预测缺失的令牌。在这个任务中,有些场合下,模型可以访问到其中一个语言中缺失的令牌(例如,在图 9.1中的句子对中分别为doğallanguage)。

另一个例子,你可以看到波斯语和土耳其语句子的同一对。在第二个句子中,değiştirdiler 标记可以被第一个句子中的多个标记(一个被掩码)关注到。在下面的例子中,单词 تغییر 缺失,但 değiştirdiler 的含义是 تغییر دادند**。**

图 9.2 – 波斯语和土耳其语之间的跨语言关系示例

因此,一个模型可以学习这些含义之间的映射。就像一个翻译模型一样,我们的 TLM 也必须学习这些语言之间的复杂性,因为机器翻译MT)不仅仅是一个标记到标记的映射。

XLM 和 mBERT

在本节中我们选择了两个模型进行解释:mBERT 和 XLM。我们选择这些模型是因为它们对应于写作本文时最好的两种多语言类型。mBERT 是一个在不同语言语料库上使用 MLM 建模训练的多语言模型。它可以单独为许多语言进行操作。另一方面,XLM 是使用 MLM、CLM 和 TLM 语言建模在不同语料库上训练的,可以解决跨语言任务。例如,它可以通过将它们映射到共同的向量空间来测量两种不同语言句子的相似度,而这在 mBERT 中是不可能的。

mBERT

你对来自第三章的 BERT 自动编码器模型以及如何在指定语料库上使用 MLM 进行训练已经很熟悉了。想象一下提供了一个广泛且庞大的语料库,不是来自单一语言,而是来自 104 种语言。在这样的语料库上进行训练将会产生一个多语言版本的 BERT。然而,在如此广泛的语言上进行训练将会增加模型的大小,在 BERT 的情况下是不可避免的。词汇量会增加,因此嵌入层的大小会因为更多的词汇而变大。

与单语言预训练的 BERT 相比,这个新版本能够在一个模型内处理多种语言。然而,这种建模的缺点是,该模型不能在语言之间进行映射。这意味着在预训练阶段,模型并未学习到关于不同语言的这些标记的语义含义之间的映射。为了为这个模型提供跨语言映射和理解,有必要在一些跨语言监督任务上对其进行训练,比如XNLI数据集中提供的任务。

使用这个模型与你在之前章节中使用的模型一样简单(更多详情请参见 huggingface.co/bert-base-multilingual-uncased)。以下是你需要开始的代码:

from transformers import pipeline
unmasker = pipeline('fill-mask', model='bert-base- 
                    multilingual-uncased')
sentences = [
"Transformers changed the [MASK] language processing",
"Transformerlar [MASK] dil işlemeyi değiştirdiler",
"ترنسفرمرها پردازش زبان [MASK] را تغییر دادند"
]
for sentence in sentences:
    print(sentence)
    print(unmasker(sentence)[0]["sequence"])
    print("="*50)

输出结果将如下代码片段所示呈现:

Transformers changed the [MASK] language processing
transformers changed the english language processing
==================================================
Transformerlar [MASK] dil işlemeyi değiştirdiler
transformerlar bu dil islemeyi degistirdiler
==================================================
ترنسفرمرها پردازش زبان [MASK] را تغییر دادند
ترنسفرمرها پردازش زبانی را تغییر دادند
==================================================

正如你所见,它可以为各种语言执行 fill-mask

XLM

语言模型的跨语言预训练,例如 XLM 方法所示,基于三种不同的预训练目标。MLM、CLM 和 TLM 被用来预训练 XLM 模型。这种预训练的顺序是使用所有语言之间共享的 BPE 分词器执行的。共享标记的原因在于,在具有相似标记或子词的语言情况下,共享标记提供了较少的标记,而另一方面,这些标记可以在预训练过程中提供共享的语义。例如,一些标记在许多语言中的书写和含义非常相似,因此这些标记对所有语言都使用 BPE 进行共享。另一方面,一些在不同语言中拼写相同的标记可能具有不同的含义——例如,在德语和英语环境中 was 是共享的。幸运的是,自注意力机制帮助我们使用周围的上下文消除 was 的含义歧义。

这种跨语言建模的另一个主要改进是它还在 CLM 上进行了预训练,这使得它在需要句子预测或完成时更加合理。换句话说,这个模型对语言有一定的理解,能够完成句子、预测缺失的标记,并利用其他语言源预测缺失的标记。

下图显示了跨语言建模的整体结构。你可以在 arxiv.org/pdf/1901.07291.pdf 上阅读更多内容。

图 9.3 – MLM 和 TLM 跨语言建模的预训练

XLM 模型的更新版本也被发布为XLM-R,其在训练和使用的语料库中有轻微的更改。XLM-R 与 XLM 模型相同,但在更多的语言和更大的语料库上进行了训练。CommonCrawl 和 Wikipedia 语料库被聚合,XLM-R 在其中进行 MLM 的训练。然而,XNLI 数据集也用于 TLM。下图显示了 XLM-R 预训练使用的数据量:

图 9.4 – 数据量(GB)(对数刻度)

在添加新语言进行训练数据时,有许多优点和缺点——例如,添加新语言并不总是会提高自然语言推理NLI)的整体模型。XNLI 数据集通常用于多语言和跨语言 NLI。从前面的章节中,您已经看到了多样化体裁 NLIMNLI)数据集用于英语;XNLI 数据集与之几乎相同,但具有更多的语言,而且还有句子对。然而,仅在此任务上进行训练是不够的,它不会涵盖 TLM 预训练。对于 TLM 预训练,会使用更广泛的数据集,例如OPUS开源平行语料库的缩写)的平行语料库。该数据集包含来自不同语言的字幕,经过对齐和清理,由许多软件来源提供的翻译,如 Ubuntu 等。

以下截图显示了 OPUS (opus.nlpl.eu/trac/) 及其用于搜索和获取数据集信息的组件:


图 9.5 – OPUS

描述使用跨语言模型的步骤如下:

  1. 对先前的代码进行简单更改,您就可以看到 XLM-R 如何执行掩码填充。首先,您必须更改模型,如下所示:
unmasker = pipeline('fill-mask', model='xlm-roberta-base')
  1. 之后,您需要将掩码标记从[MASK]更改为,这是 XLM-R 的特殊标记(或简称为tokenizer.mask_token)。以下是完成此操作的代码:
sentences = [
"Transformers changed the <mask> language processing",
"Transformerlar <mask> dil işlemeyi değiştirdiler",
"ترنسفرمرها پردازش زبان <mask" را تغییر دادند
]
  1. 然后,您可以运行相同的代码,如下所示:
for sentence in sentences:
  print(sentence)
  print(unmasker(sentence)[0]["sequence"])
  print("="*50)
  1. 结果将如此显示:
Transformers changed the <mask> language processing
Transformers changed the human language processing
==================================================
Transformerlar <mask> dil işlemeyi değiştirdiler
Transformerlar, dil işlemeyi değiştirdiler
================================================== ترنسفرمرها پردازش زبان [MASK] را تغییر دادند
 ترنسفرمرها پردازش زبانی را تغییر دادند
==================================================
  1. 但从土耳其语和波斯语的例子中可以看出,模型仍然犯了错误;例如,在波斯文本中,它只是添加了ی,在土耳其版本中,它添加了,。对于英文句子,它添加了human,这不是我们所期望的。这些句子并没有错,但不是我们所期望的。然而,这一次,我们有一个使用 TLM 训练的跨语言模型;所以,让我们通过连接两个句子并给模型一些额外的提示来使用它。我们开始吧:
print(unmasker("Transformers changed the natural language processing. </s> Transformerlar <mask> dil işlemeyi değiştirdiler.")[0]["sequence"])
  1. 结果将如下所示:
Transformers changed the natural language processing. Transformerlar doğal dil işlemeyi değiştirdiler.
  1. 就这样!模型现在已经做出了正确的选择。让我们再玩一会儿,看看它的表现如何,如下所示:
print(unmasker("Earth is a great place to live in. </s> زمین جای خوبی برای <mask> کردن است.")[0]["sequence"])
  1. 这是结果:
Earth is a great place to live in. زمین جای خوبی برای زندگی کردن است.

干得好!到目前为止,您已经了解了诸如 mBERT 和 XLM 等多语言和跨语言模型。在下一节中,您将学习如何使用这些模型进行多语言文本相似性。您还将看到一些用例,例如多语言抄袭检测。

精通 Transformers(三)(4)https://developer.aliyun.com/article/1510708

相关文章
|
7月前
|
机器学习/深度学习 自然语言处理 PyTorch
精通 Transformers(一)(2)
精通 Transformers(一)
196 4
|
7月前
|
API TensorFlow 算法框架/工具
精通 Transformers(四)(1)
精通 Transformers(四)
72 0
精通 Transformers(四)(1)
|
7月前
|
自然语言处理 数据可视化 NoSQL
精通 Transformers(四)(3)
精通 Transformers(四)
94 0
|
7月前
|
编解码 自然语言处理 数据可视化
精通 Transformers(四)(4)
精通 Transformers(四)
186 0
|
7月前
|
机器学习/深度学习 数据可视化 API
精通 Transformers(四)(2)
精通 Transformers(四)
80 0
|
5月前
|
编解码 缓存 算法
Transformers 4.37 中文文档(一百)(2)
Transformers 4.37 中文文档(一百)
49 1
|
5月前
|
存储 自然语言处理 PyTorch
Transformers 4.37 中文文档(八十三)(1)
Transformers 4.37 中文文档(八十三)
45 3
|
5月前
|
存储 自然语言处理 测试技术
Transformers 4.37 中文文档(八)(4)
Transformers 4.37 中文文档(八)
93 2
|
5月前
|
存储 PyTorch TensorFlow
Transformers 4.37 中文文档(二)(1)
Transformers 4.37 中文文档(二)
97 1
|
5月前
|
存储 自然语言处理 PyTorch
Transformers 4.37 中文文档(九十八)(4)
Transformers 4.37 中文文档(九十八)
35 0