二、用于预训练BERT的数据集( 二 )


class BERTEncoder(nn.Module):"""BERT编码器"""def __init__(self, vocab_size, num_hiddens, norm_shape, ffn_num_input,ffn_num_hiddens, num_heads, num_layers, dropout,max_len=1000, key_size=768, query_size=768, value_size=768,**kwargs):super(BERTEncoder, self).__init__(**kwargs)self.token_embedding = nn.Embedding(vocab_size, num_hiddens)self.segment_embedding = nn.Embedding(2, num_hiddens)self.blks = nn.Sequential()for i in range(num_layers):self.blks.add_module(f"{i}", d2l.EncoderBlock(key_size, query_size, value_size, num_hiddens, norm_shape,ffn_num_input, ffn_num_hiddens, num_heads, dropout, True))# 在BERT中,位置嵌入是可学习的self.pos_embedding = nn.Parameter(torch.randn(1, max_len, num_hiddens))def forward(self, tokens, segments, valid_lens):# 在以下代码段中,X的形状保持不变:(批量大小,最大序列长度,num_hiddens)X = self.token_embedding(tokens) + self.segment_embedding(segments)X = X + self.pos_embedding.data[:, :X.shape[1], :]for blk in self.blks:X = blk(X, valid_lens)return X
4.预训练任务
预训练包括两个任务:掩蔽语言模型和下一句预测 。前者能够编码双向上下文来表示单词,而后者则显式地建模文本对之间的逻辑关系 。
掩蔽语言模型
语言模型使用左侧的上下文预测词元 。为了双向编码上下文以表示每个词元,BERT随机掩蔽词元并使用来自双向上下文的词元以自监督的方式预测掩蔽词元 。此任务称为掩蔽语言模型() 。
在这个预训练任务中,将随机选择15%的词元作为预测的掩蔽词元 。要预测一个掩蔽词元而不使用标签作弊,一个简单的方法是总是用一个特殊的“”替换输入序列中的词元 。然而,特殊词元“”不会出现在微调中 。为了避免预训练和微调之间的这种不匹配,如果为预测而屏蔽词元(例如,在“this movie is great”中选择掩蔽和预测“great”),则在输入中将其替换为:
请注意,在15%的概率中,有10%的概率插入了随机词元 。这种偶然的噪声鼓励BERT在其双向上下文编码中不那么偏向于掩蔽词元(尤其是当标签词元保持不变时) 。
class MaskLM(nn.Module):"""BERT的掩蔽语言模型任务"""def __init__(self, vocab_size, num_hiddens, num_inputs=768, **kwargs):super(MaskLM, self).__init__(**kwargs)self.mlp = nn.Sequential(nn.Linear(num_inputs, num_hiddens),nn.ReLU(),nn.LayerNorm(num_hiddens),nn.Linear(num_hiddens, vocab_size))def forward(self, X, pred_positions):"""输入BERTEncoder的编码结果和用于预测的词元位置,输出是这些位置的预测结果"""num_pred_positions = pred_positions.shape[1]pred_positions = pred_positions.reshape(-1)batch_size = X.shape[0]batch_idx = torch.arange(0, batch_size)# 假设batch_size=2,num_pred_positions=3# 那么batch_idx = tensor([0, 0, 0, 1, 1, 1])batch_idx = torch.repeat_interleave(batch_idx, num_pred_positions)masked_X = X[batch_idx, pred_positions]masked_X = masked_X.reshape((batch_size, num_pred_positions, -1))mlm_Y_hat = self.mlp(masked_X)return mlm_Y_hat

二、用于预训练BERT的数据集

文章插图
下一句预测
尽管掩蔽语言建模能够编码双向上下文来表示单词,但它不能显式地建模文本对之间的逻辑关系 。为了帮助理解两个文本序列之间的关系,BERT在预训练中考虑了一个二元分类任务——下一句预测(Next) 。在为预训练生成句子对时,有一半的概率它们确实是标签为“真”的连续句子;在另一半的概率里,第二个句子是从语料库中随机抽取的,标记为“假” 。
由于编码器中的自注意力,特殊词元“”的BERT表示已经对输入的两个句子进行了编码 。因此,多层感知机分类器的输出层(self.)以X作为输入,其中X是多层感知机隐藏层的输出,而MLP隐藏层的输入是编码后的“”词元 。