GPT-2 案例详解:Decoder-only 自回归模型的完整生命周期

本文档以 GPT-2 模型为例,将 Transformers 框架的所有模块串联起来,重点展示 Decoder-only 自回归模型从配置加载、分词编码、前向传播、注意力机制、自回归生成到训练推理的完整生命周期。
源码文件:


相关文章:
Hugging Face Transformers 源码全景解读
01-Hugging Face Transformers 核心基础设施深度分析
02-Hugging Face Transformers 配置系统深度分析
03-Hugging Face Transformers 模型系统深度分析
04-Hugging Face Transformers 注意力与掩码系统深度分析
05-Hugging Face Transformers 缓存系统深度分析
06-Hugging Face Transformers 生成系统深度分析
07-Hugging Face Transformers 分词器系统深度分析
08-Hugging Face Transformers 多模态处理系统深度分析
09-Hugging Face Transformers 训练系统深度分析
10-Hugging Face Transformers 量化系统深度分析
11-Hugging Face Transformers 分布式与并行系统深度分析
12-Hugging Face Transformers之Pipeline 推理管道深入分析
13-Hugging Face Transformers之AutoModel 自动分发机制深入分析
14-Hugging Face Transformers 模型实现模式深度分析
15-Hugging Face Transformers之CLI 与工具架构总览
16-Hugging Face Transformers之测试体系架构总览
17-Hugging Face Transformers之BERT 案例详解:Transformers 框架全模块串联
18-Hugging Face Transformers之GPT-2 案例详解:Decoder-only 自回归模型的完整生命周期
19-Hugging Face Transformers之Qwen3.5-MoE 系列详解:混合专家 + 线性注意力 + 多模态的完整生命周期

1. GPT-2 在 Transformers 中的定位

GPT-2 是 OpenAI 于 2019 年发布的 Decoder-only 因果语言模型,采用自回归生成范式:每次只预测下一个 token,已生成的内容作为上下文参与后续预测。与 BERT 等 Encoder 模型不同,GPT-2 使用**因果掩码(Causal Mask)**确保每个位置只能看到自身及之前的 token。

GPT-2 的一个标志性设计是使用 Conv1D 线性层(而非标准 nn.Linear),这是 OpenAI 原始实现的遗留设计——权重矩阵的形状为 (in_features, out_features),与 nn.Linear(out_features, in_features) 互为转置。

架构定位图

Decoder-only 因果语言模型家族

Conv1D→nn.Linear
Post-Norm→Pre-Norm

绝对位置→RoPE
GELU→SwiGLU

架构继承
规模扩展

GPT-2
2019 · OpenAI
Conv1D + Post-Norm
768/1024/1280/1600

GPT-Neo / GPT-J
2021 · EleutherAI
nn.Linear + Parallel Attention

LLaMA
2023 · Meta
RMSNorm + SwiGLU + RoPE

Qwen 系列
2023- · 阿里
RMSNorm + SwiGLU + RoPE

核心特征总结

特征 GPT-2 LLaMA(对比)
线性层 Conv1D(权重转置) nn.Linear
归一化 LayerNorm + Post-Norm RMSNorm + Pre-Norm
激活函数 gelu_new(近似 GELU) silu(SwiGLU)
位置编码 可学习绝对位置 wpe 旋转位置编码 RoPE
注意力缩放 scale_attn_weights + 可选层逆缩放 标准 head_dim^-0.5
权重绑定 lm_head.weight ↔ wte.weight 同样绑定

2. Config 定义与特殊设计

GPT2Config 继承自 PreTrainedConfig,定义于 configuration_gpt2.py。它使用 @strict 装饰器(来自 huggingface_hub)确保数据类字段的严格类型检查,并通过 attribute_map 将 GPT-2 原始命名映射到 Transformers 统一命名。

关键参数解析

# 源自 configuration_gpt2.py L78-L103
vocab_size: int = 50257              # 词表大小
n_positions: int = 1024              # 最大位置编码长度
n_embd: int = 768                    # 隐藏层维度
n_layer: int = 12                    # Transformer 层数
n_head: int = 12                     # 注意力头数
n_inner: int | None = None           # MLP 中间层维度,默认 4 * n_embd
activation_function: str = "gelu_new" # 近似 GELU 激活
scale_attn_weights: bool = True      # 是否缩放注意力权重(1/√d_k)
reorder_and_upcast_attn: bool = False # 混合精度下重排序并上溯注意力计算
add_cross_attention: bool = False    # 是否添加交叉注意力(用于编码器-解码器场景)
tie_word_embeddings: bool = True     # 权重绑定:lm_head ↔ wte

