【理论】GPT和Bert的区别
1、GPT和Bert的区别?
GPT vs Bert_bert和gpt的区别-CSDN博客
1)目标任务
Bert基于编码器,Bert 模型的输出是每个单词位置的隐层状态,这些状态可以被用作特征表示,以便于在其他任务中进行 fine-tuning。由于 Bert 模型采用了双向编码,它可以更好地捕捉句子中的上下文信息,因此在许多自然语言处理任务中都取得了非常好的效果。
BERT通过掩码语言模型(Masked Language Model,MLM)和下一句预测(Next Sentence Prediction,NSP)任务进行训练。
掩码语言模型(Masked Language Model,MLM):在输入序列中,BERT随机掩盖一些词语,然后要求模型预测这些被掩盖的词语。通过这个任务,BERT可以学习到在给定上下文的情况下,预测缺失词语的能力。
下一句预测(Next Sentence Prediction,NSP):在一些自然语言处理任务中,理解句子之间的关系是很重要的。为了让模型学习句子级别的关系,BERT使用了NSP任务。该任务要求模型判断两个句子是否是连续的,即一个句子是否是另一个句子的下一句。
GPT基于解码器,GPT 模型中,输入的序列首先被通过一个嵌入层转换成向量表示,然后输入到 Transformer 解码器中,每个解码器层都由多个注意力头和前馈神经网络组成,用于逐步生成下一个词语的概率分布。
2)训练方式
BERT:BERT使用了双向语言模型的训练策略。在输入序列中,BERT随机掩盖一些词语,并让模型预测这些被掩盖的词语。这种方式使BERT能够从上下文中学习词语的语义和语境信息。
GPT:GPT使用了自回归语言模型的训练方式。它通过让模型预测当前位置的词语来学习生成文本的能力。在预训练过程中,GPT逐步生成下一个词语,并优化参数以最大化下一个词语的概率。
3)上下文理解能力
两种基于Transformer架构的预训练模型,它们在上下文理解能力和应用领域上有所不同。
BERT:由于BERT采用双向模型,通过预测被掩盖的词语和判断句子之间的关系。它可以从上下文中获取更丰富的信息,并具有较强的上下文理解能力。这使得BERT在词语级别的任务中表现出色,如命名实体识别、问答等。
GPT:GPT是一个单向模型,它只能依赖已生成的上文来预测下一个词语。在预训练过程中,GPT使用自回归语言模型进行训练,通过逐步生成下一个词语来学习生成连贯的文本。由于单向模型的限制,GPT在生成式任务中表现较好,如对话生成、文本生成等。GPT能够生成具有上下文连贯性和逻辑性的文本,因为它在生成每个词语时都能考虑之前已生成的上文。
4)下游任务适用性
BERT:由于BERT具有强大的上下文理解能力和双向模型的特点,它在各种下游任务中表现优秀,如文本分类、命名实体识别、语义关系判断等。
GPT:GPT主要用于生成式任务,如对话生成、文本生成和机器翻译等。它能够生成自然流畅的文本,但在一些需要输入-输出对齐的任务中效果较弱。
第一阶段,在未标记数据上使用语言建模目标来学习神经网络模型的初始参数
第二阶段,预训练的GPT模型是生成式的,而在具体应用中,可以通过微调(fine-tuning)将GPT用于特定的下游任务。在微调阶段,可以添加任务特定的层或结构,并使用有标签的任务数据来进一步调整模型,使其适应特定任务的要求。
Bert代码
import torch
from torch import nn
from d2l import torch as d2l
#@save
def get_tokens_and_segments(tokens_a, tokens_b=None):
"""获取输入序列的词元及其片段索引"""
tokens = ['<cls>'] + tokens_a + ['<sep>']
# 0和1分别标记片段A和B
segments = [0] * (len(tokens_a) + 2)
if tokens_b is not None:
tokens += tokens_b + ['<sep>']
segments += [1] * (len(tokens_b) + 1)
return tokens, segments
#@save
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
#@save
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):
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是np.array([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
#@save
class NextSentencePred(nn.Module):
"""BERT的下一句预测任务"""
def __init__(self, num_inputs, **kwargs):
super(NextSentencePred, self).__init__(**kwargs)
self.output = nn.Linear(num_inputs, 2)
def forward(self, X):
# X的形状:(batchsize,num_hiddens)
return self.output(X)
#@save
class BERTModel(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,
hid_in_features=768, mlm_in_features=768,
nsp_in_features=768):
super(BERTModel, self).__init__()
self.encoder = BERTEncoder(vocab_size, num_hiddens, norm_shape,
ffn_num_input, ffn_num_hiddens, num_heads, num_layers,
dropout, max_len=max_len, key_size=key_size,
query_size=query_size, value_size=value_size)
self.hidden = nn.Sequential(nn.Linear(hid_in_features, num_hiddens),
nn.Tanh())
self.mlm = MaskLM(vocab_size, num_hiddens, mlm_in_features)
self.nsp = NextSentencePred(nsp_in_features)
def forward(self, tokens, segments, valid_lens=None,
pred_positions=None):
encoded_X = self.encoder(tokens, segments, valid_lens)
if pred_positions is not None:
mlm_Y_hat = self.mlm(encoded_X, pred_positions)
else:
mlm_Y_hat = None
# 用于下一句预测的多层感知机分类器的隐藏层,0是“<cls>”标记的索引
nsp_Y_hat = self.nsp(self.hidden(encoded_X[:, 0, :]))
return encoded_X, mlm_Y_hat, nsp_Y_hat
GPT代码
GPT = Multi-Head Attention + Feed forward + LN层 + 残差
由于Decoder具备文本生成能力,故作为侧重生成式任务的GPT选择了Transformer Decoder部分作为核心架构。
但只保留了多头注意力层Multi-Head Attention层和前馈神经网络Feed forward层,最后再加上求和与归一化的前置LN层 + 残差。
import torch
import torch.nn as nn
from transformers import GPT2Model, GPT2Tokenizer
class GPT2(nn.Module):
def __init__(self, num_layers, d_model, num_heads, d_ff, vocab_size, max_sequence_length):
super(GPT2, self).__init__()
self.tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
self.embedding = nn.Embedding(vocab_size, d_model)
self.transformer = GPT2Model(
num_layers=num_layers,
d_model=d_model,
nhead=num_heads,
dim_feedforward=d_ff,
max_position_embeddings=max_sequence_length
)
self.fc = nn.Linear(d_model, vocab_size)
def forward(self, inputs):
embedded = self.embedding(inputs)
outputs = self.transformer(embedded)
logits = self.fc(outputs.last_hidden_state)
return logits
# GPT-2 hyperparameters
num_layers = 12
d_model = 768
num_heads = 12
d_ff = 3072
vocab_size = 50257
max_sequence_length = 1024
# Create GPT-2 model instance
model = GPT2(num_layers, d_model, num_heads, d_ff, vocab_size, max_sequence_length)
# Example input
input_ids = torch.tensor([[31, 51, 99, 18, 42, 62]]) # Input token IDs
# Forward pass
logits = model(input_ids)
上述代码是一个简化的实现示例,使用了PyTorch和Hugging Face的transformers库。GPT-2模型使用了GPT-2的预训练权重,其中的GPT2Model是GPT-2的主体Transformer模型,GPT2Tokenizer用于将文本转换为模型所需的输入。
版权声明:
作者:Zhang, Hongxing
链接:http://zhx.info/archives/336
来源:张鸿兴的学习历程
文章版权归作者所有,未经允许请勿转载。