Bert基础(十一)--Bert变体之ELECTRA

ELECTRA(Efficiently Learning an Encoder that Classifies Token Replacements Accurately,高效训练编码器准确分类替换标记)是BERT的另一个变体。我们已知要使用掩码语言模型构建任务和下句预测任务对BERT进行预训练。在掩码语言模型构建任务中,我们随机掩盖15%的标记,并训练BERT来预测被掩盖的标记。但是,ELECTRA没有使用掩码语言模型构建任务作为预训练目标,而是使用一个叫作替换标记检测的任务进行预训练。

替换标记检测任务与掩码语言模型构建任务非常相似,但它不是用[MASK]标记来掩盖标记,而是用另一个标记来替换,并训练模型判断标记是实际标记还是替换后的标记。

但为什么使用替换标记检测任务,而不使用掩码语言模型构建任务?这是因为掩码语言模型构建任务有一个问题。它在预训练时使用了[MASK]标记,但在针对下游任务的微调过程中,[MASK]标记并不存在,这导致了预训练和微调之间的不匹配。在替换标记检测任务中,我们不使用[MASK]来掩盖标记,而是用不同的标记替换另一个标记,并训练模型来判断给定的标记是实际标记还是替换后的标记。这就解决了预训练和微调之间不匹配的问题。

与使用掩码语言模型构建任务和下句预测任务进行预训练的BERT不同,ELECTRA仅使用替换标记检测任务进行预训练。但替换标记检测任务是如何工作的?需要替换什么标记?如何训练模型来执行这一任务?下面,就让我们找出这些问题的答案。

1 了解替换标记检测任务

让我们通过一个例子来了解替换标记检测任务究竟是如何工作的。

首先,我们为句子The chef cooked the meal进行分词,如下所示。

python 复制代码
tokens = [ the, chef, cooked, the, meal ]

然后,把第一个标记the换成a,把第三个标记cooked换成ate,如下所示。

python 复制代码
tokens = [ a, chef, ate, the, meal ]

我们替换了两个标记,现在开始训练模型,来判断标记是实际标记还是替换标记。我们把这个模型叫作判别器,因为它只是对标记是实际标记还是替换标记进行分类。

如图所示,将标记送入判别器,它将给出分类结果。

我们已知需要在句子中替换一些标记,并将其送入判别器,以判断这些标记是实际标记还是替换标记。但问题是,在将标记送入判别器之前,究竟该如何替换它们?为了替换标记,需要使用掩码语言模型。在为句子The chef cooked the meal分词后,我们得到的结果如下所示。

python 复制代码
tokens = [ the, chef, cooked, the, meal ]

现在,用[MASK]标记随机地替换两个标记,结果如下所示。

python 复制代码
tokens = [ [MASK], chef, [MASK], the, meal ]

接下来,将这些标记送入另一个BERT模型,并预测被掩盖的标记。我们把这个BERT模型称为生成器,因为它会返回标记的概率分布。从图中可以看到,我们将[MASK]标记送入生成器,它会预测出被[MASK]掩盖的最有可能的标记。

从图中可以看出,生成器将the预测为a,将cooked预测为ate。就这样,将生成器生成的标记拿出来用于替换。也就是说,我们用生成器生成的标记替换给定句子中的标记。还是以句子The chef cooked the meal为例,在分词后,我们得到如下结果。

python 复制代码
tokens = [ the, chef, cooked, the, meal ]

现在,用生成器生成的标记替换这些标记,标记列表将变成如下内容。

python 复制代码
tokens = [ a, chef, ate, the, meal ]

可以看到,我们将the和cooked替换为生成器生成的a和ate。然后,我们将标记送入判别器,并训练它对标记是实际标记还是替换标记进行分类。

如下图所示,我们首先随机地将标记替换为[MASK],并将其送入生成器。生成器预测[MASK]标记。接下来,我们用生成器生成的标记替换原先的标记,并将其送入判别器。判别器对输入的标记是实际标记还是替换标记进行分类。

2 ELECTRA的生成器和判别器

