BERT论文解析

1.Introduction

在许多NLP任务中,使用预训练模型的方式,可有效提升最终模型的精度。
常见任务有:

  • 句子粒度
    • 自然语言推断
    • 预测句子之间的关系
  • 词粒度
    • 实体识别
    • 问答任务

有两种主流策略来实现将预训练词向量表达应用于下游任务。

  • 基于特征的方法,例如ELMo
    使用特定网络结构,词向量表达,是特定网络内部的一部分。
  • 基于微调的方法,例如Generative Pre-trained Transformer(抱歉,这部分论文我还没有看,理解不一定到位)
    引入了最小的任务特定参数,并通过简单地微调预训练参数来训练下游任务。

作者认为,目前使用的技术严重限制了预训练词向量表达的力量。
这种局限性体现在:标准的语言模型是单向的,这个条件限制了在预训练期间可以采用的网络结构。
比如,OpenAI GPT模型是一种从左到右的结构。在这个结构中,每个词只能注意到它前面的所有词语,而无法接触到它后面的词语。
这种局限性会拖累句子粒度的NLP任务精度,更会严重干扰词粒度的NLP任务精度。例如,在SQuAD-QA任务上,从两个方向合并语义至关重要。

由此,引出微调加强版–BERT模型Bidirectional Encoder Representations from Transformers。
为了解决单向语言模型对词向量表达的限制问题,BERT提出了一种新的预训练目标masked language model。
这种模型随机遮蔽句子中的一些词,训练的目标是基于句子上下文环境,来预测出这些被遮蔽词的id。
基于这样的训练目标,词向量表达在训练过程中会学习上下文内容信息,避免了只能单向学习的尴尬。
如此,可以训练得到双向Transformer模型。
除masked language model外,论文中还提出了一种训练任务,预测训练语料中的两个句子是否连贯。
运用joint learning方法,联合预训练出"句子对"的词向量表达。

2.Related Work

大致介绍了NLP领域近期在预训练词向量和迁移学习语义表达的进展。

3.BERT

3.1模型结构

BERT的模型是由多层双向Transformer编码器组成的。
论文中提出两种大小的网络结构
Base:12层,768隐藏单元,12个multi-head-attention的head,总参数量110M。
Base模型可以在单GPU上运行。
Large:24层,1024隐藏单元,16个multi-head-attention的head,总参数量340M。
Large模型需要在TPU上运行。

3.2输入数据

数据由[A, B]这样的一对句子组成。(比如[Question, Answer])
句子对整体作为一个序列,在序列内部,用特殊标识分割它们。
token的embedding是由三个向量加和而成,分别是:token,segment和position embedding。
其中,segment embedding,是句子对[A, B]各自的sentence embedding。

3.3预训练任务

  • task1: 遮蔽单词预测(原文叫masked LM)
    总体来说,是在原句中随机选择单词做遮蔽处理。
    由于训练过程,语料含有遮蔽的词,而训练后将模型应用于实际任务时,语料没有遮蔽词。这种不匹配问题,用下面的方式来解决:
    挑选15%的词。这些被选中的词中,80%直接替换成[MASK],10%被随机替换成另一个语料中的词,10%不做任何处理。
    Transformer编码器不知道最终要预测哪个词,更不知道输入句子对里哪个词是被随机替换成其他词了,所以它必须保留每个词语的语境表达分布信息。此外,这种随机替换的概率只有15%*10%=1.5%,因此它不会严重破坏语言模型的理解能力。
    由于task1中只对15%的遮蔽词做预测,这样的任务需要更多的训练步骤才能达到收敛。但它对模型精度提升的收益远大于训练时间成本。

  • task2: 句子对[A, B]关系预测
    许多重要的下游任务,如问答(QA)和自然语言推理(NLI)都是基于理解两个句子之间的关系。通过上述语言模型,无法直接获得这种信息。
    为了训练一个理解句子关系的模型,论文中给出了task2作为解决方法:训练一个二分类任务,判断句子对[A,B]是否连贯的上下文。
    生成句子对[A,B]时,50%概率是连贯的上下句,50%概率是随机摘取的不相关句子。

