
BERT
BERT
里面也有一些 BERT 模型族的讲解: Meena: Google 的开放域聊天机器人 - 知乎
1 预训练任务
1.1 MLM
- Masked Language Model, 掩码语言模型
- 在输入文本和
[SEP]
时,输出 MLM 结果。
1.1.1 掩码样本生成
- 对输入没有特别要求,可以是一段文本也可以是两段,为了配合 NSP,BERT 预训练时统一输入为两段文本。
- 传统基于条件概率的建模(比如 n-gram)只能顺序建模或者逆序建模。
- 同时进行双向建模会导致模型偷懒,直接从未来的词中挑选当前预测的结果而非基于历史词推测。
- 本质上是因为答案就在输入序列里(没有掩码)。
- ELMo 模型采用了独立的顺序、逆序 LSTM 建模再拼接的方法。
- 同时进行双向建模会导致模型偷懒,直接从未来的词中挑选当前预测的结果而非基于历史词推测。
- MLM 采用完形填空的方法。
- 预处理时,将输入文本中的部分单词掩码。
- 然后通过模型还原该词。
- 采用了 15% 的掩码比例,输入序列中 15% 的 WordPieces 子词进行掩码操作。
- 掩码不能太多,因为下游任务精调时并没有
[MASK]
出现。 - 掩码操作如下
- 掩码不能太多,因为下游任务精调时并没有
概率 | 操作 | 例子 |
---|---|---|
80% | 替换为 [MASK] |
I [MASK] you. |
10% | 替换为词表的一个随机词 | I apple you. |
10% | 不做操作 | I love you. |
- 经过掩码后,原始输入$x_1x_2\dots x_n$变成了$x_1’x_2’\dots x_n’$。
- 然后进行输入表示,得到$v$作为编码层输入。
1.1.2 输入表示
- InputRepresentation
- 由三种向量线性叠加,三种向量的维度都是$e$,称为输入表示维度。 $$ v = v^t + v^s + v^p $$
向量 | 含义 | 解释 | 示例 | 如何获得 |
---|---|---|---|---|
$v^t$ | 词向量 | 代表每个词,包括字符和特殊词 | $v_{[CLS]}, v_{[我]}, v_{[你]}$ | 先构造独热向量矩阵$e^t$,乘上可训练权重矩阵$W^t$ |
$v^s$ | 块向量 | 代表每个词所属的块,从 0 开始编码 | $v_{块 A}, v_{块 B}$ | 先按块号得到块编码矩阵$e^s$,乘上可训练权重矩阵$W^s$ |
$v^p$ | 位置向量 | 代表每个词所在的绝对位置(跨句子) | $v_{位置 0}, v_{位置 1}$ | 先按词的位置得到独热向量矩阵$e^p$,乘上可训练权重矩阵$W^p$ |
- 宏观上认为输入序列是$X=[CLS]x_1^{(1)}x_2^{(1)}\dots x_n^{(1)} [SEP] x_1^{(2)} x_2^{(2)}\dots x_m^{(2)}[SEP]$
- 认为上述三种向量的构造与线性叠加的操作叫$\textnormal{InputRepresentation}$.
- 最终得到输入向量$\mathbf{v} \in \mathbb{R}^{N\times e}$,显然,$\mathbf{v} = \textnormal{InputRepresentation}(X)$
1.1.2.1 词向量
- $v^t$
- 上标用$t$表示词向量相关的变量。
- 输入序列$x$(非粗体)由 N 个词组成(N 是 最大序列长度 N ,“词”后面都会解释),词表大小为$|V|$。
- 每个“词”是一个长度为$|V|$的 One-Hot 向量。
- 所以输入序列 x 的独热向量表示为$\textbf{e}^t$($e$表示 embedding),维度为$N\times \mathbb{V}$(记作$\textbf{e}^t \in \mathbb{R}^{N\times \left| \mathbb{V} \right|}$)
- ** 可训练的权重矩阵**是$W^t$,其维度是$\mathbb{V}\times e$(记作$\textbf{W}^t \in \mathbb{R}^{\left| {\mathbb{V}} \right| \times e}$)
- 最终参与输入表示的词向量是$\textbf{v}^t = \textbf{e}^t \textbf{W}^t$,显然维度为$N\times e$。
- 每行是一个单元的词向量,有$e$维度。称为词向量维度,是一个超参数。 ^a5eb44
- 由$|V|$维独热向量的稀疏表示变成了$e$维的稠密表示。 ^ba5dfc
1.1.2.2 块向量
- $v^b$
- 上标用$b$表示块向量相关的变量。
- 块向量用于表示当前的词所属的块(Segment)。
- 输入序列$x$中每个词对应的块编码(Segment Encoding)为当前块的序号。
- 从 0 开始计数。
- 如果只有单个块,比如单句文本分类,则块编码都是 0.
- 如果是两个块(如 下一个句子预测 )。
- 则第一个句子中每个词的块编码是 0,
[CLS]
位是 0,第一个句子结束时的[SEP]
块编码是 0. - 第二个句子中每个词的编码为 1.
- 则第一个句子中每个词的块编码是 0,
- 按照如上规则得到块编码$e^s$。
- 然后引入可训练的权重矩阵$\textbf{W}^s$(维度为$N\times |\mathbb{S} |$,N 是词个数,$|\mathbb{S}|$是块数,因为规定了块编号按块数来)。
- 最终得到块向量$v^s$.
1.1.2.3 位置向量
- $e^p$
- 上标用$p$表示位置向量相关的变量。
- 首先将输入序列中的每个词按照下标获得位置独热编码,比如第 2 个词就是
[0 1 0...]
。 - 然后引入可训练的权重矩阵$\textbf{W}^p$(维度为$N\times e$,N 是词个数,e 是 隐层维度 )。
- 最终得到位置向量$v^p$.
1.1.3 编码层
- 从宏观上看,BERT 的主体部分由 L 层 Transformer 组成(记单层 Transformer 为 Transformer-Block),则可以描述为如下
- h 表示 hidden,即隐层,维度为$N\times d$,$d$是一个超参数,表示隐层的维度。
$$ \displaylines{ \mathbf{h}^{[l]} = \textnormal{Tranformer-Block}(\mathbf{h}^{[l-1]}), \forall l\in {1,2,\dots, L} \ \mathbf{h}^{[0]} = \mathbf{v} } $$
- 以上公式可以简单记作$\mathbf{h} = \textnormal{Transformer}_L (\mathbf{v})$
- 最终得到的$h$是最后一层 Tranformer-Block 的隐层。
1.1.4 输出层
- 根据[[#输入层]]知道,掩码比例只有 15%,只需要在掩码的位置进行预测即可。
- 预测是免费的,但是预测后计算交叉熵、梯度、反向传播调参是非常繁重的,所以只预测这些有用的。
- 从$h$中抽取出对应的表示,即从 N 行中抽取出掩码过的 k 行,得到的矩阵$\mathbf{h}^m \in \mathbb{R}^{k\times d}$。
- m 表示 mask,k 表示掩码总数量,在输入文本长度为 n 时,$k=\textnormal{floor}(n\times 15%)$(下取整)。
- 记掩码位置下标集合$\mathbb{M} = {m_1, m_2, \dots, m_k}$
- 对于掩码表示中的第 i 个分量$\mathbf{h}_i^m$,将其映射到词表空间。
- 注意最后优化的目标是得到词向量$v_t$里那个权重矩阵$W^t$。
- 模型的含义是人赋予的,你认为 Transformer 出来的结果表示预测的词嵌入,那就是。
- 由于词向量的表示维度$e$(超参数)在实际训练时与隐层维度$d$(超参数)选的一样,所以直接计算即可。 ^cc8009
- 如果不相等,中间要加一层$e\times d$的全连接层。
- 用词向量矩阵作为权重矩阵,加上偏置,进行 Softmax 分类,得到概率分布。
- $P_i = \textnormal{Softmax}(\mathbf{h}_i^m{W^t}^\intercal + \mathbf{b}^o)$
- 然后用概率分布$P_i$与标签$y_i$(即被掩码前,该处单词$x_i$的独热向量表示)计算交叉熵。
1.2 下一个句子预测
- Next Sentence Prediction, NSP
- 顾名思义,用来判断两段文本之间的关系。是一个二分类任务。
1.2.1 正负样本
- 正样本:负样本 = 1:1
样本类型 | 上句 | 下句 |
---|---|---|
正样本 | I love you. | For eternity. |
负样本 | I love you. | Weather is good. |
- 样本简单,可以大量产生,可以看做一个无监督任务。
- 目的仍然是得到高质量的词向量。
1.2.2 输入层
- 对于掩码处理后的输入文本,进行拼接,然后再计算其输入表示。
- ${x_1^{(1)}}, {x_2^{(2)}}$是两个掩码后的句子。
- $X = [CLS] x_1^{(1)} \dots x_1^{(n)} [SEP] x_1^{[2]}\dots x_2^{[m]} [SEP]$
- $\mathbf{v} = \textnormal{InputRepresentation}(X)$
- 块向量$v_b$的表示。
1.2.3 编码层(模型结构)
- 同 MLM 任务的 编码层(模型结构) 。
1.2.4 输出层
- 得到最后一个隐层$\textbf{h}$后,从中提取出$[CLS]$的向量。
- 由于$[CLS]$都放在了序列最前面,所以直接取首个分量$\textbf{h}_0$就行。
- 此时需要一个额外的权重矩阵(全连接层)$W^p$参与预测,预测结果只有两个,写成独热向量($\mathbb{R}^2$)。
- $P = \textnormal{Softmax}(\textbf{h}_0 \textbf{W}^p + \textbf{b}^0)$
- $W^p \in \mathbb{R}^{d\times 2}$,偏置$\textbf{b}^0 \in \mathbb{R}^2$.
- 然后将概率分布与真实结果(要么
[1,0]
要么[0,1]
).
2 starts here
#todo Seq2Seq 预训练语言模型:BART 和 T5 - Ethan Yan 的文章 - 知乎 https://zhuanlan.zhihu.com/p/420090646
MacBERT: 中文自然语言预训练模型(2020 年 11 月论文) - 知乎 >
- Bidirectional Encoder Representation from Tranformers, BERT
- 基于深层 Transformer 的预训练语言模型。
- 利用了大规模无标注文本来挖掘语义信息。
- 加深了自然语言处理模型的深度。
- 面试资料 2021 年 10 月 25 日-京东 NLP 工程师一面面试题分享 - 知乎
- 和 RoBERTa 的区别
- r 去掉了 NSP
- 1)训练时间更长,batch size 更大,训练数据更多; 2)移除了 next predict loss; 3)训练序列更长; 4)动态调整 Masking 机制。 5) Byte level BPE RoBERTa is trained with dynamic masking (Section 4.1), FULL - SENTENCES without NSP loss (Section 4.2), large mini-batches (Section 4.3) and a larger byte-level BPE (Section 4.4).
- 和 ALBERT 的区别 ALBERT 的改进 / 贡献: 提出了两种减少内存的方法(因式分解、参数共享) 改进了 BERT 中的 NSP 的预训练任务,提升了训练速度 提升了模型效果 ALBERT 的改进有三个方面: 对 Embedding 进行因式分解 跨层参数共享(性能轻微降低,参数大量减少)
一般来言,输入 embedding 到 hidden layer 必然有 embedding size = hidden size,即 E = H
为了提高模型效果而放大 hidden size 的 H,必然会导致 embedding size 的 E 过大。实际对 word 的表征不需要那么大的 embedding size,过大的 E 会使得 embedding 稀疏甚至会有负向效果。
作者对 vocab 矩阵进行矩阵分解使得 VH 的矩阵(word list 的长度 * embedding size)变成两个子矩阵的乘积,(VE 的矩阵)(EH 的矩阵)
矩阵分解意味着信息压缩意味着参数减少,本来要训练 V*H 的矩阵,现在只要训练两个小的子矩阵
- 如果输入句子太长怎么办
- longformer ,big bird ,linformer
- sop(sentence order prediction)
深入浅出语言模型(四)——BERT 的后浪们(RoBERTa、MASS、XLNet、UniLM、ALBERT、TinyBERT、Electra)_一个 nlp 探险者的博客-CSDN 博客
移去 NSP 任务,使用 SOP 任务 BERT 的 NSP 任务实际上是一个二分类,训练数据的正样本是通过采样同一个文档中的两个连续的句子,而负样本是通过采用两个不同的文档的句子。NSP 的设计思路实际上是将主题预测和连贯性预测这两个任务混杂在同一个任务里。主题预测任务比连贯性预测任务更容易学习训练,并且在 MASK 语言模型的训练过程中已经学到了不少主题预测的信息。
ALBERT 中,为了只保留一致性任务去除主题识别的影响,提出了一个新的任务 — 句子连贯性预测 sentence-order prediction(SOP),SOP 的正样本和 NSP 的获取方式是一样的,负样本把正样本的顺序反转即可。这样做的目的是:通过调整正负样本的获取方式去除主题识别的影响,使预训练更关注于句子关系一致性预测。
3 BERT 代码解析
-
-
句子长度
max_len
取 30-256 都是合理的,最好能够使用 90% 以上的训练数据,再长就是文档了,需要进一步处理。 -
一个句子内的掩码不能太多,通过
max_pred=5
来制约。- 不同版本的代码可能没有这个参数,只取 15%.
- 注意 10% 是
else
分支里的 50%,随机数是否重复利用,这里要考虑清楚。 - 15% 的词汇都参与计算了损失,但是没有被 mask 的词,它们的标签都是 0,在交叉熵里用 ignore_index 屏蔽了,并没有对损失函数的值有贡献。
- #todo attention 的计算那儿被封装了,没搞懂
-
随机取三个可以先打乱,然后取前三个。 04:40
-
MLM 取样后可能长度不够输入,可以补 0. 0 是在交叉熵函数的 ignore_index 里手动指定的(默认是-100),说明此处不会参与计算损失计算。 08:11
-
Transformer 中,
[PAD]
处的 attention mask 是 0. 04:44 -
torch.gather 05:40
-
两部分 loss 直接相加
06:02
- model 的 forward 只给 logits,loss 是在外面算的。