我们知道生成器执行的是掩码语言模型构建任务,它以15%的概率随机将一些标记替换为[MASK],并预测[MASK]处的标记。假设用 X = [ x 1 , x 2 , ... ... , x n ] X = [x_1,x_2,......,x_n] X=[x1,x2,......,xn]来表示输入的标记。我们随机地用[MASK]替换一些标记,并将它们作为输入送入生成器。 h G ( X ) = [ h 1 , h 2 , ... ... , h n ] h_G(X) = [h_1,h_2,......,h_n] hG(X)=[h1,h2,......,hn]是生成器返回的每个标记的特征。 h 1 h_1 h1为第一个标记 x 1 x_1 x1的特征, h 2 h_2 h2为第二个标记 x 2 x_2 x2的特征,以此类推。

现在,将标记的特征送入分类器。分类器是使用softmax函数的前馈网络层,它将返回标记的概率分布,即词表中每个单词是[MASK]的概率。

还是以句子The chef cooked the meal为例,我们随机地将一些标记替换为[MASK],并将其送入生成器。之后,由分类器返回词表中每个单词是[MASK]的概率,如下图所示。

用 x t x_t xt表示位置 t t t被[MASK]替换的单词。然后,生成器返回词表中每个单词是 x t x_t xt的概率。计算概率的公式如下所示。

P G ( x t ∣ x ) = e x p ( e ( x t ) T h G ( X ) t ) ∑ x ' e x p ( e ( x t ) T h G ( X ) t ) P_G(x_t|x) = \frac{exp(e(x_t)^Th_G(X)t)}{\sum{x^`}exp(e(x_t)^Th_G(X)_t)} PG(xt∣x)=∑x'exp(e(xt)ThG(X)t)exp(e(xt)ThG(X)t)

在上面的公式中, e ( ⋅ ) e(·) e(⋅)为标记嵌入。通过分类器返回的概率分布,可以选择高概率的单词作为[MASK]标记所掩盖的实际单词。根据上图所示的概率分布,掩码标记 x 1 x_1 x1被预测为a,而掩码标记 x 3 x_3 x3被预测为ate。接下来,用生成器生成的标记替换输入的标记,并将其送入判别器。

判别器的目标是判断给定的标记是由生成器生成的还是实际标记。首先,将标记送入判别器,判别器返回每个标记的特征。我们用 h D ( X ) = [ h 1 , h 2 , ... ... , h n ] h_D(X)=[h_1,h_2,......,h_n] hD(X)=[h1,h2,......,hn]表示判别器返回的每个标记的特征。接下来,将每个标记的特征送入分类器,已知它是使用sigmoid函数的前馈网络层。分类器返回给定的标记是实际标记还是替换标记。

如下图所示,向判别器输入标记。

x t x_t xt代表位置 t t t的标记。判别器使用sigmoid函数返回该标记是实际标记还是替换标记,如下所示。

D ( X , t ) = s i g m o i d ( w T h D ( X ) t ) D(X,t) = sigmoid(w^Th_D(X)_t) D(X,t)=sigmoid(wThD(X)t)

小结一下,将[MASK]标记送入生成器,生成器则预测被[MASK]替换的标记。然后,用生成器生成的标记替换输入的标记,将其再送入判别器。判别器对输入的标记是实际标记还是替换标记进行分类,如图所示。

判别器就是ELECTRA模型,它要训练BERT对给定的标记是实际标记还是替换标记进行分类,因此它被称为ELECTRA,即高效训练编码器准确分类替换标记。

与BERT相比,ELECTRA有自己的优点。在BERT中,我们使用掩码语言模型构建任务作为训练目标,只替换15%的固定标记,所以模型的训练信号只有这15%的标记,它只预测那些被替换为[MASK]的标记。但是在ELECTRA中,训练信号是所有的标记,因为模型会对所有给定的标记是实际标记还是替换标记进行分类。

3 训练ELECTRA模型

