GPT 技术架构与源码分析
一句话概括:GPT 不是 Transformer 架构的简单复用,而是一场以“Decoder-Only + 因果语言建模”为核心的生成式 AI 范式革命——它舍弃了 Transformer 的编码器-解码器对称结构,仅保留解码器部分,用“预测下一个词”这一极其简洁的训练目标,通过海量无标注文本的预训练+少量有标注数据的微调,回答了深度学习领域一个根本性的问题:如果模型能够通过阅读互联网上的所有文本学会“理解”语言,那我们还需要为每个任务单独标注数据吗?****
一、引言
如果你用过 Hugging Face 的 Transformers 库,你一定写过类似这样的代码:
fromtransformersimportGPT2LMHeadModel,GPT2Tokenizer model=GPT2LMHeadModel.from_pretrained("gpt2")tokenizer=GPT2Tokenizer.from_pretrained("gpt2")inputs=tokenizer("The future of AI is",return_tensors="pt")outputs=model.generate(**inputs,max_length=50)print(tokenizer.decode(outputs[0]))几行代码,一个能生成连贯文本的语言模型就跑起来了。看起来很轻松,对吧?
但在 2018 年之前,事情远没有这么简单。如果你想做一个文本分类、机器翻译或问答系统,你几乎绕不开有监督学习——你需要为每个任务收集大量标注数据,然后训练一个专用于该任务的模型。你做一个情感分析模型,需要上万条标注了“正面/负面”的影评;你做一台机器翻译系统,需要百万级对齐的双语语料。每个任务都是独立的,每个任务都需要重新标注数据、重新训练模型。
你可能会问:为什么不能让模型先“读懂”语言,再针对具体任务做少量微调?
这正是 GPT(Generative Pre-trained Transformer)回答的问题。
2018 年,OpenAI 的 Alec Radford、Karthik Narasimhan、Tim Salimans 和 Ilya Sutskever 发表了论文《Improving Language Understanding by Generative Pre-Training》。论文的核心思想极其简洁:在大规模无标注文本上预训练一个语言模型(预测下一个词),然后在具体任务上用少量有标注数据进行微调。
这个“预训练 + 微调”的范式,彻底改变了 NLP 的研究范式。GPT 的原始版本只有1.17 亿参数——在今天看来微不足道——但它证明了“无标注预训练”的有效性。
2019 年,GPT-2 将参数规模扩大到15 亿,展示了零样本迁移的惊人能力。2020 年,GPT-3 将规模推至1750 亿参数,展示了少样本学习(Few-shot Learning)的能力——你只需要在 Prompt 中给几个例子,模型就能学会执行新任务。2023 年,GPT-4 据估计达到1.8 万亿参数,采用MoE(混合专家)架构,并具备了多模态能力。
那么,这个“Decoder-Only + 因果语言建模”的架构到底长什么样?为什么只用“预测下一个词”就能让模型学会理解语言?GPT-2 和 GPT-3 的源码是如何实现的?我们从论文、开源实现和 Hugging Face Transformers 库出发,一步步拆解。
二、整体架构与设计哲学
2.1 架构总览:Decoder-Only Transformer
GPT 系列模型的核心架构是Decoder-Only Transformer——它只使用了原始 Transformer 架构中的解码器(Decoder)部分,并舍弃了编码器(Encoder)和交叉注意力(Cross-Attention)机制。
┌─────────────────────────────────────────────────────────────────────┐ │ GPT 模型架构(Decoder-Only) │ ├─────────────────────────────────────────────────────────────────────┤ │ 输入文本 → Tokenizer → Token IDs │ │ ↓ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 嵌入层(Token Embedding + Positional Embedding) │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ Transformer Decoder 层(×N) │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Masked Multi-Head Self-Attention(因果掩码) │ │ │ │ │ │ · 每个 token 只能看到它之前的 token │ │ │ │ │ │ · 不能“偷看”未来位置 │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ ↓ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Layer Normalization + Residual Connection │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ ↓ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Feed-Forward Network(位置独立的前馈网络) │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ ↓ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Layer Normalization + Residual Connection │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ LM Head → Softmax → 下一个 Token 的概率分布 │ │ │ └──────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘图:GPT 的 Decoder-Only 架构。与原始 Transformer 不同,GPT 只保留了解码器部分,并去掉了编码器-解码器交叉注意力。每个 Token 通过因果掩码(Causal Masking)只能看到自己和前面的 Token,确保了自回归生成的因果性。
与原始 Transformer 的关键区别:
| 维度 | 原始 Transformer | GPT(Decoder-Only) |
|---|---|---|
| 架构 | Encoder + Decoder | 仅 Decoder |
| 注意力 | 双向自注意力(Encoder)+ 掩码自注意力(Decoder) | 仅掩码自注意力 |
| 交叉注意力 | 有(Decoder 关注 Encoder 输出) | 无 |
| 训练目标 | Seq2Seq(翻译等) | 因果语言建模(预测下一个词) |
| 适用任务 | 序列到序列 | 文本生成、理解、对话 |
为什么舍弃 Encoder?因为 GPT 的目标不是“理解输入序列并生成输出序列”(如翻译),而是“根据已有文本预测下一个词”——这是一个纯粹的自回归生成任务,不需要双向编码上下文。
2.2 设计哲学:预训练 + 微调
GPT 的设计围绕一个核心判断展开:与其为每个 NLP 任务单独训练模型,不如先让模型在大规模无标注文本上学会“理解”语言,再针对具体任务做少量微调。
这个“预训练 + 微调”范式包含两个阶段:
阶段一:无监督预训练(Unsupervised Pre-training)
在大规模无标注文本语料上,训练模型预测下一个词。训练目标是最小化负对数似然:
L1(U)=∑ilogP(ui∣ui−k,...,ui−1;Θ)L_1(U) = \sum_i \log P(u_i | u_{i-k}, ..., u_{i-1}; \Theta)L1(U)=i∑logP(ui∣ui−k,...,ui−1;Θ)
其中kkk是上下文窗口大小,Θ\ThetaΘ是模型参数。模型通过这个任务学习语言的统计规律——词与词之间的共现关系、语法结构、语义关联,甚至一定程度上的世界知识。
阶段二:有监督微调(Supervised Fine-tuning)
在预训练完成后,将模型参数作为初始值,在具体任务(如文本分类、自然语言推理、问答)的有标注数据上进行微调。微调时,模型的输出层会根据任务进行调整,但主体参数只做小幅更新。
这种设计的核心洞察是:预训练阶段让模型获得了通用的语言理解能力,微调阶段只需要教会模型“如何把这种理解应用到具体任务上”。因此,微调所需的有标注数据远少于从头训练一个模型。
2.3 模型规模演进
GPT 系列模型的参数规模经历了指数级增长:
| 模型 | 发布时间 | 参数量 | 层数 | 隐藏维度 | 注意力头数 | 上下文长度 |
|---|---|---|---|---|---|---|
| GPT-1 | 2018 年 6 月 | 1.17 亿 | 12 | 768 | 12 | 512 |
| GPT-2 | 2019 年 2 月 | 15 亿 | 48 | 1600 | — | 1024 |
| GPT-3 | 2020 年 5 月 | 1750 亿 | 96 | 12288 | 96 | 2048 |
| GPT-4 | 2023 年 3 月 | ~1.8 万亿 | 120 | — | — | 32K+ |
GPT-2 相比 GPT-1 的规模提升主要体现在层数和隐藏维度上——从 12 层 768 维扩展到 48 层 1600 维。GPT-3 则进一步扩大到 96 层、12288 维隐藏层。
GPT-4 的参数量据估计在1.8 万亿左右,分布在120 层中。值得注意的是,GPT-4 的架构从稠密 Transformer 转向了MoE(Mixture of Experts,混合专家)架构——包含16 个专家(Experts),每个专家约1110 亿参数。在推理时,每个 Token 只会被路由到部分专家,而非激活全部参数——这大幅降低了推理成本。
三、核心抽象与源码解析
3.1 Token Embedding + Positional Embedding——把文本变成数字
GPT 处理文本的第一步是将原始文本转换为数值表示,包含两个层次:
Token Embedding(词元嵌入):将每个 Token(词或子词)映射为一个固定维度的向量。GPT 使用BPE(Byte Pair Encoding)分词器——将罕见词拆分为更常见的子词单元,既控制了词表大小,又能处理未登录词。
Positional Embedding(位置嵌入):由于 Transformer 本身不包含顺序信息,需要显式注入位置编码。GPT-1/2 使用可学习的位置嵌入(Learned Positional Embedding),而非原始 Transformer 的正弦编码。
# 文件路径:mingpt/model.py(minGPT 实现,结构示意)# 来源:github.com/karpathy/minGPTclassGPT(nn.Module):def__init__(self,config):super().__init__()# Token Embedding:将 token id 映射为向量self.tok_emb=nn.Embedding(config.vocab_size,config.n_embd)# Position Embedding:可学习的位置编码self.pos_emb=nn.Parameter(torch.zeros(1,config.block_size,config.n_embd))# Dropoutself.drop=nn.Dropout(config.embd_pdrop)# Transformer Decoder 层堆叠self.blocks=nn.Sequential(*[Block(config)for_inrange(config.n_layer)])# Layer Normalization(GPT-2 采用 Pre-LN 结构)self.ln_f=nn.LayerNorm(config.n_embd)# LM Head:将隐藏状态映射回词表概率分布self.lm_head=nn.Linear(config.n_embd,config.vocab_size,bias=False)这段代码实现了什么?输入是一串 Token ID(整数序列),经过tok_emb变成向量序列,加上pos_emb注入位置信息,然后送入 Transformer 层堆叠处理。
设计模式解读:这是工厂模式(Factory Pattern)的体现——GPT类像一个工厂,将 Token Embedding、Position Embedding、Transformer Blocks、Layer Norm 和 LM Head 组装成一个完整的语言模型。
3.2 Causal Self-Attention——因果掩码的核心
因果自注意力(Causal Self-Attention)是 GPT 与原始 Transformer 自注意力的本质区别——它通过一个上三角掩码矩阵确保每个 Token 只能看到自己和之前的位置,而不能“偷看”未来。
# 文件路径:mingpt/model.py(minGPT 实现,结构示意)classCausalSelfAttention(nn.Module):def__init__(self,config):super().__init__()# 将 Q、K、V 放在一个线性层中self.c_attn=nn.Linear(config.n_embd,3*config.n_embd)# 输出投影self.c_proj=nn.Linear(config.n_embd,config.n_embd)# 因果掩码(上三角矩阵)self.register_buffer("bias",torch.tril(torch.ones(config.block_size,config.block_size)).view(1,1,config.block_size,config.block_size))defforward(self,x):B,T,C=x.size()# batch, sequence length, embedding dimension# 1. 计算 Q、K、Vqkv=self.c_attn(x)# (B, T, 3 * C)q,k,v=qkv.split(self.n_embd,dim=2)# 2. 计算注意力分数att=(q @ k.transpose(-2,-1))*(1.0/math.sqrt(k.size(-1)))# 3. ★ 应用因果掩码——将未来位置的分数设为 -infatt=att.masked_fill(self.bias[:,:,:T,:T]==0,float('-inf'))# 4. Softmax 得到注意力权重att=F.softmax(att,dim=-1)# 5. 加权求和y=att @ vreturny这段代码实现了什么?自注意力机制的核心是让序列中的每个位置“关注”其他位置。在 GPT 中,通过masked_fill将上三角(未来位置)的注意力分数设为-inf,使得每个 Token 在计算注意力时只能看到自己和之前的 Token。
设计模式解读:这是模板方法模式(Template Method Pattern)的体现——自注意力的计算流程(QKV 投影 → 注意力分数 → 掩码 → Softmax → 加权求和)是固定的,但掩码策略(因果 vs 双向)可以替换。
设计权衡分析:
- 收益:① 因果掩码保证了自回归生成的因果性——生成第 t 个 Token 时只能依赖前 t-1 个 Token;② 在训练时可以进行 Teacher Forcing——所有位置的预测可以并行计算,大幅提升训练效率。
- 代价:① 因果掩码意味着每个 Token 的视野受限,无法利用未来的上下文信息;② 对超长序列(如 10K+ tokens),O(n²) 的注意力计算仍然是瓶颈。
- 适用场景:因此,Decoder-Only + Causal Attention 是自回归文本生成的标准范式——GPT、GPT-2、GPT-3、GPT-4 以及所有主流大语言模型(LLaMA、Claude、DeepSeek 等)都采用这一设计。
3.3 Transformer Block——堆叠出深度理解
GPT 的每一层 Transformer Block 包含两个子层:掩码多头自注意力和前馈网络(FFN),每个子层都配有残差连接和层归一化。
GPT-2 相比 GPT-1 的一个关键架构变化是Layer Norm 前置(Pre-LN):
# 文件路径:mingpt/model.py(minGPT 实现,结构示意)classBlock(nn.Module):def__init__(self,config):super().__init__()# Pre-LN:Layer Norm 放在 Attention 和 FFN 之前self.ln1=nn.LayerNorm(config.n_embd)self.attn=CausalSelfAttention(config)self.ln2=nn.LayerNorm(config.n_embd)self.mlp=MLP(config)defforward(self,x):# Pre-LN + 残差连接x=x+self.attn(self.ln1(x))x=x+self.mlp(self.ln2(x))returnxPre-LN vs Post-LN:原始 Transformer 采用 Post-LN(Layer Norm 在子层之后),而 GPT-2 开始采用 Pre-LN(Layer Norm 在子层之前)。Pre-LN 的优势在于训练更稳定——梯度可以直接通过残差连接传播,避免了深层网络中梯度消失的问题。
3.4 minGPT:300 行的 GPT 教学实现
minGPT 是 Andrej Karpathy 开发的最小化 GPT 实现,旨在用最简洁的代码展示 GPT 的核心机制。
整个库只有三个核心文件:
mingpt/ ├── model.py # ★ Transformer 模型定义(~300 行) ├── bpe.py # BPE 分词器实现 └── trainer.py # 训练循环(PyTorch 模板代码)model.py的核心结构:
classGPT(nn.Module):"""300 行代码实现的 GPT 语言模型"""# 包含:Token Embedding、Position Embedding、# Transformer Block 堆叠、Layer Norm、LM Head设计模式解读:minGPT 是教学型实现(Educational Implementation)的典范——它的目标不是性能最优,而是可读性最优。300 行代码覆盖了 GPT 的所有核心组件,让学习者能够快速理解“一个语言模型到底是怎么工作的”。
3.5 nanoGPT:生产级的 GPT 实现
nanoGPT 是 Karpathy 对 minGPT 的重写版本,定位从“教学”转向“实用”。
核心特征:
model.py约300 行,train.py约300 行- 在8×A100 40GB节点上约4 天可复现 GPT-2 (124M)
- 可选的GPT-2 权重加载,支持从 OpenAI 的预训练权重继续微调
- 支持混合精度训练、分布式训练等生产级特性
nanoGPT 的设计哲学是“简洁但实用”——代码足够简单,任何人都可以按需修改;同时足够强大,可以在真实硬件上训练出可用的模型。
3.6 MiniGPT:从第一性原理重建 GPT
2026 年 5 月,一篇题为《MiniGPT: Rebuilding GPT from First Principles》的论文正式发表。MiniGPT 是一个从零开始、在单个 Notebook 中实现的 GPT,旨在从第一性原理重建 GPT 的核心 pipeline。
MiniGPT 实现的完整组件包括:
- Token 嵌入和位置嵌入
- 因果多头自注意力
- Pre-LayerNorm Transformer Block
- 残差连接
- 前馈 MLP 层
- 下一个 Token 的交叉熵训练(Teacher Forcing)
- 验证跟踪和检查点选择
- 自回归文本生成
性能数据:
- 0.83M 参数的基线模型在 Tiny Shakespeare 数据集上训练 3000 步后,验证损失达到1.7236
- 10.77M 参数的更强配置,验证损失达到1.4780,能够生成可识别的莎士比亚风格对话
MiniGPT 的意义在于:它证明了 GPT 的核心思想可以用极少的代码、在单个 Notebook 中完整复现。这对于教育者和研究者理解 GPT 的内部机制具有重要价值。
四、推理过程:从概率分布到文本
4.1 生成策略——解码的艺术
模型前向传播输出的只是概率分布(Logits),如何将这些概率转化为流畅的文本,是解码策略的核心。
Hugging Face Transformers 库的model.generate()方法封装了完整的解码流程:
输入 Prompt → Tokenizer → input_ids ↓ model.generate() 循环: ├── 前向传播 → Logits ├── 应用解码策略(Greedy / Beam Search / Sampling / Top-k / Top-p) ├── 选择下一个 Token ├── 将 Token 追加到序列 └── 判断是否满足停止条件(达到 max_length / 遇到 EOS) ↓ 输出 Token IDs → Tokenizer.decode() → 文本常见解码策略:
| 策略 | 原理 | 特点 |
|---|---|---|
| Greedy Decoding | 每步选择概率最高的 Token | 最快,但容易陷入重复 |
| Beam Search | 维护 K 条候选序列 | 质量更高,但计算量大 |
| Top-k Sampling | 从概率最高的 k 个 Token 中采样 | 平衡多样性和质量 |
| Top-p (Nucleus) Sampling | 从累积概率达到 p 的最小集合中采样 | 动态调整候选集大小 |
| Temperature Scaling | 调整概率分布的“尖锐度” | 控制生成的随机性 |
在 Transformers 库中,通过model.generate()的参数控制解码策略:
outputs=model.generate(input_ids,max_length=100,do_sample=True,# 启用采样temperature=0.8,# 温度参数top_k=50,# Top-k 采样top_p=0.95,# Top-p (Nucleus) 采样)4.2 Pipeline 的数据流
当你使用 Hugging Face 的 Pipeline 接口时,数据经历了完整的生命周期:
- Preprocess(预处理):文本被 Tokenizer 转换为
input_ids和attention_mask - Forward(前向传播):模型执行
generate() - Postprocess(后处理):Token IDs 被解码为文本
fromtransformersimportpipeline generator=pipeline('text-generation',model='gpt2')result=generator("I like eating fried",max_length=20)在这个 Pipeline 内部:
input_ids的形状是(1, 4),对应输入"I like eating fried"的 4 个 Token- 模型逐 Token 生成,每步将新 Token 追加到序列中
- 最终输出被解码为完整文本
五、工程化实践
理论说完了,接下来聊聊实战——用 GPT 类模型搭建应用时,你最关心的几个问题。
5.1 快速接入
使用 Hugging Face Transformers:
fromtransformersimportGPT2LMHeadModel,GPT2Tokenizer# 加载预训练模型和分词器model=GPT2LMHeadModel.from_pretrained("gpt2")tokenizer=GPT2Tokenizer.from_pretrained("gpt2")# 文本生成inputs=tokenizer("The future of AI is",return_tensors="pt")outputs=model.generate(**inputs,max_length=50,do_sample=True)print(tokenizer.decode(outputs[0]))使用 minGPT 从零训练:
frommingpt.modelimportGPTfrommingpt.trainerimportTrainer# 配置模型(GPT-2 124M 版本)config=GPT.get_default_config()config.model_type='gpt2'config.vocab_size=50257config.block_size=1024model=GPT(config)# 训练trainer=Trainer(train_config,model,train_dataset)trainer.run()使用 nanoGPT 训练:
# 准备数据(以莎士比亚字符级为例)python data/shakespeare_char/prepare.py# 训练python train.py config/train_shakespeare_char.py# 生成文本python sample.py--out_dir=out-shakespeare-char在单张 A100 GPU 上,上述莎士比亚字符级训练约需3 分钟。
5.2 常见工程陷阱与解决方案
陷阱 1:OOM(显存不足)
现象:加载大模型或处理长序列时显存溢出。
解决方案:
- 使用更小的模型(如
gpt2而不是gpt2-xl) - 减小
max_length或batch_size - 启用梯度检查点(Gradient Checkpointing)
- 使用混合精度训练(FP16/BF16)
陷阱 2:生成文本重复
现象:模型陷入重复循环,不断输出相同的词或短语。
解决方案:
- 使用Repetition Penalty:
model.generate(..., repetition_penalty=1.2) - 调整解码策略:从 Greedy 改为 Top-k/Top-p Sampling
- 增加
temperature值(如 0.8-1.0)
陷阱 3:Tokenizer 不匹配
现象:加载预训练模型时,Tokenizer 的词表与模型不匹配。
解决方案:始终使用与模型配套的 Tokenizer:
# 正确做法tokenizer=AutoTokenizer.from_pretrained("gpt2")model=AutoModelForCausalLM.from_pretrained("gpt2")# 错误做法:混用不同模型的 Tokenizer# tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")# model = AutoModelForCausalLM.from_pretrained("gpt2") # ❌六、总结与展望
6.1 关键版本里程碑
| 版本/事件 | 时间 | 参数量 | 核心创新 |
|---|---|---|---|
| GPT-1 论文发表 | 2018 年 6 月 | 1.17 亿 | 预训练 + 微调范式 |
| GPT-2 发布 | 2019 年 2 月 | 15 亿 | 零样本迁移、Pre-LN |
| GPT-3 发布 | 2020 年 5 月 | 1750 亿 | 少样本学习(In-Context Learning) |
| GPT-4 发布 | 2023 年 3 月 | ~1.8 万亿 | MoE 架构、多模态 |
| GPT-5 | 2024 年 | — | 持续迭代 |
6.2 设计哲学提炼
GPT 的设计哲学可以提炼为三个关键词:
预训练即基础:在大规模无标注文本上预训练语言模型,让模型先“读懂”语言
微调即适应:在具体任务上用少量标注数据进行微调,将通用能力转化为专项能力
规模即能力:随着模型参数、训练数据和计算资源的增长,模型能力持续涌现
6.3 核心架构亮点
| 亮点 | 说明 |
|---|---|
| Decoder-Only 架构 | 舍弃 Encoder,仅保留 Decoder,专注自回归生成 |
| 因果掩码(Causal Masking) | 确保每个 Token 只能看到过去,不能看到未来 |
| Pre-LN(Layer Norm 前置) | 训练更稳定,支持更深层的网络 |
| BPE 分词 | 平衡词表大小和未登录词处理 |
| 可学习位置嵌入 | 相比正弦编码,更具灵活性 |
| 预训练 + 微调范式 | 开创了 NLP 的新范式 |
6.4 对开发者的启示与适用场景
GPT 的本质不是一种“模型架构”,而是一种“学习范式”——用“预测下一个词”这个极其简单的训练目标,让模型从海量文本中自动学习语言的统计规律、语法结构、语义关联,甚至世界知识。它回答了一个根本性的问题:如果模型能够通过阅读互联网上的所有文本学会“理解”语言,那我们还需要为每个任务单独标注数据吗?GPT 的答案是:不需要。
适用场景:
- 文本生成:故事写作、邮件撰写、代码生成
- 对话系统:聊天机器人、客服助手
- 内容理解:文本分类、情感分析、命名实体识别(通过微调)
- 代码辅助:代码补全、代码解释、Bug 修复
不适用场景:
- 对推理延迟极度敏感的场景(自回归生成是顺序的,无法完全并行)
- 对输出确定性有极致要求的场景(采样引入随机性)
- 超长序列(>10K tokens)的处理(O(n²) 注意力计算是瓶颈)
本文数据来源:OpenAI GPT 系列论文(Radford et al., 2018, 2019; Brown et al., 2020)、GPT-4 Technical Report(OpenAI, 2023)、minGPT 与 nanoGPT 开源实现、Hugging Face Transformers 文档、第三方技术解析(截至 2026 年 8 月)
如您所在的企业正面临数字化难题,或有 AI 落地、系统集成相关需求,欢迎进一步沟通。我们可提供针对贵企业具体场景的定制化方案和现场调研服务。