GPT与自回归语言模型

生成式预训练的强大力量 —— Generative Pre-trained Transformer 深度解析

核心主题: GPT系列模型原理、架构演进与自回归解码技术

主要内容: Transformer解码器架构、因果掩码机制、GPT-1/2/3/4演进路线、自回归解码策略、RLHF与Prompt Engineering

关键词: GPT, 自回归, Transformer解码器, 因果掩码, Few-shot, RLHF, ChatGPT, Prompt, 深度学习, 大语言模型

一、自回归语言模型基础

自回归(Autoregressive)语言模型是自然语言处理领域最核心的建模范式之一。其基本思想是:将文本序列的联合概率分解为条件概率的乘积,即给定上文预测下一个token。数学上,对于一个长度为T的token序列 x = (x₁, x₂, ..., x_T),自回归语言模型将其概率建模为:

P(x) = P(x₁) · P(x₂ | x₁) · P(x₃ | x₁, x₂) · ... · P(x_T | x₁, ..., x_{T-1}) = ∏_{t=1}^{T} P(x_t | x_{<t})

这种从左到右的生成方式与人类阅读和写作的自然顺序高度一致,使得自回归模型在文本生成任务上具有天然优势。与BERT等双向编码器模型不同,自回归解码器在生成时只能依赖左侧上下文,无法"偷看"未来的token——这一约束正是因果掩码(Causal Masking)的体现。

核心概念

  • 自回归建模: 将序列概率分解为条件概率乘积,每个token仅依赖之前已生成的token
  • 因果约束: 生成当前位置时,未来信息不可见,保证生成过程的因果关系
  • Tokenization: 使用BPE(Byte Pair Encoding)或SentencePiece将文本切分为子词单元
  • 最大似然估计: 训练目标为最大化训练语料中序列的对数似然
# PyTorch伪代码:自回归语言模型训练示例 import torch import torch.nn as nn import torch.nn.functional as F class AutoregressiveLM(nn.Module): def __init__(self, vocab_size, d_model, n_layers): super().__init__() self.embedding = nn.Embedding(vocab_size, d_model) self.transformer = nn.TransformerEncoder( nn.TransformerEncoderLayer(d_model, nhead=8), num_layers=n_layers ) self.lm_head = nn.Linear(d_model, vocab_size) def forward(self, input_ids): # input_ids: (batch, seq_len) x = self.embedding(input_ids) # 因果掩码确保每个位置只能看到左侧token causal_mask = nn.Transformer.generate_square_subsequent_mask( input_ids.size(1) ) h = self.transformer(x, mask=causal_mask) logits = self.lm_head(h) # (batch, seq_len, vocab_size) return logits # 训练时:预测每个位置的下一个token def compute_loss(logits, labels): # shift: logits[:, :-1] 预测 labels[:, 1:] shift_logits = logits[:, :-1, :].contiguous() shift_labels = labels[:, 1:].contiguous() loss = F.cross_entropy( shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1) ) return loss

二、Transformer解码器架构

GPT系列模型的核心架构是Transformer解码器。与Transformer原论文中的编码器-解码器结构不同,GPT仅保留了解码器部分,并对自注意力机制施加了因果约束。这使得模型能够高效地进行自回归文本生成。

架构组件详解

  1. Token嵌入层: 将离散的token ID映射为连续向量表示,维度通常为d_model(如GPT-3的12288维)
  2. 位置编码: 为每个位置添加正弦/余弦位置编码或可学习的位置嵌入,使模型感知token顺序
  3. 掩码多头自注意力: 核心组件,每个token通过注意力机制聚合左侧所有token的信息
  4. 前馈神经网络(FFN): 通常为两层MLP,中间维度扩展为4倍d_model,使用GELU激活函数
  5. 层归一化(Layer Norm): 稳定训练过程,GPT-2之后采用Pre-Norm结构(先归一化再进入子层)
  6. 残差连接(Residual Connection): 每一子层输入与输出相加,缓解梯度消失问题