Config 类图

PreTrainedConfig

+model_type: str

+is_decoder: bool

+from_pretrained()

+to_dict()

GPT2Config

+vocab_size: int = 50257

+n_positions: int = 1024

+n_embd: int = 768

+n_layer: int = 12

+n_head: int = 12

+n_inner: int | None

+activation_function: str

+scale_attn_weights: bool

+reorder_and_upcast_attn: bool

+add_cross_attention: bool

+tie_word_embeddings: bool

+attribute_map: dict

attribute_map 将 GPT-2 原始命名\n映射到 Transformers 统一命名:\nhidden_size → n_embd\nnum_attention_heads → n_head\nnum_hidden_layers → n_layer\nmax_position_embeddings → n_positions

Conv1D vs nn.Linear 对比图

Conv1D(GPT-2 使用)

nn.Linear

数学等价
xW^T ≡ x·W_transposed

输入 x
(batch, seq, in_features)

权重 W
shape: (out_features, in_features)

输出 y = xW^T + b
(batch, seq, out_features)

输入 x
(batch, seq, nx)

权重 W
shape: (nx, nf) ← 转置!

输出 y = xW + b
(batch, seq, nf)

Conv1D 的核心差异(定义于 pytorch_utils.py L97-L123):

class Conv1D(nn.Module):
    def __init__(self, nf, nx):
        super().__init__()
        self.nf = nf
        self.nx = nx
        # 关键:权重形状为 (nx, nf),即 (in_features, out_features)
        # 而 nn.Linear 的权重形状为 (out_features, in_features)
        self.weight = nn.Parameter(torch.empty(nx, nf))
        self.bias = nn.Parameter(torch.zeros(nf))
        nn.init.normal_(self.weight, std=0.02)

    def forward(self, x):
        size_out = x.size()[:-1] + (self.nf,)
        # torch.addmm(bias, input, weight) 计算 bias + input @ weight
        # 等价于 nn.Linear 的 F.linear(x, W.T, b) = x @ W.T + b
        x = torch.addmm(self.bias, x.view(-1, x.size(-1)), self.weight)
        x = x.view(size_out)
        return x

3. from_pretrained 完整时序

GPT2LMHeadModel.from_pretrained('gpt2') 到模型就绪,涉及多个关键步骤。

时序图

HuggingFace Hub PreTrainedModel GPT2LMHeadModel GPT2Config AutoModelForCausalLM 用户代码 HuggingFace Hub PreTrainedModel GPT2LMHeadModel GPT2Config AutoModelForCausalLM 用户代码 Conv1D 权重无需转置 因为 checkpoint 已是 (nx, nf) 格式 lm_head.weight ← transformer.wte.weight _tied_weights_keys 指定绑定关系 from_pretrained('gpt2') 下载 config.json config.json GPT2Config.from_pretrained() config 实例 根据 model_type='gpt2' 分发到 GPT2LMHeadModel GPT2LMHeadModel.from_pretrained('gpt2') PreTrainedModel.from_pretrained() 1. 解析模型架构 _load_pretrained_model() 2. 下载权重文件 model.safetensors 权重 state_dict 3. 加载权重到模型 model.load_state_dict() 4. 权重绑定处理 tie_weights() 5. 设备放置与 dtype 转换 模型就绪 可用模型实例

权重绑定机制

GPT2LMHeadModel 通过 _tied_weights_keys 声明权重绑定关系(modeling_gpt2.py L646):

class GPT2LMHeadModel(GPT2PreTrainedModel, GenerationMixin):
    _tied_weights_keys = {"lm_head.weight": "transformer.wte.weight"}

    def __init__(self, config):
        super().__init__(config)
        self.transformer = GPT2Model(config)
        # lm_head 使用 nn.Linear,权重形状 (vocab_size, n_embd)
        self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False)
        self.post_init()  # 在此触发 tie_weights()

绑定过程:lm_head.weight(形状 (50257, 768))与 transformer.wte.weight(形状 (50257, 768))共享同一存储,修改一个另一个同步变化。

Conv1D 权重加载的特殊处理

