一、定义

Bert 模型是 2018 年 10 月由 Google AI 研究院提出的一种预训练模型,采用 Transformer 的编码器(Encoder)结构,堆叠多层,目的是:训练出一个懂文本语言的通用特征提取器

二、BERT 机制

1. 双向注意力机制(Bidirectional Attention)= 自注意力机制

1.定义

普通 RNN/LSTM 只能从左到右看一句,BERT 可以同时看一句话的左右两边

双向 = 左边所有词 + 右边所有词(一句话内)= 上下文 full context

例如:

句子:“我喜欢吃苹果,因为它很甜。”

BERT 看 “苹果” 时:

  • 左边:我喜欢吃
  • 右边:因为它很甜
  • 同时理解,真正双向注意力

2.自注意力公式(也即双向注意力公式)

  • Q:查询(当前词)
  • K:键(所有词)
  • V:值(所有词)

2.多头注意力机制(Multi-Head Attention)

BERT 自注意力是多头并行:把 Query、Key、Value 向量分头投影成多组,并行执行多头自注意力,最后再拼接融合。

过程如下:

设输入词向量维度 d,头数 h

1.线性投影分头

输入词向量后分别得到 Q,K,V 矩阵,将 Q,K,V 矩阵分别通过学习权重矩阵投影,切分为 h 个小头:

每一头维度:d / h

2.每一头独立执行自注意力

3.多头结果拼接

把 h 个头的输出在维度上拼接:

三、BERT 预训练任务

任务:模型的任务 = 看【最终输出 + 损失函数】怎么定义,同一个模型结构,只要改最后输出层和损失函数,任务完全变掉。

1. MLM(Masked Language Model)掩码语言

在句子中随机遮盖一部分单词,让模型去猜

例子:“我喜欢吃 [MASK],因为它很甜。”模型要猜:是苹果?香蕉?还是橘子?

目的:让模型更好地根据全文理解单词的意思

2. NSP(Next Sentence Prediction)下句预测

给模型两句话,判断是不是同一段文章的连续两句,输出:是 / 不是(二分类)。

目的:让模型能够更好地理解句子间的关系

四、BERT 结构

上图是 BERT 的结构图,左侧的图表示了预训练的过程,右边的图是对于具体任务的微调过程。

1.BERT 的输入

BERT 得到要输入的句子后,要将句子的单词转成 Embedding:​编辑

  1. Token Embedding:词向量
  2. Segment Embedding:句子编号向量,用于区分每一个单词属于句子 A 还是句子 B
  3. Positional Encoding:位置向量

BERT 的输入向量,是由 三种 Embedding 直接相加 得到的:

[CLS] 和 [SEP] 作用?
 

[CLS]:分类专用 token.

最后一层 [CLS] 代表整个句子的语义向量

[SEP]:句子分隔符 + 注意力边界

句间隔离,不让两句词互相看见

2.Bert 预训练

BERT 输入句子得到 Input Embedding 之后,通过预训练方式训练模型,预训练有两个任务:

  • MLM
  • NSP

BERT 预训练的过程可以用下图来表示:

3.Bert 微调

预训练得到的 BERT 模型可以在后续用于具体 NLP 任务的时候进行微调 ,BERT 模型可以适用于多种不同的 NLP 任务,如下图所示

五、例子

1.分词

将 “商将务大床房” 拆成单个汉字 "商 务 大 床 房"。这是 BERT 的中文分词方式:按单个字 / 词切分(也可以是词粒度,但中文 BERT 通常用字粒度)。

注意:

  • 实际 BERT 分词器还会加上特殊符号:商 务 大 床 房 → 商 务 大 床 房
  • 最终序列是:[CLS] 商 务 大 床 房 [SEP]

2.生成标准输入向量

1. input_ids:词表索引

(101, 2112, 555, 2315, 13145, 32141, 102)
  • 每个数字代表该 token 在词表中的索引
  • 101 是 [CLS] 的 ID,102 是 [SEP] 的 ID
  • 后续模型会通过这些 ID,在嵌入层查表得到词向量

2. mask:注意力掩码

(1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,......)
  • 1 代表真实 token,模型需要处理
  • 0 代表 padding(填充的无效 token),模型会忽略
  • 作用:让所有输入序列长度一致,不影响注意力计算

3. seq_ids(segment_ids):句子标记

(0,0,0,0,0,0,0,0 ........................)
  • 标记每个 token 属于哪个句子(0 代表第一句,1 代表第二句)
  • 这张图是单句输入,所以全是 0
  • 如果是句子对任务(如问答),第一句标0,第二句标1

3.Embedding 嵌入

根据标准输入向量得到3种Embedding:

Token Embedding(词嵌入)———— input_ids

Segment Embedding(句子嵌入)———— seq_ids

Position Embedding(位置嵌入)————pos_ids

BERT 把这三种向量直接相加,得到每个 token 的最终输入向量:

嵌入的实际操作:

input_ids,seq_ids,pos_ids 各自通过一次全连接,输出维度为768的向量

4.多头自注意力(Multi-Head Attention)

1.输入向量 Embeedding 经过3个分别的全连接线性变换,得到 Query(Q)、Key(K)、Value(V)

2.计算多头注意力:

  • 把 Q/K/V 分成多个头
  • 每个头独立计算注意力,再拼接起来

3.输出的向量维度和输入保持一致,还是 768

5.Add & Norm(残差连接与层归一化,第1次)

1.Add(残差连接):把「多头注意力的输出」和「原始输入向量」直接相加

2.Norm(层归一化):对相加后的结果做层归一化,稳定分布

结果:输出的向量维度和输入保持一致,还是 768,作为下一层(前馈网络)的输入

6.前馈神经网络(Feed Forward)

这是一个两层的全连接网络 Linear,BERT 里的标准结构是:

  1. 第一层:Linear(768 → 3072),然后加激活函数(GELU)
  2. 第二层:Linear(3072 → 768),恢复维度

作用:对每个位置的向量做非线性变换,提取更复杂的语义特征

7.Add & Norm(残差连接与层归一化,第2次)

  1. Add:把「前馈网络的输出」和「前馈网络的输入」直接相加
  2. Norm:对相加后的结果做层归一化,稳定分布
  3. 输出的向量维度和输入保持一致,还是 768,传给 BERT 的下一层(或者传给Pooler output层)

8.Pooler output

1.取最后一层 [CLS] token 的 hidden state

也就是从 BERT 输出的最终向量里,只拿出每句话的 第 0 个位置 = [CLS]。即每句话开头的 [CLS] 768维向量  【以BERT-base 的 768 为例】

为什么要拿[CLS] 768 维向量 ?

因为 [CLS] 经过了全部 12 层双向注意力它融合了整句话所有词的信息所以可以当作 句子的总代表向量

2.拿到 [CLS] 768 维向量后通过一个全连接层(Linear)+ Tanh 激活

公式:pooler_output=tanh(W⋅CLS_hidden+b)

  • 输入维度:hidden_size(BERT-base 是 768)
  • 输出维度:和输入一样,也是 768
  • 作用:把 [CLS] 的向量,映射成一个 “句子级的向量表示”

9.输出给解码器

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