import torch import torch.nn as nn import torch.nn.functional as F import math class CausalSelfAttention(nn.Module): """因果自注意力:每个位置只能attend到当前位置及左侧位置""" def __init__(self, d_model, n_head, dropout=0.1): super().__init__() self.n_head = n_head self.d_head = d_model // n_head self.c_attn = nn.Linear(d_model, 3 * d_model) self.c_proj = nn.Linear(d_model, d_model) self.dropout = nn.Dropout(dropout) # 因果掩码:下三角矩阵 self.register_buffer( "bias", torch.tril(torch.ones(1, 1, 1024, 1024)) ) def forward(self, x): B, T, C = x.shape # batch, seq_len, d_model qkv = self.c_attn(x) q, k, v = qkv.chunk(3, dim=-1) # 分割多头维度 q = q.view(B, T, self.n_head, self.d_head).transpose(1, 2) k = k.view(B, T, self.n_head, self.d_head).transpose(1, 2) v = v.view(B, T, self.n_head, self.d_head).transpose(1, 2) # 计算注意力分数 att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(self.d_head)) # 应用因果掩码 att = att.masked_fill( self.bias[:, :, :T, :T] == 0, float('-inf') ) att = F.softmax(att, dim=-1) att = self.dropout(att) y = att @ v y = y.transpose(1, 2).contiguous().view(B, T, C) y = self.c_proj(y) return y class GPTBlock(nn.Module): """GPT解码器块:因果注意力 + 前馈网络,Pre-Norm结构""" def __init__(self, d_model, n_head, dropout=0.1): super().__init__() self.ln_1 = nn.LayerNorm(d_model) self.attn = CausalSelfAttention(d_model, n_head, dropout) self.ln_2 = nn.LayerNorm(d_model) self.mlp = nn.Sequential( nn.Linear(d_model, 4 * d_model), nn.GELU(), nn.Linear(4 * d_model, d_model), nn.Dropout(dropout) ) def forward(self, x): x = x + self.attn(self.ln_1(x)) # Pre-Norm结构 x = x + self.mlp(self.ln_2(x)) return x

三、因果掩码与从左到右生成

因果掩码(Causal Masking)是GPT架构区别于BERT编码器的关键设计。在自注意力计算中,因果掩码是一个下三角矩阵,使得第i个token只能关注到第1到第i个token(包括自身),而对第i+1到第T个token的注意力分数被设置为负无穷,经过softmax后权重为0。

因果掩码的数学表达

Attention(Q, K, V) = softmax( (QK^T / √d_k) + M ) · V

其中掩码矩阵M为:

M_{ij} = 0, if j ≤ i (允许关注)

M_{ij} = -∞, if j > i (掩码屏蔽)

生成过程详解

在推理(生成)阶段,GPT采用自回归方式逐个生成token:

  1. 以起始token(如<sos>或prompt)作为初始输入
  2. 模型前向传播,输出最后一个位置的logits(词汇表上的概率分布)
  3. 从概率分布中采样或贪心选择下一个token
  4. 将新生成的token拼接到输入序列末尾
  5. 重复步骤2-4,直到遇到结束token或达到最大长度
def greedy_generate(model, prompt_ids, max_len, eos_id): """贪心解码:每一步选择概率最高的token""" model.eval() generated = prompt_ids.clone() with torch.no_grad(): for _ in range(max_len): logits = model(generated) # (1, seq_len, vocab_size) next_logits = logits[:, -1, :] # 取最后一个位置 next_token = next_logits.argmax(dim=-1) # 贪心选择 generated = torch.cat([generated, next_token.unsqueeze(0)], dim=-1) if next_token.item() == eos_id: break return generated # KV Cache优化:避免重复计算历史token的Key和Value def generate_with_kv_cache(model, prompt_ids, max_len): """使用KV Cache加速自回归生成""" past_kv = None generated = prompt_ids.clone() for step in range(max_len): if step == 0: logits, past_kv = model(generated, use_cache=True) else: # 仅输入当前新token,复用过去KV logits, past_kv = model( next_token, past_key_values=past_kv, use_cache=True ) next_token = logits[:, -1, :].argmax(dim=-1) generated = torch.cat([generated, next_token], dim=-1) return generated

