《大模型实战指南》—— 面向软件开发者的系统性入门

第二章 大模型如何工作:从 Token 到 Transformer

"Transformer 不是魔法,而是一套精心设计的信息路由系统。"

------ 本书作者 _abab

2.1 整体流程概览:一条文本的旅程

当你向大模型输入一句 "你好,今天天气怎么样?",它经历了以下步骤:

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [原始文本] ↓ [Tokenizer 分词] → ["你", "好", ",", "今", "天", "天", "气", "怎", "么", "样", "?"] ↓ [Embedding 层] → 每个 token 变成 4096 维向量(以 Qwen-7B 为例) ↓ [位置编码(Positional Encoding)] → 注入"第3个词是','"的位置信息 ↓ [多层 Transformer Block] → 重复 32 次(Qwen-7B 的层数) ↓ [输出层(LM Head)] → 预测下一个 token 的概率分布 ↓ [采样策略(如 Top-p)] → 选择"晴"作为下一个词 ↓ [循环生成] → 拼接"晴",继续预测,直到结束 |

✅ 开发者视角:整个过程可视为一个 stateful 的函数调用链 ,每一步都可监控、可干预。例如:

  • 分词后可过滤敏感 token
  • 生成中可中断不符合预期的输出
  • 位置编码可自定义扩展上下文长度

2.2 Tokenizer:文本的 "原子化" 处理

为什么需要分词?

神经网络只能处理数字,不能直接处理汉字或英文单词。Tokenizer 就是文本到数字 ID 的映射器,核心目标是:

  1. 覆盖所有可能的输入(最小化 OOV 率)
  2. 平衡 token 数量(太少导致语义模糊,太多增加计算量)
主流分词算法对比

|----------------------------------|------------|------------------------------|-------------------------------------------|---------------|-------------------|
| 算法 | 原理 | 示例(中文) | 示例(英文) | 适用模型 | 开发者关注要点 |
| WordPiece | 贪心合并高频子词 | "你好" → ["你", "好"] | "unhappiness" → ["un", "happi", "ness"] | BERT, ChatGLM | 中文 OOV 率低,适合理解类任务 |
| Byte Pair Encoding (BPE) | 统计合并最常见字节对 | "天气" → ["天", "气"] | "apple" → ["app", "le"] | GPT, Llama | 英文压缩率高,生成速度快 |
| SentencePiece | 无监督,支持跨语言 | "AI 助手" → ["AI", "助", "手"] | 同上,支持混合语言 | T5, Qwen | 适配多语言场景,可自定义词表 |

Qwen 使用 基于 BPE 的 SentencePiece ,其 tokenizer 核心优势(开发者需知):

  • 中文按字切分为主,生僻字自动拆分为 UTF-8 字节(OOV 率接近 0)
  • 支持动态扩展词表(如添加领域专有名词)
  • 内置特殊 token(如 <s> 起始符、符、填充符)
开发者实操(Hugging Face)

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| from transformers import AutoTokenizer # 加载 Qwen 的 tokenizer(需信任远程代码) tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B-Chat", trust_remote_code=True) # 基础分词与解码 inputs = "你好,世界!" tokens = tokenizer(inputs) print("Token ID 序列:", tokens["input_ids"]) # 输出: [151644, 872, 198, 108503, 108504, 32852, 151645] print("Token 文本:", tokenizer.convert_ids_to_tokens(tokens["input_ids"])) # 输出: ['>', '你', '好', ',', '世', '界', '!', 'print("解码还原:", tokenizer.decode(tokens["input_ids"])) # 输出: "你好,世界!" # 处理长文本(自动截断/填充) long_text = "这是一段超过模型最大上下文长度的文本..." tokens = tokenizer(long_text, max_length=10, truncation=True, padding="max_length") print("截断后长度:", len(tokens["input_ids"])) # 输出: 10 # 自定义特殊 token tokenizer.add_special_tokens({"additional_special_tokens": [" print("新增 token ID:", tokenizer("")["input_ids"]) # 输出新增 ID |

