萱仔大模型学习记录2.1-BERT算法论文和实践

第二章的内容承接上一章的内容,主要对nlp的模型bert论文进行学习和分析,虽然以前的项目中已经使用过bert进行新闻文本分类,但我个人认为我自己还是对理论和论文分析的不够到尾,需要对论文的理论进行仔细的学习,这样才能应对未来的魔改操作。这里我学习bert算法以及对应的transform结构

1.bert原论文——

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

论文网址:
https://arxiv.org/pdf/1810.04805

代码网址: https://github.com/google\-research/bert(论文内代码网址)

2.transform原论文——

Attention Is All You Need

论文网址:
https://arxiv.org/pdf/1706.03762

代码网址:

---------------------------------------------------------------------------------------------------------------

BERT:

1.摘要

我们介绍了一种新的语言表示模型,名为BERT,全称是双向编码器表示的Transformer。与最近的语言表示模型(如Peters等人,2018;Radford等人,2018)不同,BERT被设计为从无标签文本中预训练深度双向表示,它通过在所有层中同时考虑左右上下文来实现这一点。因此,预训练后的BERT模型只需在其基础上添加一个额外的输出层,就可以针对各种任务(如问答和语言推理)创建最先进的模型,而无需进行大幅度的任务特定架构修改。

BERT在概念上简单但在实验中却非常强大。它在十一项自然语言处理任务上获得了新的最先进结果,包括将GLUE基准得分提高到80.5%(绝对提升7.7个百分点)、MultiNLI准确率提高到86.7%(绝对提升4.6个百分点)、SQuAD v1.1问答测试的F1得分提高到93.2(绝对提升1.5个百分点)以及SQuAD v2.0测试的F1得分提高到83.1(绝对提升5.1个百分点)。

2.引言

在本文中,我们通过提出BERT(双向编码器表示的Transformer)改进了基于微调的方法。BERT通过使用“掩码语言模型”(MLM)预训练目标缓解了之前提到的单向性约束,这个目标受到了Cloze任务(Taylor,1953)的启发。掩码语言模型随机掩盖输入中的一些词,目标是仅基于其上下文预测被掩盖词的原始词汇ID。与从左到右的语言模型预训练不同,MLM目标使表示能够融合左右上下文,这使我们能够预训练一个深度双向的Transformer。除了掩码语言模型外,我们还使用了“下一个句子预测”任务,该任务共同预训练文本对的表示。

与训练和微调都差不太多,除了输出层以外。相同的预训练模型参数用于初始化不同下游任务的模型。在微调期间,所有参数都将进行微调。[CLS]是在每个输入示例前添加的特殊符号,而[SEP]是特殊的分隔符(例如,分隔问题/答案)。

可以看出来,前面已经解释了重点的贡献,和两种预训练微调的方法

  • 预训练(Pre-training)

    • 输入数据
      :大量的未标记文本。
    • 架构
      :Transformer架构,使用注意力机制来处理文本序列。
    • 预训练
      • 掩码语言模型(Masked Language Model, MLM)
        :随机掩盖输入文本中的一些单词,模型的任务是根据上下文预测被掩盖的单词。
      • 下一句预测(Next Sentence Prediction, NSP)
        :训练的模型需要判断两个句子是否是连续的。
    • 输出
      :预训练好的模型参数。
  • 微调(Fine-tuning)

    • 输入数据
      :包含特定任务的标记数据(如问答数据、情感分析数据等)。
    • 架构
      :与预训练时相同的Transformer架构。
    • 微调过程
      • 初始化
        :使用预训练好的模型参数初始化模型。
      • 训练
        :在特定任务数据上进行训练,调整所有模型参数。
    • 输出
      :适应特定任务的模型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') #随便选一个已经与训练好的模型

dataset = load_dataset('glue', 'mrpc')
def preprocess_function(examples):
return tokenizer(examples['sentence1'], examples['sentence2'], truncation=True, padding='max_length', max_length=128)
encoded_dataset = dataset.map(preprocess_function, batched=True)
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')