"自回归生成就像是人类写作的过程——每写一个词,都要基于已经写出的所有词来决定下一个词是什么。GPT将这种直觉形式化为一个数学上优雅的条件概率链式分解。"

四、GPT-1/2/3演进之路

GPT系列模型的演进是深度学习历史上最具影响力的发展轨迹之一。从2018年的GPT-1到2020年的GPT-3,模型规模增长了超过1000倍,能力也从最初的"尚可"发展到令人惊叹的水平。

特性 GPT-1 (2018) GPT-2 (2019) GPT-3 (2020)
参数量 117M 1.5B 175B
层数 12 48 96
d_model 768 1600 12288
注意力头数 12 25 96
训练数据 BookCorpus (~5GB) WebText (~40GB) Common Crawl (~570GB+)
核心创新 生成式预训练+微调 Zero-shot能力发现 In-Context Learning

GPT-1:开创性的预训练-微调范式

GPT-1验证了一个关键假设:在大型无标注语料上预训练语言模型,然后在下游任务上进行微调,可以显著优于从头训练的模型。它使用12层Transformer解码器,在BookCorpus上训练,在多个NLP基准上取得了当时最先进的结果。

GPT-2:零样本能力的发现

GPT-2将参数量扩大到1.5B,训练数据也从BookCorpus扩展到从Reddit高赞链接爬取的WebText。GPT-2最重要的发现是:随着模型规模增大,语言模型自动获得了零样本(Zero-shot)任务执行能力——可以通过特定prompt格式触发模型完成翻译、问答、摘要等任务,无需额外训练。

GPT-2的关键公式变化

GPT-1的训练目标:P(output | input),通过微调适配下游任务

GPT-2的训练目标:P(output | input, task_prompt),通过prompt设计引出任务能力

GPT-3的训练目标:P(output | input, task_prompt, examples),通过上下文中提供的示例进行学习(In-Context Learning)

GPT-3:规模的力量

GPT-3是真正的里程碑,1750亿参数量使其成为当时最大的神经网络。它的核心贡献不是架构创新(基本沿用GPT-2的架构),而是证明了规模缩放律(Scaling Laws):随着模型规模、数据量和计算量的增大,模型能力呈现可预测的提升。GPT-3首次展示了强大的Few-shot In-Context Learning能力,仅需在prompt中提供几个示例就能执行复杂任务。

GPT-3的三种学习范式

  • Zero-shot: 只给指令,不给示例。"Translate English to Chinese: Hello world →"
  • One-shot: 给一个示例+指令。"Translate English to Chinese: Hello → 你好。World →"
  • Few-shot: 给多个示例(通常3-64个)。在prompt中嵌入示例对,引导模型完成任务

五、GPT-3核心技术:Prompt与In-Context Learning

In-Context Learning(上下文学习)

In-Context Learning是GPT-3最令人惊讶的能力。模型不需要更新任何参数,只需要在输入中提供任务描述和若干示例,就能自动"理解"任务要求并执行。这与传统的机器学习训练有着本质区别:

# In-Context Learning 示例:情感分类 prompt = """ Classify the sentiment of the following movie reviews. Review: This movie was absolutely fantastic! I loved every minute. Sentiment: Positive Review: What a waste of time. The plot made no sense at all. Sentiment: Negative Review: The acting was decent but the story was predictable. Sentiment: Neutral Review: I have never been so bored in a theater. Terrible. Sentiment: """ # 模型会根据prompt中给出的示例模式,自动推断最后一个样本的情绪 # 输出: Negative

Prompt工程的核心要素

  1. 指令清晰: 明确告知模型要完成的任务,避免歧义
  2. 示例选择: 选择与目标样本接近的示例,覆盖多种情况
  3. 格式一致性: 输入和输出格式保持一致,让模型捕捉到模式
  4. 示例数量: 通常3-8个示例效果最佳,过多可能引入噪声
  5. 示例顺序: 随机排列示例比按类别聚集效果更好