3.4训练词向量过程

ELMO使用句子级语料(按句子粒度shuffle训练集),与ELMO不同,而BERT为了提取更长序列信息,采用了document级语料。[A,B]句子对的总长度不大于512token。
batch_size = 256
sentence_length = 512
epoch = 40
optimizer = Adam
lr = 1e-4
beta1 = 0.9
beta2 = 0.999
l2 weight = 0.01
lr warmup = 10,000
dropout = 0.1
activation = gelu

3.5微调过程

(未完待续ing)

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BERT是一种预训练的语言模型,它在自然语言处理领域表现出色。在这里,我将简要介绍如何使用PyTorch实现BERT模型。 首先,我们需要导入必要的库: ```python import torch import torch.nn as nn from transformers import BertModel ``` 然后,我们定义BERT模型的类: ```python class BERT(nn.Module): def __init__(self, bert_path): super(BERT, self).__init__() self.bert = BertModel.from_pretrained(bert_path) self.dropout = nn.Dropout(0.1) self.fc = nn.Linear(768, 1) def forward(self, input_ids, attention_mask): output = self.bert(input_ids=input_ids, attention_mask=attention_mask) output = output.last_hidden_state output = self.dropout(output) output = self.fc(output) output = torch.sigmoid(output) return output ``` 在这个类,我们首先使用`BertModel.from_pretrained()`方法加载预训练BERT模型。然后,我们添加了一个dropout层和一个全连接层。最后,我们使用sigmoid函数将输出值转换为0到1之间的概率。 接下来,我们定义训练和测试函数: ```python def train(model, train_dataloader, optimizer, criterion, device): model.train() running_loss = 0.0 for inputs, labels in train_dataloader: inputs = inputs.to(device) labels = labels.to(device) optimizer.zero_grad() outputs = model(inputs['input_ids'], inputs['attention_mask']) loss = criterion(outputs.squeeze(-1), labels.float()) loss.backward() optimizer.step() running_loss += loss.item() * inputs.size(0) epoch_loss = running_loss / len(train_dataloader.dataset) return epoch_loss def test(model, test_dataloader, criterion, device): model.eval() running_loss = 0.0 with torch.no_grad(): for inputs, labels in test_dataloader: inputs = inputs.to(device) labels = labels.to(device) outputs = model(inputs['input_ids'], inputs['attention_mask']) loss = criterion(outputs.squeeze(-1), labels.float()) running_loss += loss.item() * inputs.size(0) epoch_loss = running_loss / len(test_dataloader.dataset) return epoch_loss ``` 在训练函数,我们首先将模型设置为训练模式,并迭代数据集的每个批次,将输入和标签移动到GPU上,然后执行前向传播、计算损失、反向传播和优化器步骤。在测试函数,我们将模型设置为评估模式,并在数据集上进行迭代,计算测试损失。 最后,我们可以实例化模型并开始训练: ```python if __name__ == '__main__': bert_path = 'bert-base-uncased' train_dataset = ... test_dataset = ... train_dataloader = ... test_dataloader = ... device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = BERT(bert_path).to(device) optimizer = torch.optim.Adam(model.parameters(), lr=1e-5) criterion = nn.BCELoss() for epoch in range(num_epochs): train_loss = train(model, train_dataloader, optimizer, criterion, device) test_loss = test(model, test_dataloader, criterion, device) print(f'Epoch {epoch+1}/{num_epochs}, Train loss: {train_loss:.4f}, Test loss: {test_loss:.4f}') ``` 在这里,我们首先定义数据集和数据加载器,然后实例化模型并将其移动到GPU上(如果可用)。然后,我们定义优化器和损失函数,并开始训练模型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值