training_args = TrainingArguments(
output_dir='./results',
evaluation_strategy="epoch",
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=3,
weight_decay=0.01,
)


trainer = Trainer(
model=model,
args=training_args,
train_dataset=encoded_dataset['train'],
eval_dataset=encoded_dataset['validation'],
)

trainer.train()

  • 导入transformers库中的BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments模块,以及datasets库。
  • 定义训练参数,包括输出目录、评估策略、每个设备的训练和评估批次大小、训练轮数和权重衰减。

BERT的模型架构是基于Vaswani等人(2017年)提出的原始实现和tensor2tensor库发布的多层双向Transformer编码器。bert几乎和原始版本相同,因此我们不再详细介绍模型架构的背景,建议读者参考Vaswani等人的论文和一些优秀的指南,比如“注释版Transformer”。

代码地址如下(论文中的):

https://github.com/tensorflow/tensor2tensor

其中层数用L表示,隐藏层大小用H表示,自注意力头的数量用A表示。论文里主要展示了两种模型大小的结果:BERTBASE(L=12, H=768, A=12,总参数=110M)和BERTLARGE(L=24, H=1024, A=16,总参数=340M)。选择BERTBASE是为了与OpenAI GPT在模型规模上进行对比。BERT Transformer使用的是双向自注意力,GPT Transformer使用的是单向自注意力,每个词元只能关注其左侧的上下文。

bert的输入表示方法,能清晰地表示单个句子和成对的句子(例如问题和答案)。在论文的研究中,“句子”可以是任意一段连续的文字,而不一定是一个完整的语言句子。“序列”指的是输入给BERT的词序列,可以是一个句子或两个句子连在一起。

论文里使用WordPiece嵌入方法,这种方法将单词拆分成更小的词片,使用一个包含30,000个词片的词汇表。每个序列的第一个词片是一个特殊的分类词片([CLS])。这个词片的最终隐藏状态用于分类任务中,作为整个序列的代表。两个句子被打包在一个序列中。我们用两种方式区分这两个句子:首先,用一个特殊的分隔词片([SEP])将它们分开;其次,为每个词片添加一个标识,表明它属于句子A还是句子B。如图1所示,我们将输入嵌入表示为E,特殊[CLS]词片的最终隐藏向量表示为C ∈ RH,i个输入词片的最终隐藏向量表示为Ti ∈ RH。

对于每个词片,它的输入表示通过将对应的词片、段和位置嵌入相加得到。这个过程的可视化见图2。

3.1 预训练 BERT(原文翻译)

引言

不同于Peters等人(2018a)和Radford等人(2018),我们不使用传统的从左到右或从右到左的语言模型来预训练BERT。相反,我们使用两种无监督任务来预训练BERT。本节详细描述了这两种任务。这一步如图1的左半部分所示。

任务1:遮蔽语言模型 (Masked LM)

直观上来看,一个深度的双向模型要比单向模型(无论是从左到右还是从右到左)或左右双向模型的浅层拼接更加强大。然而,标准的条件语言模型只能从左到右或从右到左进行训练,因为双向条件会导致每个词可以间接地“看到自己”,这样模型可以在多层上下文中轻松地预测目标词。

为了训练一个深度双向表示,我们简单地随机遮蔽输入词元中的一部分,然后预测那些被遮蔽的词元。我们将这个过程称为“遮蔽语言模型”(Masked LM, MLM),尽管在文献中它通常被称为Cloze任务(Taylor, 1953)。在这种情况下,与被遮蔽词元对应的最终隐藏向量会被输入到词汇表上的输出softmax中,就像标准的语言模型一样。在我们的所有实验中,我们随机遮蔽每个序列中15%的WordPiece词元。不同于降噪自编码器(Vincent等,2008),我们只预测被遮蔽的词而不是重建整个输入。

虽然这让我们获得了一个双向的预训练模型,但有一个缺点是,这在预训练和微调之间产生了不匹配,因为[MASK]词元在微调过程中不会出现。为了缓解这一问题,我们并不总是用实际的[MASK]词元替换“被遮蔽”的词。训练数据生成器随机选择15%的词元位置进行预测。如果选择了第i个词元,