思维链(Chain-of-Thought, CoT)

思维链提示是一种增强大型语言模型推理能力的技术。通过在prompt中提供包含中间推理步骤的示例,引导模型在回答前"思考"推理过程,显著提升了数学、逻辑和常识推理任务的准确率。

# 标准Few-shot提示(直接回答) Q: Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many tennis balls does he have now? A: The answer is 11. # 思维链Few-shot提示(展示推理过程) Q: Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many tennis balls does he have now? A: Roger starts with 5 balls. 2 cans of 3 tennis balls each is 2 x 3 = 6 balls. 5 + 6 = 11. The answer is 11. Q: The cafeteria had 23 apples. They used 20 to make lunch and bought 6 more. How many apples do they have? A: They started with 23 apples. They used 20, so 23 - 20 = 3. They bought 6 more, so 3 + 6 = 9. The answer is 9.

Zero-shot CoT:让模型"一步步思考"

一个有趣的发现是,即使在prompt中不加任何示例,仅仅在问题后面添加"Let's think step by step"这句话,就能显著提升模型在推理任务上的表现。这种简单而强大的技术被称为Zero-shot Chain-of-Thought。

六、自回归解码策略

在自回归生成中,从模型输出的概率分布中选择下一个token的策略对生成质量有决定性影响。不同的解码策略在多样性质量之间做出不同的权衡。

1. Greedy Search(贪心搜索)

每一步选择概率最高的token。简单高效,但容易产生重复和乏味的文本,因为一旦选错就无法回溯。

2. Beam Search(束搜索)

维护beam_size个候选序列,每一步扩展所有候选,保留全局概率最高的beam_size个序列。适用于机器翻译、摘要等需要高确定性的任务。

3. Top-K采样

从概率最高的K个token中采样。固定K值的缺点是:在概率分布平滑时可能截断合理token,在分布尖锐时可能包含过低概率token。

4. Top-P(Nucleus)采样

选择累积概率达到阈值P的最小token集合(即核心集),然后从核心集中重新归一化后采样。自适应地调整候选集大小,比Top-K更灵活。

5. Temperature采样

通过temperature参数τ缩放logits后再应用softmax:

import torch import torch.nn.functional as F def top_k_top_p_sampling(logits, k=50, p=0.9, temperature=1.0): """Top-K + Top-P (Nucleus) 采样""" # Temperature缩放 logits = logits / temperature # Top-K过滤 top_k_logits, top_k_indices = torch.topk(logits, k, dim=-1) filtered_logits = torch.full_like(logits, float('-inf')) filtered_logits.scatter_(-1, top_k_indices, top_k_logits) # Top-P (Nucleus) 过滤 sorted_logits, sorted_indices = torch.sort(filtered_logits, descending=True) cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1) # 移除累积概率超过p的token(保留第一个超过的) sorted_mask = cumulative_probs - sorted_probs >= p # 假设sorted_probs已计算 sorted_mask[..., 1:] = sorted_mask[..., :-1].clone() sorted_mask[..., 0] = False indices_to_remove = sorted_mask.scatter(-1, sorted_indices, sorted_mask) filtered_logits[indices_to_remove] = float('-inf') # 从过滤后的分布采样 probs = F.softmax(filtered_logits, dim=-1) next_token = torch.multinomial(probs, num_samples=1) return next_token def repetition_penalty(logits, input_ids, penalty=1.1): """重复惩罚:降低已生成token的采样概率""" for token_id in input_ids[0]: if logits[0, token_id] < 0: logits[0, token_id] *= penalty else: logits[0, token_id] /= penalty return logits

解码策略对比

策略 多样性 质量 适用场景
Greedy Search 中(易重复) 确定性任务(翻译)
Beam Search 高(全局最优) 翻译、摘要
Top-K (K=40-50) 通用对话
Top-P (p=0.9-0.95) 中高 创意写作
Temperature (τ=0.7-0.9) 可控 可控 配合Top-K/P使用

