随着自然语言处理技术的飞速发展,OpenAI 提出的 GPT 系列模型成为了生成式预训练模型的代表。作为 GPT 系列的两代代表,GPT-1 和 GPT-2 虽然在架构上有着继承关系,但在设计理念和性能上有显著的改进。本文将从模型架构、参数规模、训练数据和实际能力等方面分析 GPT-1 和 GPT-2 的联系与区别。
一、GPT-1 和 GPT-2 的基本联系
- 相同的核心架构:基于 Transformer 的解码器结构
- GPT-1 和 GPT-2 都采用了 Transformer 架构中的解码器部分,取消了编码器部分。这种设计使得模型专注于自回归任务,即通过给定前文预测下一个词。
- 两者均使用多头自注意力机制和前馈网络相结合的模块堆叠。
- 语言建模目标一致
- 两代模型的训练目标都是无监督语言建模(Unsupervised Language Modeling),以最大化给定文本序列的似然概率为优化目标。
- 使用左到右的单向生成方式,从序列的开头逐词预测,适用于语言生成任务。
- 位置嵌入(Positional Embedding)
- 两代模型均使用了位置嵌入,将词汇嵌入(Token Embedding)与位置嵌入相加后作为 Transformer 的输入。
- 残差连接与 LayerNorm
- 残差连接(Residual Connection)和层归一化(Layer Normalization)被广泛用于提升梯度流动和训练稳定性。
二、GPT-1 和 GPT-2 的主要区别
1. 模型规模
GPT-2 的显著改进在于模型规模的扩展:
- GPT-1:只有一个版本,参数规模为 1.1 亿(110M),包含 12 层 Transformer 解码器,每层的隐藏状态维度为 768。
- GPT-2:提供了多个版本,最大参数规模达到 15 亿(1.5B),包含 48 层 Transformer 解码器,每层的隐藏状态维度为 1600,注意力头数从 12 增加到 16。
2. 上下文窗口长度
- GPT-1 的最大上下文长度为 512。
- GPT-2 扩展到了 1024,使得模型可以捕获更长的上下文依赖关系,提升了生成的连贯性和逻辑性。
3. 训练数据集
- GPT-1:训练数据规模较小,主要来自书籍数据集(BooksCorpus)等,包含约 5GB 的文本。
- GPT-2:大幅扩展训练数据,使用了一个名为 WebText 的数据集,包含约 40GB 的高质量互联网文本。WebText 通过过滤低质量内容(如广告和代码)优化了数据质量。
- 这种数据规模和多样性的提升,让 GPT-2 的泛化能力远超 GPT-1。
4. LayerNorm 的位置
- GPT-1 使用了前置 LayerNorm(Pre-Norm),即将 LayerNorm 放在子模块的输入部分。
- GPT-2 改为后置 LayerNorm(Post-Norm),即将 LayerNorm 放在子模块的输出部分。后置 LayerNorm 改善了梯度流动问题,提升了模型的训练稳定性。
5. 语言生成能力
- GPT-2 在语言生成的连贯性、上下文一致性和逻辑性方面大幅超越 GPT-1,尤其是在长文本生成时表现尤为突出。
- GPT-2 具备更强的多任务能力,即使没有专门的微调,也能解决翻译、问答等多种任务(零样本和少样本学习)。
6. 训练优化
- GPT-2 引入了更高效的优化技术,比如改进了学习率调度策略(线性学习率热身和余弦衰减)、更少的 Dropout 使用等。
三、GPT-1 和 GPT-2 的实际意义
1. GPT-1:验证 GPT 架构的有效性
- GPT-1 是生成式预训练模型(Generative Pre-trained Transformer)的首次实践,验证了基于无监督预训练的 Transformer 架构在自然语言处理任务中的潜力。
- 其提出了“预训练 + 微调”的通用框架,为后续模型的快速发展奠定了基础。
2. GPT-2:大规模模型的潜力
- GPT-2 的成功揭示了“更大模型 + 更多数据”在提升自然语言处理能力上的重要性。
- 它的强大能力表明,模型规模的扩大与数据质量的提升可以显著提高模型在语言生成和多任务学习中的表现。
3. 技术传播与影响
- GPT-1 的问世将注意力吸引到生成式语言模型领域,而 GPT-2 的发布则推动了行业对大规模预训练模型的关注,直接影响了后续 GPT-3、ChatGPT 等更强大的模型发展。
四、总结
GPT-1 和 GPT-2 作为两代生成式预训练模型,既有紧密的联系,也展现出明显的区别:
特性 | GPT-1 | GPT-2 |
---|---|---|
参数规模 | 1.1 亿 | 15 亿 |
Transformer 层数 | 12 层 | 48 层(大模型) |
隐藏层维度 | 768 | 1600 |
上下文长度 | 512 | 1024 |
训练数据集 | 5GB | 40GB |
LayerNorm 位置 | 前置 | 后置 |
生成质量 | 一般 | 优秀 |
GPT-1 提供了理论框架,GPT-2 则通过更大的规模、更优的数据和更精细的优化将这种架构的潜力发挥到了极致。两者的进化过程体现了深度学习领域中“大规模预训练模型”的发展思路,也为后续 GPT 系列的发展铺平了道路。
五、参考代码(不完整,仅供理解)
import torch
import torch.nn as nn
import torch.optim as optimclass GPT1Layer(nn.Module):"""GPT-1 的 Transformer 子模块,使用前置 LayerNorm"""def __init__(self, embed_size, num_heads):super(GPT1Layer, self).__init__()self.ln = nn.LayerNorm(embed_size)self.attn = nn.MultiheadAttention(embed_size, num_heads)self.ffn = nn.Sequential(nn.Linear(embed_size, 4 * embed_size),nn.GELU(),nn.Linear(4 * embed_size, embed_size))def forward(self, x):# 前置 LayerNorm + 注意力x_norm = self.ln(x)attn_out, _ = self.attn(x_norm, x_norm, x_norm)x = x + attn_out # 残差连接# 前置 LayerNorm + 前馈网络x_norm = self.ln(x)ffn_out = self.ffn(x_norm)x = x + ffn_out # 残差连接return xclass GPT2Layer(nn.Module):"""GPT-2 的 Transformer 子模块,使用后置 LayerNorm"""def __init__(self, embed_size, num_heads):super(GPT2Layer, self).__init__()self.attn = nn.MultiheadAttention(embed_size, num_heads)self.ln1 = nn.LayerNorm(embed_size)self.ffn = nn.Sequential(nn.Linear(embed_size, 4 * embed_size),nn.GELU(),nn.Linear(4 * embed_size, embed_size))self.ln2 = nn.LayerNorm(embed_size)def forward(self, x):# 注意力 + 残差连接 + 后置 LayerNormattn_out, _ = self.attn(x, x, x)x = x + attn_outx = self.ln1(x)# 前馈网络 + 残差连接 + 后置 LayerNormffn_out = self.ffn(x)x = x + ffn_outx = self.ln2(x)return xclass GPT(nn.Module):"""通用 GPT 模型,允许指定 LayerNorm 逻辑"""def __init__(self, vocab_size, embed_size, num_heads, num_layers, max_len, layer_cls):super(GPT, self).__init__()self.embed = nn.Embedding(vocab_size, embed_size)self.pos_embed = nn.Embedding(max_len, embed_size)self.layers = nn.ModuleList([layer_cls(embed_size, num_heads) for _ in range(num_layers)])self.ln_f = nn.LayerNorm(embed_size) # 用于 GPT-2 的全局 LayerNormself.fc = nn.Linear(embed_size, vocab_size)def forward(self, x):seq_len = x.size(1)pos = torch.arange(seq_len, device=x.device).unsqueeze(0)x = self.embed(x) + self.pos_embed(pos)for layer in self.layers:x = layer(x)x = self.ln_f(x) # GPT-2 的全局 LayerNorm,GPT-1 可视情况移除return self.fc(x)# Hyperparameters for GPT-1 and GPT-2
gpt1_config = {'vocab_size': 30522,'embed_size': 768,'num_heads': 12,'num_layers': 12,'max_len': 512,'layer_cls': GPT1Layer
}gpt2_config = {'vocab_size': 50257,'embed_size': 1600,'num_heads': 25,'num_layers': 48,'max_len': 1024,'layer_cls': GPT2Layer
}# Initialize models
gpt1 = GPT(**gpt1_config)
gpt2 = GPT(**gpt2_config)# Loss function and optimizers
criterion = nn.CrossEntropyLoss()
optimizer1 = optim.Adam(gpt1.parameters(), lr=0.001)
optimizer2 = optim.Adam(gpt2.parameters(), lr=0.001)# Example input (batch_size, seq_len)
batch_size1, batch_size2 = 2, 2
input_ids1 = torch.randint(0, gpt1_config['vocab_size'], (batch_size1, gpt1_config['max_len']))
input_ids2 = torch.randint(0, gpt2_config['vocab_size'], (batch_size2, gpt2_config['max_len']))# Forward pass
outputs1 = gpt1(input_ids1) # Output for GPT-1
outputs2 = gpt2(input_ids2) # Output for GPT-2print(f"GPT-1 Output Shape: {outputs1.shape}") # (batch_size, seq_len, vocab_size)
print(f"GPT-2 Output Shape: {outputs2.shape}") # (batch_size, seq_len, vocab_size)def count_parameters(model):return sum(p.numel() for p in model.parameters() if p.requires_grad)def format_parameters(num_params):if num_params >= 1e9:return f"{num_params / 1e9:.2f}B" # 转换为十亿单位并保留两位小数elif num_params >= 1e6:return f"{num_params / 1e6:.2f}M" # 转换为百万单位并保留两位小数else:return f"{num_params}"# 计算并格式化参数数量
gpt1_params = count_parameters(gpt1)
gpt2_params = count_parameters(gpt2)print(f"GPT-1 Model Parameters: {format_parameters(gpt1_params)}")
print(f"GPT-2 Model Parameters: {format_parameters(gpt2_params)}")
参考
- Improving Language Understanding by Generative Pre-Training (GPT-1)
- Language Models are Unsupervised Multitask Learners (GPT-2)