BERT简介
BERT(Bidirectional Encoder Representations from Transformers)是由 Google 在 2018 年提出的一种预训练语言模型。BERT 在自然语言处理(NLP)领域取得了重大突破,因为它能够有效地捕捉文本的上下文信息,从而在各种 NLP 任务中表现出色。以下是 BERT 模型的详细讲解,包括其架构、训练方法、应用场景和使用方法。
1. BERT 的基本概念
1.1 双向性
传统的语言模型通常是单向的,即只能从前向后(前向模型)或从后向前(后向模型)捕捉上下文信息。而 BERT 是双向的,能够在同一时间捕捉到词语的前后上下文信息。这种双向性使得 BERT 能够更好地理解词语的多义性。
单向编码
单向编码指的是在编码过程中,模型只能利用到当前位置之前的文本信息(或只能利用到当前位置之后的文本信息,但这种情况较少见),而无法同时利用到当前位置前后的文本信息。这种编码方式使得模型在处理文本时具有一种“前瞻性”或“回顾性”,但缺乏全局的上下文理解能力。
GPT是一个典型的采用单向编码的预训练语言模型。GPT使用Transformer的解码器部分作为其主要结构,通过自回归的方式进行训练,即模型在生成下一个词时只能看到之前的词,无法看到之后的词。
双向编码
双向编码则允许模型在编码过程中同时利用到当前位置前后的文本信息,从而能够更全面地理解文本的上下文。这种编码方式使得模型在处理文本时具有更强的语义理解能力和更丰富的信息来源。
BERT是一个典型的采用双向编码的预训练语言模型。BERT通过掩码语言模型(MLM)的方式进行训练,即随机掩盖文本中的部分词汇,然后让模型预测这些被掩盖的词汇。
举个例子:考虑一个文本序列“今天天气很好,我们决定去公园散步。”
- 在单向编码中,每个词或标记的编码仅依赖于其之前的词或标记。因此,在编码“决定”这个词时,模型只会考虑“今天”、“天气”、“很好”和“我们”这些在它之前的词。
- 在双向编码中,每个词或标记的编码都会同时考虑其前后的词或标记。因此,在编码“决定”这个词时,模型会同时考虑“今天”、“天气”、“很好”以及之后的“去公园散步”等词,从而更全面地理解整个句子的语义。
1.2 Transformer 架构
BERT 基于 Transformer 架构,这是一种基于自注意力机制(self-attention mechanism)的神经网络模型。Transformer 架构最初由 Vaswani 等人在 2017 年的论文《Attention is All You Need》中提出,它摒弃了传统的 RNN 和 CNN,完全依赖于自注意力机制来处理序列数据。
2. BERT 的架构
从上图左侧,我们可以看到BERT包含三种模块:
- 最底层⻩⾊标记的Embedding模块。
- 中间层蓝⾊标记的Transformer模块。
- 最上层绿⾊标记的预微调模块。
上图右侧是Encoder block的内部模块图。图中蓝色模块被画成了两层,这表示BERT模型中堆叠了多个Transformer编码器块。每个编码器块都包含自注意力机制(Self-Attention Mechanism)和前馈神经网络(Feed-Forward Neural Network),以及层归一化(Layer Normalization)和残差连接(Residual Connections)。
2.1 输入表示(Embedding模块)
BERT 的输入(Embedding模块)表示由三个部分组成:
- Token Embeddings:每个词的词嵌入, 输入文本中的每个单词或字符转换为一个固定维度的向量。Base版为768维,Large版为1024维。
- Segment Embeddings:用于区分句子 A 和句子 B 的段落嵌入, 单词或字符在句子中的位置信息。BERT中的位置嵌入是可学习的,它会随着模型的训练而更新,非固定的三角函数
- Position Embeddings:用于表示词在句子中的位置的位置嵌入,用于区分同一输入序列中不同句子的来源。对于多句输入,BERT会为每个句子分配一个不同的段编号,来区分它们。Segment Embeddings的取值通常是0和1,如果输入包含两个句子,通常第一个句子的token会被赋予全0的向量,第二个句子的token会被赋予全1的向量。
下图是一个示例(Position Embeddings)。
输入表示的公式为:
Input Embedding = Token Embedding + Segment Embedding + Position Embedding
2.2 Transformer 编码器
BERT 使用多层 Transformer 编码器来处理输入。每一层编码器包含两个子层:
- 多头自注意力机制(Multi-Head Self-Attention):用于捕捉词语之间的依赖关系。
- 前馈神经网络(Feed-Forward Neural Network):用于对每个词的表示进行非线性变换。
- 每层编码器还包括残差连接(Residual Connections)和层归一化(Layer Normalization)。
3. BERT 的训练方法
3.1 预训练任务
BERT 通过两个预训练任务来学习语言表示:
- Masked Language Model (MLM):随机掩盖输入句子中的某些词,然后让模型预测这些被掩盖的词。这种方法强制模型理解词语的上下文信息。
- Next Sentence Prediction (NSP):给模型两个句子,让模型判断第二个句子是否是第一个句子的下一个句子。这个任务帮助模型理解句子之间的关系。
1、Masked Language Model (MLM)
Masked Language Model,即遮蔽语言模型,是BERT预训练的一个重要部分。在这一阶段,模型的任务是预测输入句子中被随机遮蔽(masked)掉的部分单词。
- 输入文本处理:首先,对于输入的句子,随机选择句子中15%的单词进行遮蔽。对于每个被选中的单词,有80%的概率直接用[MASK]标记替换,10%的概率用随机的一个单词替换(这有助于模型学习理解上下文的重要性,而不仅仅是依赖于[MASK]标记),剩下的10%则保持不变(这有助于模型在微调阶段更好地处理未遮蔽的单词)。
- 模型预测:模型的目标是根据上下文预测这些被遮蔽单词的原始值。这种机制促使BERT能够深入理解文本中的语义关系。
我们来看一个例子,假设有一句话:my dog is hairy
1)80%的时候是[MASK]。如,my dog is hairy——>my dog is [MASK]
2)10%的时候是随机的其他token。如,my dog is hairy——>my dog is apple
3)10%的时候是原来的token。如,my dog is hairy——>my dog is hairy
2、Next Sentence Prediction (NSP)
Next Sentence Prediction,即下一句预测,是BERT预训练的另一个重要部分,旨在提高模型对句子间关系的理解能力。
- 句子对生成:在预训练时,模型不仅接收单个句子作为输入,还接收句子对。这些句子对可能是连续的(即真实的下一句),也可能是随机组合的(即非连续的)。
- 模型预测:对于每个句子对,模型需要预测第二个句子是否是第一个句子的真实下一句。这是一个简单的二分类任务,输出是一个[0, 1]范围内的值,表示第二个句子是第一个句子真实下一句的概率。
注:在BERT的后续版本中,Next Sentence Prediction(NSP)任务被废弃了。因为研究人员发现这个任务对下游任务的性能提升有限,因此在BERT的一些后续变体中被弃用了。
3.2 微调
预训练完成后,BERT 模型可以通过微调(Fine-Tuning)应用于各种下游任务,如文本分类、命名实体识别、问答等。微调过程中,模型的权重会被更新以适应特定任务。
1、句对分类
- 任务描述:句对分类任务涉及两个句子的输入,并需要模型判断这两个句子之间的关系或情感倾向等。
- 应用场景:例如,自然语言推断(NLI)任务,需要判断一个句子是否可以从另一个句子推断出来;或者语义文本相似性(STS)任务,需要评估两个句子的语义相似度。
如下图所示,句对分类的处理过程为:
- 输入处理:将两个句子(句对)作为输入,在两个句子之间添加特殊的分隔符[SEP],并在开头添加开始符[CLS],在末尾添加结束符[EOS]。[CLS]标记的输出表示将被用作句对分类的输入特征。
- 模型微调:在预训练的BERT模型基础上,添加一个全连接层作为输出层,用于句对分类任务。
- 特征提取:利用BERT编码器提取的句对表示,结合注意力机制等技术,捕捉两个句子之间的关系和交互信息,用于句对分类。
举例说明:下面有两个句子,我们要判断句子2是否是句子1的合理后续,即句子间的逻辑关系,如蕴含、中立、矛盾等。在这个例子中,可以视为一个蕴含关系,因为好天气通常适合户外运动。
句子1: "今天的天气真好。"
句子2: "适合去户外运动。"
BERT处理:将两个句子用[SEP]分隔,并在开头添加[CLS]标记,然后输入到BERT模型中。模型输出[CLS]标记的表示,用于句对关系的分类。
[CLS] 今天的天气真好。 [SEP] 适合去户外运动。 [SEP]
模型输出标签:entailment(蕴含)
注:实际的模型输出是一个概率分布,如[0.85, 0.1, 0.05],分别对应蕴含、中立、矛盾的概率,这里为了简化只给出了最可能的标签。
2、单句分类
-
任务描述:单句分类任务是将单个句子作为输入,并输出该句子的类别或情感倾向。
-
应用场景:如情感分析(判断文本是正面、负面还是中性)、垃圾邮件检测(判断邮件是否为垃圾邮件)等。
如下图所示,单句分类的处理过程为: -
输入处理:将单个句子作为输入,添加开始符[CLS]。
-
模型微调:与句对分类类似,在预训练的BERT模型基础上添加一个全连接层作为输出层,用于单句分类任务。通过微调整个模型来优化分类性能。
-
特征提取:利用BERT编码器提取的单个句子表示,捕捉句子中的语义信息,用于单句分类。
举例说明:下面的句子,我们将句子分类为正面情感或负面情感。在这个例子中,句子表达的是正面情感。
句子: "这部电影非常精彩!"
BERT处理:将句子作为输入,添加[CLS]标记,然后输入到BERT模型中。模型输出一个或多个类别的概率分布,选择概率最高的类别作为分类结果。
[CLS] 这部电影非常精彩!
输出概率分布:[0.95, 0.05],其中第一个值对应正面情感的概率,第二个值对应负面情感的概率。
3、文本问答
-
任务描述:文本问答任务涉及一个问题和一段文本(如文章或段落),模型需要从文本中找出问题的答案。
-
应用场景:如机器阅读理解(MRC),自动问答系统(FAQ)等。
如下图所示,文本回答的处理过程为: -
输入处理:将问题和相关文档或段落作为输入,使用特殊的分隔符[SEP]将问题和文档分隔开。
-
答案抽取:BERT模型通过编码器部分提取问题和文档的表示,然后可以结合指针网络等机制来定位答案在文档中的位置。在某些情况下,可能需要在BERT模型的基础上添加额外的层(如两个指针层)来指示答案的起始和结束位置。
-
微调任务:针对问答任务进行微调,优化模型在定位答案位置方面的性能。
举例说明:下方的问题,我们从文档中找出问题的答案。在这个例子中,答案是"北京不是省份"。
问题: "北京是中国的哪个省份?"
文档: "北京是中国的首都,位于华北地区,不是省份。"
BERT处理:将问题和文档分别作为输入,然后输入到BERT模型中。模型输出包括两个指针,用于指示答案在文档中的位置。
问题:[CLS] 北京是中国的哪个省份? [SEP]
文档:[CLS] 北京是中国的首都,位于华北地区,不是省份。 [SEP]
模型输出:
起始索引:(在文档中的位置,假设从0开始) 23
结束索引:(同样,假设从0开始) 25
注:这里的索引只是示意性的,实际输出可能依赖于文档的预处理和编码方式。
4、单句标注
-
任务描述:单句标注任务是对句子中的每个词或子词进行标注,如命名实体识别(NER)、词性标注(POS Tagging)等。
-
应用场景:在信息抽取、文本分析等领域有广泛应用。
如下图所示,单句标注的处理过程为: -
输入处理:将单个句子作为输入,不需要特殊的分隔符,但可能需要对句子进行分词处理以符合BERT的输入要求。
-
序列标注:将单句标注视为序列标注任务,其中句子中的每个单词或子词都被分配一个标签。BERT模型通过编码器部分提取句子的表示,然后结合序列标注层(如CRF层或softmax层)来为每个单词或子词分配标签。
-
微调模型:在BERT模型的基础上添加一个序列标注层,并通过微调来优化标注性能。微调过程中,模型会学习如何将句子的表示映射到对应的标签序列上。
举例说明:下方的句子,我们对句子中的实体进行标注,如公司名称、地点等。在这个例子中,"苹果公司"应被标注为公司名称,"美国加利福尼亚州库比蒂诺"应被标注为地点。
句子: "苹果公司是一家总部位于美国加利福尼亚州库比蒂诺的科技公司。"
BERT处理:将句子作为输入,并添加特定的标记。然后,使用BERT的编码器部分提取句子的表示,并结合序列标注层(如CRF或softmax层)来为每个单词或子词分配标签。最后,根据标签确定实体的类型和边界。
[CLS] 苹果公司是一家总部位于美国加利福尼亚州库比蒂诺的科技公司。
对句子分词:
苹果公司 是 一家 总部 位于 美国 加利福尼亚州 库比蒂诺 的 科技 公司 。
模型输出(假设为BIO标注方案):
- 苹果公司:B-ORG, I-ORG
- 美国:B-LOC
- 加利福尼亚州库比蒂诺:B-LOC
- 科技公司:B-ORG
注:BIO标注方案中,B表示实体的开始,I表示实体的内部,O表示非实体部分。此外,B和I后面通常会跟随一个表示实体类型的标签,如B-PER(人名)、B-LOC(地名)、B-ORG (机构)等。
4. BERT 的应用场景
4.1 文本分类
通过在预训练的 BERT 模型上添加一个分类层,可以进行文本分类任务。
4.2 命名实体识别
通过在预训练的 BERT 模型上添加一个序列标注层,可以进行命名实体识别任务。
4.3 问答
通过在预训练的 BERT 模型上添加一个问答层,可以进行问答任务。
4.4 语义相似度
通过比较两个句子的 BERT 表示,可以计算它们的语义相似度。
5. 使用 Hugging Face Transformers 库加载 BERT 模型
5.1 安装 Transformers 库
pip install transformers
5.2 导入必要的模块
from transformers import BertTokenizer, BertModel
5.3 加载预训练的 BERT 模型和分词器
# 选择一个预训练的 BERT 模型,例如 'bert-base-uncased'
model_name = 'bert-base-uncased'
# 加载分词器
tokenizer = BertTokenizer.from_pretrained(model_name)
# 加载模型
model = BertModel.from_pretrained(model_name)
5.4 使用模型进行推理
# 输入文本
text = "Hello, how are you?"
# 对输入文本进行编码
inputs = tokenizer(text, return_tensors='pt')
# 通过模型进行推理
outputs = model(**inputs)
# 获取最后一层的隐藏状态
last_hidden_state = outputs.last_hidden_state
# 打印输出
print(last_hidden_state)