由于 GPT-2 的 checkpoint 中 Conv1D 权重已经以 (nx, nf) 格式存储,加载时无需额外转置。但需注意:

  • c_attn.weight:形状 (768, 2304),一次投影出 Q/K/V
  • c_proj.weight:形状 (768, 768),注意力输出投影
  • c_fc.weight:形状 (768, 3072),MLP 上投影
  • c_proj.weight(MLP):形状 (3072, 768),MLP 下投影

4. Tokenizer 编码流程

GPT2Tokenizer 定义于 tokenization_gpt2.py,继承自 TokenizersBackend,使用 Byte-Level BPE 分词算法。

核心设计特点

  1. ByteLevel 预处理:将所有字符先转为 UTF-8 字节,再映射到 Unicode 字符,确保任何文本都可编码(无 <unk> 问题)
  2. 无 [CLS]/[SEP]:GPT-2 没有 BERT 风格的特殊分隔 token,只有 <|endoftext|> 作为 BOS/EOS
  3. 空格敏感:词首有无空格会产生不同 token(如 "Hello" vs " Hello"
# 源自 tokenization_gpt2.py L94-L129
class GPT2Tokenizer(TokenizersBackend):
    vocab_files_names = VOCAB_FILES_NAMES  # {"vocab_file": "vocab.json", "merges_file": "merges.txt"}
    model_input_names = ["input_ids", "attention_mask"]
    model = BPE  # 使用 BPE 模型

    def __init__(self, vocab, merges, errors="replace",
                 unk_token="<|endoftext|>", bos_token="<|endoftext|>",
                 eos_token="<|endoftext|>", pad_token=None,
                 add_prefix_space=False, **kwargs):
        self.add_prefix_space = add_prefix_space
        self._vocab = vocab if vocab is not None else {}
        self._merges = merges or []
        # 构建 tokenizers 库的 BPE 模型
        self._tokenizer = Tokenizer(BPE(
            vocab=self._vocab, merges=self._merges,
            dropout=None, continuing_subword_prefix="",
            end_of_word_suffix="", fuse_unk=False,
        ))
        # ByteLevel 预分词器:将文本转为字节级表示
        self._tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(
            add_prefix_space=add_prefix_space
        )
        # ByteLevel 解码器:将字节级表示还原为文本
        self._tokenizer.decoder = decoders.ByteLevel()

编码流程图

原始文本
'Hello world'

ByteLevel 预处理
pre_tokenizers.ByteLevel

1. 按 Unicode 分割
识别词边界(空格→Ġ前缀)

2. 字节映射
每个字符→UTF-8字节→Unicode映射
'H'→'H', 'e'→'e', ' '→'Ġ'

BPE 分词
Tokenizer(BPE)

1. 初始化:每个字节映射为子词

2. 迭代合并
按 merges.txt 中的优先级
合并最高频的相邻子词对

3. 输出子词序列
['Hello', 'Ġworld']

词表查找
vocab.json

input_ids: [15496, 995]

attention_mask 生成
默认全1(无padding时)

attention_mask: [1, 1]

模型输入
input_ids + attention_mask

空格敏感性示例

tokenizer = GPT2Tokenizer.from_pretrained("openai-community/gpt2")
tokenizer("Hello world")["input_ids"]     # [15496, 995]    → "Hello" + "Ġworld"
tokenizer(" Hello world")["input_ids"]    # [18435, 995]    → "ĠHello" + "Ġworld"
# 注意:"Hello" 和 " Hello" 编码为不同的 token!

5. 模型前向传播全链路

input_idslogits 的完整数据流,定义于 modeling_gpt2.pyGPT2LMHeadModel.forward()GPT2Model.forward()

数据流图

input_ids
(batch, seq_len)

wte: nn.Embedding
词嵌入
(batch, seq_len, 768)

position_ids
自动生成
(1, seq_len)

wpe: nn.Embedding
位置嵌入
(1, seq_len, 768)

⊕ 相加
hidden = wte + wpe

drop: Dropout
embd_pdrop=0.1

GPT2Block #0
ln_1 → Attn → + → ln_2 → MLP → +

GPT2Block #1
ln_1 → Attn → + → ln_2 → MLP → +

...

GPT2Block #11
ln_1 → Attn → + → ln_2 → MLP → +

ln_f: LayerNorm
最终层归一化

lm_head: nn.Linear
(768, 50257, bias=False)

logits
(batch, seq_len, 50257)

单层 GPT2Block 内部结构图

保存 residual

保存 residual

hidden_states
(batch, seq, 768)

ln_1: LayerNorm

GPT2Attention
c_attn → Q/K/V split →
Causal Attention → c_proj

+ 残差连接
hidden = attn_out + residual

ln_2: LayerNorm

GPT2MLP
c_fc → gelu_new → c_proj

+ 残差连接
hidden = mlp_out + residual

输出 hidden_states
(batch, seq, 768)

对应源码(modeling_gpt2.py L262-L309):

class GPT2Block(GradientCheckpointingLayer):
    def forward(self, hidden_states, past_key_values=None,
                attention_mask=None, ...):
        # Post-Norm:先归一化,再注意力,再残差
        residual = hidden_states
        hidden_states = self.ln_1(hidden_states)
        attn_output, _ = self.attn(hidden_states, ...)
        hidden_states = attn_output + residual  # 第一个残差连接

        # Post-Norm:先归一化,再MLP,再残差
        residual = hidden_states
        hidden_states = self.ln_2(hidden_states)
        feed_forward_hidden_states = self.mlp(hidden_states)
        hidden_states = residual + feed_forward_hidden_states  # 第二个残差连接

        return hidden_states

Post-Norm 架构对比图

LLaMA: Pre-Norm

x

RMSNorm(x)

Attention(RMSNorm(x))

x + Attention(RMSNorm(x))

RMSNorm(x + Attn_out)

MLP(RMSNorm(x + Attn_out))

x + Attn_out + MLP(RMSNorm(...))

输出

GPT-2: Post-Norm

x

Attention(x)

x + Attention(x)

LayerNorm(x + Attention(x))

MLP(LN_out)

LN_out + MLP(LN_out)

LayerNorm(LN_out + MLP(LN_out))

输出

Post-Norm vs Pre-Norm:GPT-2 采用 Post-Norm(归一化在残差之后),训练时梯度可能不稳定;LLaMA 采用 Pre-Norm(归一化在子层之前),训练更稳定,是现代 LLM 的主流选择。


6. 注意力系统运作

GPT2Attention 定义于 modeling_gpt2.py L75-L226,是 GPT-2 的核心计算模块。

注意力前向流程图

hidden_states
(batch, seq, 768)

c_attn: Conv1D(2304, 768)
一次投影 Q/K/V

split(768, dim=2)
→ Q, K, V 各 (batch, seq, 768)

Q.view + transpose
(batch, num_heads, seq, head_dim)

K.view + transpose
(batch, num_heads, seq, head_dim)

V.view + transpose
(batch, num_heads, seq, head_dim)

KV Cache 更新
past_key_values.update(K, V)

K_full (含历史)

V_full (含历史)

attn_weights = Q @ K_full^T × scaling
scaling = 1/√head_dim

+ 因果掩码
create_causal_mask()

Softmax(dim=-1)

attn_dropout

attn_output = weights @ V_full
(batch, num_heads, seq, head_dim)

reshape → (batch, seq, 768)

c_proj: Conv1D(768, 768)
输出投影

resid_dropout

attn_output
(batch, seq, 768)

因果掩码生成图

因果掩码由 masking_utils.py 中的 create_causal_mask() 生成,确保每个位置只能关注自身及之前的 token:

True(默认)

False

eager

sdpa

flash_attention_2

create_causal_mask()
masking_utils.py L894

config.is_causal?

causal_mask_function
kv_idx <= q_idx

create_bidirectional_mask
双向掩码

注意力实现类型?

eager_mask()
生成 4D float 掩码
0(可见)/-inf(屏蔽)

sdpa_mask()
生成 4D bool 掩码
True(可见)/False(屏蔽)

flash_attention_mask()
返回 2D 掩码或 None

4D 掩码
(batch, 1, q_len, kv_len)

因果掩码矩阵示意(5×5):

位置  0  1  2  3  4
 0 [ ■  ⬚  ⬚  ⬚  ⬚ ]    ■ = 可见(0)
 1 [ ■  ■  ⬚  ⬚  ⬚ ]    ⬚ = 屏蔽(-inf)
 2 [ ■  ■  ■  ⬚  ⬚ ]
 3 [ ■  ■  ■  ■  ⬚ ]
 4 [ ■  ■  ■  ■  ■ ]

KV Cache 增量更新时序图

DynamicCache GPT2Attention GPT2Model DynamicCache GPT2Attention GPT2Model === 首次前向(Prefill) === === 生成第1个token === 拼接历史: K_full = cat(K_old, K_new) → (batch, 12, 6, 64) === 生成第2个token === K_full → (batch, 12, 7, 64) hidden_states (batch, 5, 768) c_attn → Q, K, V K: (batch, 12, 5, 64) V: (batch, 12, 5, 64) update(K, V, layer_idx=0) K_full=(batch,12,5,64), V_full=(batch,12,5,64) Q @ K_full^T → softmax → @ V_full attn_output (batch, 5, 768) hidden_states (batch, 1, 768) c_attn → Q, K, V K_new: (batch, 12, 1, 64) V_new: (batch, 12, 1, 64) update(K_new, V_new, layer_idx=0) K_full=(batch,12,6,64), V_full=(batch,12,6,64) Q @ K_full^T → softmax → @ V_full attn_output (batch, 1, 768) hidden_states (batch, 1, 768) update(K_new, V_new, layer_idx=0) K_full=(batch,12,7,64), V_full=(batch,12,7,64) attn_output (batch, 1, 768)

KV Cache 的关键源码(modeling_gpt2.py L193-L199):

# 在 GPT2Attention.forward() 中
if (past_key_values is not None and not is_cross_attention) or (
    past_key_values is not None and is_cross_attention and not is_updated
):
    # 将新的 K/V 与缓存中的历史 K/V 拼接
    key_states, value_states = curr_past_key_values.update(
        key_states, value_states, self.layer_idx
    )

7. generate() 生成全流程

GPT2LMHeadModel 继承了 GenerationMixinmodeling_gpt2.py L645),其 generate() 方法定义于 generation/utils.py