我们使用掩码语言模型构建任务对生成器进行训练。对于一个给定的输入 X = [ x 1 , x 2 , ... ... , x n ] X = [x_1,x_2,......,x_n] X=[x1,x2,......,xn],我们随机选择几个位置替换为[MASK]标记。 M = [ m 1 , m 2 , ... ... , m n ] M = [m_1,m_2,......,m_n] M=[m1,m2,......,mn]表示选定的[MASK]位置。然后,我们用[MASK]标记替换所选位置的标记,公式如下所示。
X m a s k e d = R e p l a c e ( X , M , [ M A S K ] ) X^{masked} = Replace(X,M,[MASK]) Xmasked=Replace(X,M,[MASK])

将 X m a s k e d X^{masked} Xmasked标记送入生成器,让生成器预测被[MASK]替换的标记。

将输入中的一些标记用由生成器生成的标记替换,并将其标记为 X c o r r u p t X^{corrupt} Xcorrupt,它是由被生成器替换的标记组成的。

生成器的损失函数如下所示。

我们将被替换的标记 X c o r r u p t X^{corrupt} Xcorrupt送入判别器,对给定的标记是实际标记还是替换标记进行分类。判别器的损失函数如下所示。

我们通过最小化生成器和判别器的综合损失来训练ELECTRA模型,其公式如下所示。

在公式中, θ G \theta_G θG和 θ D \theta_D θD分别表示生成器和判别器的参数,表示一个大型文本语料库。下面,让我们学习如何高效地训练ELECTRA模型。

4 高效的训练方法

为了高效地训练ELECTRA模型,可以在生成器和判别器之间共享权重。也就是说,如果生成器和判别器的大小相同,那么编码器的权重就可以共享。

但问题是,如果生成器和判别器的大小相同,就会增加训练时间。为了避免这种情况,可以使用较小的生成器。当生成器较小时,可以仅共享生成器和判别器之间的嵌入层(标记嵌入和位置嵌入)。这种生成器和判别器之间的共享式嵌入可使训练时间最小化。

预训练的ELECTRA模型可以从GitHub上下载。它有以下3种配置。

  • ELECTRA-small:有12层编码器,隐藏层大小为256。
  • ELECTRA-base:有12层编码器,隐藏层大小为768。
  • ELECTRA-large:有24层编码器,隐藏层大小为1024。

我们可以像使用其他BERT模型一样,将ELECTRA模型与Transformers库一起使用。

首先,导入必要的模块。

python 复制代码
from transformers import ElectraTokenizer, ElectraModel

假设使用ELECTRA-small判别器,下载并加载预训练的ELECTRA-small判别器,如下所示。

python 复制代码
model = ElectraModel.from_pretrained('google/electra-small-discriminator')

通过同样的方式,我们也可以加载ELECTRA的其他配置。

相关推荐
deephub14 分钟前
优化注意力层提升 Transformer 模型效率:通过改进注意力机制降低机器学习成本
人工智能·深度学习·transformer·大语言模型·注意力机制
搏博25 分钟前
神经网络问题之二:梯度爆炸(Gradient Explosion)
人工智能·深度学习·神经网络
KGback31 分钟前
【论文解析】HAQ: Hardware-Aware Automated Quantization With Mixed Precision
人工智能
电子手信39 分钟前
知识中台在多语言客户中的应用
大数据·人工智能·自然语言处理·数据挖掘·知识图谱
不高明的骗子40 分钟前
【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境
人工智能·pytorch·深度学习·cuda
Chef_Chen1 小时前
从0开始学习机器学习--Day33--机器学习阶段总结
人工智能·学习·机器学习
搏博1 小时前
神经网络问题之:梯度不稳定
人工智能·深度学习·神经网络
Sxiaocai1 小时前
使用 PyTorch 实现并训练 VGGNet 用于 MNIST 分类
pytorch·深度学习·分类
GL_Rain1 小时前
【OpenCV】Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR)
人工智能·opencv·计算机视觉
shansjqun1 小时前
教学内容全覆盖:航拍杂草检测与分类
人工智能·分类·数据挖掘