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

第二章 大模型如何工作:从 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),再限制上下文长度,最后考虑多卡部署
相关推荐
九狼13 分钟前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS21 分钟前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区2 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈2 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang2 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx
shengjk13 小时前
NanoClaw 深度剖析:一个"AI 原生"架构的个人助手是如何运转的?
人工智能
西门老铁5 小时前
🦞OpenClaw 让 MacMini 脱销了,而我拿出了6年陈的安卓机
人工智能
恋猫de小郭6 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程
是一碗螺丝粉6 小时前
5分钟上手LangChain.js:用DeepSeek给你的App加上AI能力
前端·人工智能·langchain