⚠️ 关键警告:不同模型的 tokenizer 完全不兼容

  • 用 Llama 的 tokenizer 处理 Qwen 的输入会导致语义错乱
  • 部署时需确保 tokenizer 与模型权重严格匹配(建议一起下载)

2.3 Embedding 与位置编码:赋予 token 意义和顺序

Embedding 层:从 ID 到语义向量
  • 核心功能:将离散的 token ID 映射为连续的向量(如 4096 维)
  • 学习机制:训练过程中,语义相近的词(如 "猫" 和 "狗")的向量在高维空间中距离更近
  • 内存占用:Qwen-7B 的 Embedding 层 ≈ 7B × 4096 维 × 4 字节(FP16)≈ 112MB(可忽略不计)

✅ 开发者优化点:

  • 量化时 Embedding 层建议保留 FP16(INT8 会导致语义损失)
  • 领域适配时可冻结 Embedding 层(减少微调参数)
位置编码:解决 Transformer 的 "顺序失忆症"

Transformer 是并行计算架构,本身不感知 token 顺序 ------ 若没有位置编码,"我吃苹果" 和 "苹果吃我" 会被视为相同输入。

主流位置编码对比

|----------------------|-------------------|---------------|-------------|-----------------------|-------------------|
| 类型 | 原理 | 优势 | 劣势 | 适用场景 | 开发者实操建议 |
| 正弦 / 余弦编码 | 用不同频率的正余弦函数生成位置向量 | 理论支持无限长度 | 长距离位置关系衰减快 | 早期模型(GPT-2) | 不建议用于上下文扩展 |
| 学习型位置编码 | 位置向量作为可训练参数 | 适配特定任务 | 超出训练长度后性能骤降 | BERT | 微调时需同步扩展位置参数 |
| RoPE(旋转位置编码) | 对向量进行旋转操作,编码相对位置 | 支持长上下文外推、计算高效 | 需适配模型架构 | Llama, Qwen, ChatGLM4 | 推荐优先选择支持 RoPE 的模型 |

RoPE 核心优势(开发者必须掌握):
  1. 外推能力:训练时用 2K 上下文,推理时可扩展到 8K 甚至 32K(仅需调整旋转角度)
  2. 相对位置保持:编码的是 "词 A 与词 B 相距 k 个位置",而非绝对位置,更符合语言逻辑
  3. 显存友好:无需存储位置参数,实时计算生成

工程实践:扩展上下文长度(如 8K → 32K)