我们会有80%的时间将其替换为[MASK]词元,10%的时间替换为一个随机词元,10%的时间保持第i个词元不变。然后,使用Ti来通过交叉熵损失预测原始词元。我们在附录C.2中比较了这种程序的变体。

这里个人理解意思是

  • 80%:用[MASK]词块替换单词:我是人——我是[MASK]
  • 10%:用随机词替换遮蔽词:我是人——我是狗
  • 10%:保持单词不变:我是人——我是人。#偏向于实际观察到的单词。

任务2:下一句预测 (Next Sentence Prediction, NSP)

许多重要的下游任务,如问答(QA)和自然语言推理(NLI),都基于理解两个句子之间的关系,而这种能力并不是直接通过语言建模捕捉到的。为了训练一个能够理解句子关系的模型,我们预训练了一个二元化的下一句预测任务,这个任务可以从任何单语语料库中轻松生成。具体来说,当为每个预训练样本选择句子A和B时,50%的时间B是实际紧随A之后的句子(标记为IsNext),50%的时间B是语料库中的一个随机句子(标记为NotNext)。如图1所示,我们使用C来进行下一句预测(NSP)。尽管这个任务很简单,但我们在第5.1节中展示了预训练这个任务对于QA和NLI任务是非常有益的。NSP任务与Jernite等人(2017)和Logeswaran与Lee(2018)使用的表示学习目标密切相关。然而,在之前的工作中,只有句子嵌入被转移到下游任务中,而在BERT中,所有参数都会被转移来初始化最终任务模型的参数。

很多重要的下游任务,例如问答(QA)和自然语言推理(NLI),都是基于对两个文本句子间关系的理解,而这种关系并非通过
语言建模
直接获得。为了训练一个理解句子关系的模型,我们预训练了一个
二值化下一句预测任务
,该任务可以从任何单语语料库中轻松生成。具体来说,选择句子A和B作为预训练样本:B有50%的可能是A的下一句,也有50%的可能是来自语料库的随机句子。例如:

  • 50%:

输入=[CLS]我是[MASK][SEP]我喜欢吃[MASK][SEP]

其中MASK是“人”,“苹果”,这种情况,标记为IsNext

  • 50%:

输入=[CLS]我是[MASK][SEP]白色的[MASK]出去玩##ing[SEP]

其中MASK是“人”,“小狗”,这种情况,标记为NotNext

预训练数据

预训练过程在很大程度上遵循了现有的语言模型预训练文献。我们使用BooksCorpus(800M词)和英文维基百科(2,500M词)作为预训练语料库。对于维基百科,我们只提取文本段落,忽略列表、表格和标题。使用文档级语料库而不是句子级语料库(如Billion Word Benchmark,Chelba等,2013)来提取长的连续序列是至关重要的。

3.2 微调

微调过程相对简单,因为Transformer中的自注意力机制允许BERT通过更换合适的输入和输出来处理多种下游任务,无论这些任务涉及单个文本还是文本对。对于涉及文本对的应用,一个常见的模式是先独立编码文本对,然后应用双向交叉注意力(例如Parikh等,2016;Seo等,2017)。而BERT则使用自注意力机制将这两个阶段统一起来,因为通过自注意力编码连接的文本对可以有效地在两个句子之间包含双向交叉注意力。

在微调BERT时,论文里将预训练好的模型应用到具体的任务上。BERT的自注意力机制让它能够处理多种任务,无论是单个文本还是文本对。对于文本对任务,传统的方法是先分别处理每个文本,再让它们相互注意;而BERT则直接将两个文本连接起来一起处理。

微调步骤

  1. 任务输入和输出
    :根据具体任务,将输入和输出插入到BERT中。例如,在问答任务中,我们的输入是问题和相关段落,输出是问题的答案;在文本分类任务中,输入是文本,输出是分类结果。
  2. 模型微调
    :微调所有模型参数,使其适应具体任务。这个过程相对简单且快速。

然后就是实验部分

4.实验

(略过实验部分)