架构演进 · 编码器

BERT

BERT-base · 与 GPT-2 同样的形状,双向阅读

对比
BERT-base vs GPT-2 small
层
12 GPT-2 12
dmodel
768 GPT-2 768
头
12 GPT-2 12
dff
3,072 GPT-2 3,072
词表
30,522 个 WordPiece GPT-2 50,257
参数
110M GPT-2 124M

全部步骤

  1. 同样的形状,两个方向

    BERT-base 的形状和 GPT-2 small 一模一样:12 层,宽 768,12 个头。不同的是方向:没有因果掩码,所以每个词元都能看到整个句子;它被训练成填出被隐藏的词,而不是预测下一个词。和 2017 年的 Transformer 一样,它在每次残差相加之后归一化。

    12 × 768 · 110M · 仅编码器

  2. 双向看

    两个真实的头。GPT-2 最明显的前一词元头只能往回看。BERT 的第 3 层头 1 是它的镜像:几乎所有注意力都给了下一个词元,而这是因果掩码所禁止的。把鼠标停在格子上看看。

    因果三角 · 完整方阵

  3. 输入了什么

    BERT 一次读一到两个句子:[CLS] 在最前,每个句子后面跟一个 [SEP]。每个输入向量是三者之和:WordPiece 词元嵌入、片段嵌入(句子 A 或 B)和学习得到的位置嵌入。WordPiece 会切开罕见词:mailman → mail ##man。

    词元 + 片段 + 位置

  4. 完形填空

    训练时,15% 的词元被选中并隐藏(大多换成 [MASK]),BERT 从两侧预测它们:这就是掩码语言建模。这些是 BERT-base 的真实预测,旁边是 GPT-2 只凭空格之前的词做出的猜测。用下方的箭头切换句子。

    从两侧预测 [MASK]

  5. 用来读,而不是写

    BERT 是为读而建的,不是为写:没有从左到右的顺序,它没有自然的方式来生成文本。取而代之的是在上面训练一个小分类器:用最终的 [CLS] 向量给每个句子一个标签(例如情感),或用每个词元的向量做标注。

    label = softmax(hCLS · W)

代码

# BERT: GPT-2 small's shape, no causal mask, LayerNorm after each add
x = layer_norm(tok_emb[ids] + seg_emb[segments] + pos_emb[positions])
for layer in layers:                          # 12 × (768 wide, 12 heads, 3,072)
    x = layer_norm(x + self_attn(x))            # every token sees every token
    x = layer_norm(x + mlp(x))
# pretraining: predict hidden tokens from both sides
logits = mlm_head(x[masked_positions])        # 30,522 WordPiece scores
loss = F.cross_entropy(logits, original_ids)
# using it: a classifier on the [CLS] vector
probs = F.softmax(x[:, 0] @ W_cls, dim=-1)

延伸阅读