七、InstructGPT与RLHF

GPT-3虽然能力强,但存在与人类意图不一致的问题:可能生成有害、虚假或无用的内容。InstructGPT/ChatGPT通过基于人类反馈的强化学习(Reinforcement Learning from Human Feedback, RLHF)解决了这一问题,使模型输出更符合人类偏好。

RLHF三阶段训练流程

  1. 阶段一:监督微调(SFT)

    收集人工编写的指令-回答对(prompt, response),对GPT-3进行监督微调。这一步建立基础的任务理解和遵循能力。

  2. 阶段二:奖励模型训练(RM Training)

    让标注员对SFT模型生成的多个回答进行排序(如"最好"、"中等"、"最差"),训练一个奖励模型Reward Model来预测人类偏好的分数。

  3. 阶段三:PPO强化学习

    使用PPO(Proximal Policy Optimization)算法,以奖励模型的分数为奖励信号,微调SFT模型。同时加入KL散度惩罚项,防止模型偏离初始SFT模型过远(避免"奖励黑客"问题)。

# PPO-ptx 训练目标伪代码 def ppo_train_step(policy_model, ref_model, reward_model, prompts, kl_coeff=0.1, clip_epsilon=0.2): # 生成回答 responses = policy_model.generate(prompts) # 计算奖励分数 rewards = reward_model(prompts, responses) # 计算KL散度惩罚(与参考模型的差异) policy_log_probs = policy_model.log_prob(prompts, responses) ref_log_probs = ref_model.log_prob(prompts, responses) kl_div = policy_log_probs - ref_log_probs # 组合奖励:奖励 - KL惩罚 combined_rewards = rewards - kl_coeff * kl_div # PPO clipped surrogate objective advantages = compute_advantages(combined_rewards) ratio = torch.exp(policy_log_probs - old_log_probs) clipped_ratio = torch.clamp(ratio, 1 - clip_epsilon, 1 + clip_epsilon) policy_loss = -torch.min(ratio * advantages, clipped_ratio * advantages) # 可选:添加预训练损失(PPO-ptx)防止灾难性遗忘 # ptx_loss = cross_entropy(pretrain_logits, pretrain_labels) # total_loss = policy_loss + ptx_coeff * ptx_loss return policy_loss.mean()

RLHF的关键技术细节

  • 奖励模型: 通常是一个参数量较小的GPT模型(如6B),在其顶部加一个线性层输出标量分数
  • 排名损失: 奖励模型训练使用pairwise ranking loss,最大化好回答和差回答之间的分数差距
  • KL散度约束: 防止RL训练导致模型输出崩溃(输出高奖励但语义不连贯的内容)
  • PPO-clip: 限制策略更新的步长,提高训练稳定性
  • PPO-ptx: 在RL目标中加入预训练损失混合项,缓解灾难性遗忘

从InstructGPT到ChatGPT

ChatGPT在InstructGPT的基础上针对对话场景进行了优化:

八、GPT-4多模态与安全对齐

多模态能力

GPT-4最重要的突破是多模态理解——能够同时处理文本和图像输入。用户可以上传图片并提问,GPT-4能够"理解"图像内容(包括图表、手写文字、照片等)并基于图像信息进行推理和回答。

GPT-4多模态架构推测

虽然OpenAI未公开完整技术细节,但业界普遍认为GPT-4采用了类似Flamingo或BLIP-2的架构:

  • 使用独立的视觉编码器(如ViT)提取图像特征
  • 通过Q-Former或交叉注意力机制将视觉特征映射到语言模型的embedding空间
  • 语言模型部分仍为标准的自回归Transformer解码器
  • 视觉和文本信息在注意力层进行融合

安全对齐

GPT-4在安全性方面进行了大量投入,包括:

安全对齐的挑战

  1. 越狱攻击(Jailbreaking): 用户通过精心设计的prompt绕过安全限制,如角色扮演、假设场景等
  2. 对抗性攻击: 在输入中添加微弱扰动导致模型输出有害内容
  3. 数据污染: 训练数据中隐含的偏见和有害知识
  4. 对齐税: 过度对齐可能导致模型在某些任务上表现下降(如创造性任务)

九、Prompt Engineering实战

Prompt Engineering(提示工程)是一门通过设计输入提示来引导大语言模型输出期望结果的技术。随着GPT系列模型的普及,提示工程已成为与大型语言模型交互的核心技能。

经典提示技巧

# 1. 角色提示 (Role Prompting) prompt = """ 你是一位资深的中医专家。请根据以下症状分析可能的原因并给出调理建议。 症状:经常感到疲劳,手脚冰凉,面色苍白,容易头晕。 """ # 2. 分步提示 (Step-by-step) prompt = """ 请按以下步骤分析这个问题: 1. 首先,确定问题的关键因素 2. 然后,列出可能的解决方案 3. 最后,推荐最优方案并说明理由 """ # 3. 格式约束 (Format Control) prompt = """ 请以JSON格式输出,包含以下字段: { "药物名称": "", "性味": "", "归经": "", "功效": [], "主治": [] } """ # 4. 多轮对话提示 (Few-shot Dialogue) prompt = """ User: 我的眼睛最近很干涩,怎么办? Assistant: 建议您: 1. 每工作45分钟休息5分钟,远眺放松 2. 使用人工泪液缓解干涩 3. 多吃富含维生素A的食物 User: 晚上总是失眠,有什么好办法? Assistant: 以下是改善失眠的建议: 1. 保持规律的作息时间 2. 睡前1小时避免使用电子产品 3. 可以尝试冥想或深呼吸放松 4. 避免咖啡因和酒精 User: 最近总是头痛,是怎么回事? Assistant: """

高级提示技巧

  1. 思维树(Tree-of-Thought, ToT): 让模型同时探索多条推理路径,并在关键步骤进行自我评估和回溯,适合需要规划的复杂问题
  2. 自我一致性(Self-Consistency): 多次采样同一prompt,选择出现频率最高的答案,提高推理稳定性和准确率
  3. 主动提示(Active Prompt): 让模型自己生成需要澄清的问题,然后基于补充信息继续推理
  4. 从简到繁(Least-to-Most): 先让模型解决简化版问题,再逐步增加复杂度,适合需要逐步推理的复杂任务
  5. 反向提示(Reverse Prompt): 让模型从结论反推原因或步骤,验证逻辑一致性

Prompt Engineering最佳实践

  • 明确具体: 模糊的指令得到模糊的回答,具体的问题得到精确的答案
  • 提供上下文: 给模型足够的背景信息,减少歧义
  • 分解复杂任务: 将大任务分解为小步骤,引导模型逐步完成
  • 指定输出格式: 明确要求JSON、Markdown、列表等格式
  • 添加负面提示: 明确指出不想要的输出类型("不要给出医疗建议"、"不要编造事实")
  • 迭代优化: 根据模型输出调整prompt,逐步逼近理想结果

十、核心要点总结

十一、进一步思考

GPT系列模型的演进不仅展示了深度学习在自然语言处理领域的巨大潜力,更引发了对人工智能本质的深层思考:

启发与展望

  • 涌现能力: 为什么大语言模型在达到一定规模后会"涌现"出小模型不具备的能力?这是偶然还是必然?
  • 推理vs记忆: 模型展现的推理能力究竟是真正的逻辑推理,还是对训练数据中推理模式的"模式匹配"?
  • Scaling Law的边界: 继续扩大模型规模和数据量是否会产生更强的能力?是否存在收益递减的临界点?
  • 架构改进: MoE混合专家、长上下文、稀疏注意力等架构改进如何进一步提升模型效率?
  • 多模态融合: 未来模型将不仅理解文本和图像,还能处理视频、音频、3D等多模态信息
  • Agent化: 大语言模型从对话系统向能自主执行任务的Agent演进,结合工具使用和规划能力