目录
BERT(Bidirectional Encoder Representations from Transformers)是Google在2018年提出的一种自然语言处理(NLP)预训练模型。BERT模型的创新之处在于它采用了Transformer的编码器架构,并且是第一个真正基于双向上下文进行训练的语言表示模型,这使得它在一系列语言理解任务上取得了当时的最先进性能。
核心概念
-
Transformer: BERT基于Transformer模型,特别是其编码器部分。Transformer模型依赖于自注意力(self-attention)机制,允许模型在处理单词时考虑句子中的所有其他单词,从而更好地理解语言上下文。
-
双向上下文: 与之前的模型(如OpenAI的GPT)不同,BERT通过同时考虑左侧和右侧的上下文信息,能够更加全面地理解单词在不同上下文中的含义。
训练任务
BERT在预训练时使用了两种无监督学习任务:
-
Masked Language Model (MLM): BERT随机地将输入文本中大约15%的单词替换为特殊标记
[MASK]
,然后让模型预测这些[MASK]
位置上的单词。这个任务迫使模型学习单词的双向上下文表示。在MLM任务中,BERT输入的句子会被部分遮盖,模型需要预测被遮盖的单词是什么。使用交叉熵损失函数来度量模型预测结果和真实标签之间的差异。具体而言,对于每个被遮盖的单词,将其对应的预测概率与真实标签(被遮盖前的单词)进行比较,计算交叉熵损失。然后对所有被遮盖的单词的损失进行求和或平均,作为整个MLM任务的损失。 -
Next Sentence Prediction (NSP): BERT还训练了一个二元分类任务,预测两个句子是否在原始文本中相邻。对于这个任务,BERT模型接收一对句子,并预测第二个句子是否是第一个句子在原文中的下一句。在NSP任务中,BERT需要判断两个句子是否是连续的。通常使用二分类的交叉熵损失函数来度量模型对下一句预测的准确性。将模型对连续性的预测概率与真实标签(连续性标签,是或否)进行比较,计算交叉熵损失。
在预训练阶段,BERT将MLM任务和NSP任务的损失进行加权求和,得到整体的预训练损失。加权的权重可以根据任务的重要性进行调整。
输入表示
BERT模型的输入是一个具有多层表示的单词序列,每个单词的表示是以下几个部分的组合:
- Token嵌入:单词的嵌入表示。
- Segment嵌入:表明每个单词属于哪个句子(对于NSP任务)。
- Position嵌入:表明单词在句子中的位置。
微调(Fine-tuning)
在预训练完成后,BERT可以通过微调来适应各种特定的下游任务,如情感分析、问答、实体识别等。微调时,通常在BERT模型的顶部添加一个小的新网络层,然后在特定任务的数据集上继续训练整个模型。
BERT简易代码
import torch
import torch.nn as nn
import torch.nn.functional as F
class TransformerBlock(nn.Module):
def __init__(self, hidden_size, num_attention_heads, intermediate_size, dropout_rate):
super(TransformerBlock, self).__init__()
self.attention = nn.MultiheadAttention(hidden_size, num_attention_heads, dropout=dropout_rate)
self.layer_norm1 = nn.LayerNorm(hidden_size)
self.feed_forward = nn.Sequential(
nn.Linear(hidden_size, intermediate_size),
nn.ReLU(),
nn.Linear(intermediate_size, hidden_size)
)
self.layer_norm2 = nn.LayerNorm(hidden_size)
self.dropout = nn.Dropout(dropout_rate)
def forward(self, x, attention_mask):
# 自注意力机制
residual = x
x, _ = self.attention(x, x, x, attn_mask=attention_mask)
x = self.dropout(x)
x = self.layer_norm1(x + residual)
# 前馈神经网络
residual = x
x = self.feed_forward(x)
x = self.dropout(x)
x = self.layer_norm2(x + residual)
return x
class BERT(nn.Module):
def __init__(self, vocab_size, hidden_size, num_layers, num_attention_heads, intermediate_size, dropout_rate):
super(BERT, self).__init__()
self.embedding = nn.Embedding(vocab_size, hidden_size)
self.transformer_blocks = nn.ModuleList([
TransformerBlock(hidden_size, num_attention_heads, intermediate_size, dropout_rate)
for _ in range(num_layers)
])
def forward(self, input_ids, attention_mask):
x = self.embedding(input_ids)
for transformer_block in self.transformer_blocks:
x = transformer_block(x, attention_mask)
return x
# 示例用法
vocab_size = 10000
hidden_size = 768
num_layers = 12
num_attention_heads = 12
intermediate_size = 3072
dropout_rate = 0.1
model = BERT(vocab_size, hidden_size, num_layers, num_attention_heads, intermediate_size, dropout_rate)
# 输入数据
input_ids = torch.tensor([[1, 2, 3, 4, 5]])
attention_mask = torch.tensor([[1, 1, 1, 1, 1]])
# 前向传播
outputs = model(input_ids, attention_mask)
print(outputs)
上述代码定义了一个TransformerBlock类和一个BERT类。TransformerBlock是BERT模型中的一个基本单元,由自注意力机制和前馈神经网络组成。BERT类则由多个TransformerBlock组成,并负责将输入序列传递给TransformerBlock进行处理。
BERT实际使用
利用Python和transformers
库实现BERT的核心代码,包括加载预训练的BERT模型,对文本进行编码,并获取编码后的特征表示。
首先,请确保你已经安装了transformers
库:
pip install transformers
然后,使用BERT:
from transformers import BertTokenizer, BertModel
import torch
# 1. 初始化分词器和模型
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')
# 2. 编码文本
text = "Here is the sentence to encode"
encoded_input = tokenizer(text, return_tensors='pt') # 将返回的类型设置为PyTorch张量
# 3. 提取输入的部分
input_ids = encoded_input['input_ids']
attention_mask = encoded_input['attention_mask']
# 4. 使用模型获取编码后的特征表示
with torch.no_grad(): # 关闭梯度计算,因为这里只是进行前向传播
output = model(input_ids, attention_mask=attention_mask)
# 5. 提取编码后的最后一层隐藏状态
last_hidden_states = output.last_hidden_state
# 通常,用于分类的特征是[CLS]标记的隐藏状态
cls_features = last_hidden_states[:, 0, :]
print(cls_features)
在这段代码中:
- 分词器(
BertTokenizer
)用于将文本转换为模型能理解的格式,即将文本分割成tokens,并将其映射为模型词汇表中的索引。 - 模型(
BertModel
)用于生成文本的特征表示。在执行模型的forward
方法时,我们提供了input_ids
和attention_mask
。 output
包含了模型返回的多个输出,其中output.last_hidden_state
是模型最后一层的隐藏状态。
注意:如果你要用BERT进行特定的下游任务(如情感分析、命名实体识别等),还需要对BERT进行微调。