以 Qwen-7B 为例,扩展上下文到 32K(需修改 RoPE 旋转系数)

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained ( "Qwen/Qwen-7B-Chat", trust_remote_code=True, rope_scaling={"type": "linear", "factor": 4.0} # 8K ×4 =32K ) tokenizer.pad_token = tokenizer.eos_token # 确保填充 token 正确 |

2.4 Transformer Block:大模型的"计算单元"

每个 Transformer 层(Decoder 层,大模型生成核心)包含两个核心子模块 + 归一化/残差连接,结构如下:

输入 X → LayerNorm → 多头自注意力 → 残差连接 → LayerNorm → FFN → 残差连接 → 输出

(1)多头注意力机制(Multi-Head Self-Attention)

"Attention is All You Need" ------ 2017 年那篇改变世界的论文

直观理解:

每个词会"关注"句子中其他词的重要性,例如:

  • 句子"猫追老鼠,因为它饿了"中,"它"会重点关注"猫"

  • 句子"苹果的价格比香蕉贵"中,"贵"会关注"苹果"和"香蕉"

数学简化(开发者友好版,忽略缩放和 dropout):

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| def multi_head_attention(X, num_heads, d_model): # X: [batch_size, seq_len, d_model] 输入向量 d_k = d_model // num_heads # 每个头的维度 # 1. 线性变换得到 Q, K, V W_q = torch.randn(d_model, d_model) # 可学习权重 W_k = torch.randn(d_model, d_model) W_v = torch.randn(d_model, d_model) Q = X @ W_q # [batch_size, seq_len, d_model] K = X @ W_k V = X @ W_v # 2. 分割为多个头(并行计算) Q = Q.reshape(-1, seq_len, num_heads, d_k).transpose(1, 2) # [batch, heads, seq_len, d_k] K = K.reshape(-1, seq_len, num_heads, d_k).transpose(1, 2) V = V.reshape(-1, seq_len, num_heads, d_k).transpose(1, 2) # 3. 计算注意力分数(相似度) scores = Q @ K.transpose(-2, -1) / math.sqrt(d_k) # [batch, heads, seq_len, seq_len] attn_weights = torch.softmax(scores, dim=-1) # 归一化 # 4. 加权求和得到输出 output = attn_weights @ V # [batch, heads, seq_len, d_k] output = output.transpose(1, 2).reshape(-1, seq_len, d_model) # 合并头 return output |

多头(Multi-Head)的核心价值:
  • 不同头关注不同关系:有的头关注语法(主谓宾),有的头关注语义(同义替换),有的头关注指代(代词指向)
  • 例如 Qwen-7B 有 16 个头,相当于 16 个 "专家" 并行分析文本关系

开发者优化点:

  • 注意力权重可可视化(如用 matplotlib 绘制热力图),辅助调试语义理解问题
  • 对长文本可使用 "稀疏注意力"(如 Local Attention),减少计算量
(2)前馈神经网络(Feed-Forward Network, FFN)
  • 结构:两层线性变换 + 非线性激活(GELU)

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| def ffn(X, d_model=4096, d_ff=11008): d_ff 通常是 d_model 的 2~4 倍(Qwen-7B 用 11008=4096×2.6875) return torch.relu (X @ W1 + b1) @ W2 + b2 # 简化版,实际用 GELU |

  • 作用:对注意力输出进行**非线性变换和特征增强**------注意力负责"关联信息",FFN 负责"提炼信息"
  • 计算占比:FFN 占 Transformer 层计算量的 60%+,是推理速度优化的重点
(3)残差连接 + LayerNorm:深层网络的"稳定器"
  • 残差连接(Residual Connection):`output = X + sublayer(X)`
  • 解决梯度消失问题,支持深层网络(如 100+ 层)
  • 开发者可通过监控残差连接的输出方差,判断模型是否训练稳定
  • LayerNorm:对每个样本的特征维度归一化(`mean=0, std=1`)
  • 加速训练收敛,提高模型鲁棒性
  • 现代模型多使用"预归一化"(输入先归一化),而非原始论文的"后归一化"

✅ 开发者须知:Transformer 层是 GPU 显存和计算的主要消耗者

  • 计算量:O(seq_len² × d_model)(注意力层) + O(seq_len × d_model × d_ff)(FFN 层)
  • 显存:主要用于存储 Q/K/V 矩阵和中间激活值(可通过梯度检查点技术优化)

2.5 输出层与采样策略:决定生成的"质量与多样性"

(1)输出层(LM Head)
  • 作用:将 Transformer 输出的高维向量(4096 维)映射为所有 token 的概率分布
  • 结构:`Linear(d_model, vocab_size) + Softmax`
  • Qwen-7B 的 vocab_size=151936,因此 LM Head 权重矩阵为 4096×151936 ≈ 6.2GB(FP16)
  • 优化技巧:权重共享(Embedding 层与 LM Head 共享权重),减少显存占用
(2)采样策略:从概率分布中选 token

生成式模型的核心决策点------不同策略会导致输出风格天差地别,开发者需根据场景选择:

策略 原理 优点 缺点 适用场景 代码示例
贪心搜索(Greedy) 每次选概率最高的 token 速度快,确定性强 输出单调,易重复 简单问答、代码生成 next_token = torch.argmax(logits, dim=-1)
束搜索(Beam Search) 保留 top-k 个候选路径,最终选最优 输出更连贯 计算量大(k倍),多样性差 摘要、翻译 beam_search(logits, beam_size=3)
Top-k 采样 从概率最高的 k 个 token 中随机选 多样性强 可能选低概率无意义 token 创意写作、对话 top_k = 50; filtered = logits.topk(top_k); next_token = torch.multinomial(filtered.softmax(dim=-1), 1)
Top-p 采样(Nucleus) 从概率和≥p 的最小 token 集合中随机选 平衡多样性和合理性 需调温度参数 大多数生成场景 top_p = 0.9; sorted_probs = torch.sort(logits.softmax(dim=-1), descending=True); cumsum = sorted_probs.cumsum(dim=-1); keep = cumsum ≤ top_p
温度调节(Temperature) 对 logits 除以温度(T>1 增加多样性,T<1 增加确定性) 灵活调整输出风格 需手动调参 所有场景 logits = logits / T; next_token = torch.multinomial(logits.softmax(dim=-1), 1)

开发者最佳实践:

对话场景:Top-p (0.9) + 温度 (0.7),平衡自然度和可控性

代码/逻辑场景:贪心搜索或 Top-k (20) + 温度 (0.3),保证准确性

创意场景:Top-p (0.95) + 温度 (1.2),增加多样性

(3)生成终止条件
  • 必须显式设置,否则模型会无限生成:

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| def generate(model, tokenizer, prompt, max_new_tokens=512, eos_token_id=151645): input_ids = tokenizer(prompt, return_tensors="pt").input_ids for _ in range(max_new_tokens): logits = model(input_ids).logits[:, -1, :] next_token = top_p_sampling(logits, top_p=0.9) input_ids = torch.cat([input_ids, next_token], dim=-1) # 终止条件:生成 eos token 或达到最大长度 if next_token.item() == eos_token_id: break return tokenizer.decode(input_ids[0], skip_special_tokens=True) |

2.6 自回归生成与 KV Cache:效率的核心

大模型生成文本采用 自回归(Autoregressive)方式------ 逐词生成,直到触发终止条件。但直接计算会有严重性能问题:

(1)无缓存的性能瓶颈
  • 每次生成新 token 时,需重新计算整个输入序列的 Transformer 前向传播
  • 生成 L 个 token 的计算量:O (L × seq_len² × d_model),seq_len 随生成过程不断增长
  • 示例:生成 1024 个 token 时,总计算量相当于单次处理 1024×(1024+1)/2 ≈ 50 万 token
(2)KV Cache:生成效率的 "革命"
  • 核心思想:缓存之前 token 的 K(Key)和 V(Value)向量,避免重复计算
  • 原理:新 token 只需要与所有历史 token 计算注意力,而历史 token 之间的注意力已在之前计算完成
  • 性能提升:生成 L 个 token 的计算量降至 O (L × seq_len × d_model),速度提升 10~100 倍

开发者实操:KV Cache 配置

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| # Hugging Face 中启用 KV Cache(默认开启) model = AutoModelForCausalLM.from_pretrained( "Qwen/Qwen-7B-Chat", trust_remote_code=True, use_cache=True # 启用 KV Cache ) # 监控 KV Cache 显存占用 def get_kv_cache_memory(model, seq_len, batch_size=1): num_layers = model.config.num_hidden_layers d_model = model.config.hidden_size num_heads = model.config.num_attention_heads d_k = d_model // num_heads # K 和 V 各占 batch_size × num_layers × seq_len × num_heads × d_k 字节 kv_memory = batch_size * num_layers * seq_len * num_heads * d_k * 2 # ×2 因为 K 和 V return kv_memory / 1024 / 1024 / 1024 # 转换为 GB # 示例:Qwen-7B 生成 8K token 时的 KV Cache 占用 print(f"KV Cache 显存: {get_kv_cache_memory(model, seq_len=8192):.2f} GB") # 输出约 8GB |

⚠️ KV Cache 注意事项:

  • 开启后会增加显存占用(如 8K 上下文约 8GB),但生成速度大幅提升
  • 多轮对话中,需缓存整个对话历史的 KV 向量,避免重新计算
  • 动态批处理(Dynamic Batching)场景下,KV Cache 会碎片化,需用 vLLM 等引擎优化

2.7 上下文长度与内存占用:工程化选型的核心依据

内存消耗拆解(以 Qwen-7B 为例,FP16 精度)

大模型推理时的显存占用 = 模型权重显存 + KV Cache 显存 + 中间激活显存 + 框架开销

|-------------|-------------------------------|----------------|----------|----------------------------------|
| 组件 | 计算方式 | 8K 上下文 | 32K 上下文 | 开发者优化建议 |
| 模型权重 | 参数量 × 2 字节(FP16) | 7B × 2B = 14GB | 14GB(不变) | 用 INT8 量化可降至 7GB,INT4 降至 3.5GB |
| KV Cache | 前文公式 | ~8GB | ~32GB | 用分组量化(如 GPTQ),或限制上下文长度 |
| 中间激活 | seq_len × d_model × 2 字节 × 层数 | ~2GB | ~8GB | 启用梯度检查点(牺牲速度换显存) |
| 框架开销 | 固定开销 | ~2GB | ~2GB | 用 TensorRT-LLM 等优化框架减少开销 |
| 总显存 | 求和 | ~26GB | ~56GB | 8K 场景用 32GB GPU,32K 场景用 80GB GPU |

上下文长度的工程化权衡

|-----------|-------------------|---------------------|--------------|--------------------------------|
| 上下文长度 | 适用场景 | 硬件要求 | 推理速度 | 开发者决策要点 |
| 2K~8K | 短对话、单轮问答、代码生成 | 消费级 GPU(16GB~32GB) | 快(TPOT ) | 大多数场景的默认选择,平衡成本和体验 |
| 16K~32K | 长文档分析、多轮对话、法律合同解读 | 企业级 GPU(40GB~80GB) | 中(TPOT 0ms) | 需开启 RoPE 外推,用 vLLM 优化 KV Cache |
| 64K~128K | 书籍摘要、论文解读、超长代码调试 | 多卡 GPU(80GB×2+) | 慢(TPOT 50ms) | 仅必要场景使用,需结合稀疏注意力优化 |

✅ 核心结论:8K 是当前平衡能力、成本和速度的 "甜点" ,除非有明确的长文本需求,否则不建议盲目追求超长上下文。

本章小结

  • 大模型的核心流程:文本→Tokenizer→Embedding→位置编码→Transformer→LM Head→采样→生成,每一步都可工程化干预。
  • Tokenizer 是 "输入入口":不同模型不兼容,需匹配权重使用,Qwen 的 SentencePiece 适配多语言场景。
  • 位置编码决定上下文能力:RoPE 支持外推,是扩展上下文长度的关键,开发者可通过 rope_scaling 配置。
  • Transformer Block 是 "计算核心":注意力负责关联信息,FFN 负责提炼特征,残差连接 + LayerNorm 保证稳定。
  • 生成效率的关键:KV Cache 减少重复计算,采样策略决定输出质量,自回归循环控制生成流程。
  • 内存占用的核心:模型权重(可量化优化)+ KV Cache(与上下文长度正相关),8K 上下文是工程化首选。

开发者落地建议:

  • 先掌握基础流程(分词→生成),再优化细节(采样策略、KV Cache)
  • 用 Qwen-7B 作为入门实践模型(文档全、生态成熟)
  • 遇到显存不足:优先量化模型(INT8),再限制上下文长度,最后考虑多卡部署
相关推荐
少油少盐不要辣2 小时前
前端如何处理AI模型返回的流数据
前端·javascript·人工智能
XianjianAI2 小时前
先见AI新功能深度介绍:以可信AI重构研报解读,数据驱动决策快人一步
大数据·人工智能·信息可视化·数据分析·需求分析
IT_陈寒2 小时前
Java21新特性实战:5个杀手级改进让你的开发效率提升40%
前端·人工智能·后端
天呐草莓2 小时前
支持向量机(SVM)
人工智能·python·算法·机器学习·支持向量机·数据挖掘·数据分析
AI营销实验室2 小时前
原圈科技AI CRM系统三步法驱动客户自动唤醒与精准营销增长
人工智能·科技
杜子不疼.2 小时前
AI智能体:从技术原理到落地实践,重构智能协作新范式
人工智能·重构
不惑_2 小时前
CNN:通俗理解卷积神经网络
人工智能·神经网络·cnn
Pyeako2 小时前
机器学习--决策树
人工智能·python·决策树·机器学习·分类·pycharm·回归树
行业探路者2 小时前
网站二维码的全解析与使用技巧分享
大数据·人工智能·学习·产品运营·软件工程