当前位置: 首页 > news >正文

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

第二章 大模型如何工作:从 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),再限制上下文长度,最后考虑多卡部署
http://www.cnnetsun.cn/news/3128335.html

相关文章:

  • SkeyeVSS视频融合汇聚平台如何实现无需插件的视频监控、实时对讲和网页直播
  • 3步搞定批量图片下载:让效率提升10倍的免费工具
  • AI赋能接口自动化:从Postman痛点突破到智能测试体系构建
  • GPT-4 Turbo与Claude 3技术对比及国产大模型落地实践
  • 深度解析mflux:苹果原生AI图像生成引擎的技术内幕与实战指南
  • K-Diffusion终极指南:5分钟掌握PyTorch扩散模型实战
  • Deepseek-V4与Claude-Opus-4.7编程实战对比:谁更懂中国开发者
  • 解锁全场景漫画体验:JHenTai无缝跨平台解决方案
  • 使用 Rust 开发图片切分工具:从零到发布的完整指南
  • 汽车工程中的需求管理:2025年最佳实践
  • 告别卡顿?这款Windows漫画神器让阅读体验提升300%
  • 古法CDC:AWS Aurora MySQL使用AWS DMS构建数据管道到数据湖(Apache Iceberg)
  • 一个装X的架构师,通过建文件夹就能亮瞎你的狗眼... ——传说中的弦哥
  • 【Java从入门到入土】45:性能调优实战:从理论到实践
  • 线性密码分析实战:从S盒线性逼近表到SPN网络密钥恢复
  • 卷积的学习
  • 1、JavaScript入门和语法类型
  • 从GitHub Copilot到企业级审查中枢:构建可审计、可回溯、可问责的AI审查流水线
  • 工业级-40°C~125°C+10µA静态电流:SN74LVC1G07DBVR的低功耗宽温逻辑器件
  • 2026免费图片去水印工具推荐在线无水印无需下载
  • 性能测试,监控CPU和内存脚本
  • 数字印花机研发调研报告
  • AI加速卡与工控机集成优化 2026 软硬件协同实操指南
  • Enhanced Motion Forecasting with Plug-and-Play Multimodal Large Language Models
  • 多Agent协作:辩论、投票与分工——AI模型中的协同新范式
  • 数据中台建设方案
  • 佛山个人开发者为私人诊所搭建官网
  • 软件测试入门——第二十一课(接口测试入门)
  • 智能汽车SoC架构与开发实战解析
  • 意识、计算与DMTx:NKS理论为意识现实主义留下的缝隙及其实证延伸