生成循环时序图

渲染错误: Mermaid 渲染失败: Parse error on line 16: ...sk() Note over Loop,Cache: === Pref ---------------------^ Expecting 'ACTOR', got 'loop'

辅助解码流程图(Speculative Decoding)

当使用辅助模型进行推测解码时,流程如下:

全部接受

第 j 个被拒绝

主模型: GPT2LMHeadModel

辅助模型: assistant_model

辅助模型生成 K 个候选 token

主模型验证 K 个候选 token
一次前向传播

验证结果

接受 K 个 token
+ 继续生成

接受前 j-1 个 token
+ 从主模型采样第 j 个

继续下一轮推测


8. 训练流程

训练循环时序图

渲染错误: Mermaid 渲染失败: Parse error on line 19: ..._labels Loss-->>Opt: loss 标量 No ----------------------^ Expecting '+', '-', '()', 'ACTOR', got 'opt'

权重绑定梯度流图

反向传播

梯度累加
同一参数

前向传播

共享存储

wte: nn.Embedding
weight: (50257, 768)

lm_head: nn.Linear
weight: (50257, 768)

lm_head.weight.grad
来自 logits 的梯度

wte.weight.grad
来自嵌入层的梯度

共享权重
梯度 = lm_head梯度 + wte梯度

optimizer.step()
一次性更新共享权重

损失计算的关键源码(modeling_gpt2.py L708-L716):

# GPT2LMHeadModel.forward()
loss = None
if labels is not None:
    # labels 自动 shift:logits 取前 n-1 位,labels 取后 n-1 位
    # 即:用位置 i 的输出预测位置 i+1 的 token
    loss = self.loss_function(
        logits,
        labels,
        vocab_size=self.config.vocab_size,
        **kwargs,
    )

GPT-2 特殊的残差缩放初始化

GPT-2 采用了特殊的残差路径初始化策略(modeling_gpt2.py L448-L458):

# GPT2PreTrainedModel._init_weights()
if isinstance(module, PreTrainedModel):
    for name, p in module.named_parameters():
        if name == "c_proj.weight":
            # 残差投影层的权重缩小 1/√(2N)
            # N 为残差层数,2 是因为每个 Block 有 2 个残差连接
            init.normal_(p, mean=0.0,
                std=self.config.initializer_range / math.sqrt(2 * self.config.n_layer))

这一策略来自 GPT-2 论文:随着模型深度增加,残差路径上的方差会累积,通过缩小残差层权重来抵消这种累积效应。


9. Pipeline 推理

pipeline("text-generation", model="gpt2") 使用 TextGenerationPipelinetext_generation.py),封装了分词、生成、后处理的完整流程。

Pipeline 时序图

后处理 GPT2LMHeadModel GPT2Tokenizer TextGenerationPipeline 用户代码 后处理 GPT2LMHeadModel GPT2Tokenizer TextGenerationPipeline 用户代码 === 初始化 === === preprocess === === _forward === === postprocess === pipeline("text-generation", model="gpt2") 1. 加载 Tokenizer 2. 加载 Model 3. 设置 padding_side="left" (Decoder-only 批量生成需要左填充) 4. 默认 GenerationConfig max_new_tokens=256 do_sample=True, temperature=0.7 ("Hello, I'm a language model", max_new_tokens=50) tokenizer(prefix + prompt_text, return_tensors="pt") input_ids, attention_mask model.generate( input_ids=input_ids, attention_mask=attention_mask, max_new_tokens=50) generated_sequence (batch, num_return, total_len) 截取新生成的 token sequence[prompt_len:] tokenizer.decode( new_tokens, skip_special_tokens=True) 生成文本 [{"generated_text": "Hello, I'm a language model, and I'm here to help..."}]

Pipeline 的关键初始化逻辑(text_generation.py L99-L106):

class TextGenerationPipeline(Pipeline):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.check_model_type(MODEL_FOR_CAUSAL_LM_MAPPING_NAMES)
        # Decoder-only 模型需要左填充以确保批量生成正确
        if self.tokenizer is not None and self.tokenizer.padding_side == "right":
            self.tokenizer.padding_side = "left"

Pipeline 默认生成配置(text_generation.py L93-L97):

_default_generation_config = GenerationConfig(
    max_new_tokens=256,
    do_sample=True,       # 自由文本生成通常使用采样
    temperature=0.7,
)

10. 状态与生命周期总结

GPT-2 模型在 Transformers 中的完整生命周期,从配置创建到推理输出,经历以下状态转换:

状态机图

GPT2Config()

GPT2LMHeadModel(config)
post_init() → _init_weights()

from_pretrained('gpt2')
下载权重 + 加载 + 权重绑定

model.forward(input_ids)
首次前向 + KV Cache 填充

生成循环
逐 token 解码

next_token → forward → sample
KV Cache 增量更新

EOS / max_length
生成完成

tokenizer.decode()
还原文本

forward → loss → backward → step
权重绑定梯度累加

输出结果

模型就绪
.eval() 模式

tokenizer(text)
ByteLevel BPE 编码

model.train()
labels=input_ids

model.eval()

ConfigCreated

ModelInstantiated

WeightsLoaded

Ready

model.train()

model.eval()

EvalMode

TrainMode

Tokenized

Prefilling

Decoding

Generated

PostProcessed

Training

生命周期关键节点总结

阶段 关键函数/类 源码位置
配置创建 GPT2Config configuration_gpt2.py L25
模型实例化 GPT2LMHeadModel.__init__ modeling_gpt2.py L648
权重初始化 GPT2PreTrainedModel._init_weights modeling_gpt2.py L433
预训练加载 PreTrainedModel.from_pretrained modeling_utils.py
权重绑定 _tied_weights_keys + tie_weights() modeling_gpt2.py L646
分词编码 GPT2Tokenizer.__call__ tokenization_gpt2.py L94
前向传播 GPT2Model.forward modeling_gpt2.py L522
注意力计算 GPT2Attention.forward modeling_gpt2.py L144
因果掩码 create_causal_mask masking_utils.py L894
KV Cache DynamicCache.update cache_utils.py L1229
自回归生成 GenerationMixin.generate generation/utils.py L339
损失计算 GPT2LMHeadModel.loss_function modeling_gpt2.py L711
Pipeline TextGenerationPipeline text_generation.py L23
Conv1D 线性层 Conv1D pytorch_utils.py L97

模型家族一览

GPT-2 在 Transformers 中提供了多种任务头:

类名 任务 头部
GPT2Model 基础模型(提取隐藏状态)
GPT2LMHeadModel 因果语言建模 lm_head (Linear, 权重绑定)
GPT2DoubleHeadsModel 语言建模 + 多项选择 lm_head + multiple_choice_head
GPT2ForSequenceClassification 序列分类 score (Linear)
GPT2ForTokenClassification Token 分类 classifier (Linear)
GPT2ForQuestionAnswering 问答 qa_outputs (Linear → 2)

总结:GPT-2 作为 Decoder-only 因果语言模型的开山之作,其设计深刻影响了后续所有 LLM。从 Conv1D 到 nn.Linear、从 Post-Norm 到 Pre-Norm、从绝对位置编码到 RoPE,每一代演进都在 GPT-2 的基础上优化。理解 GPT-2 的完整生命周期,就是理解现代大语言模型的基石。

更多推荐