Skip to content

模型优化与效率

摘要: 大模型部署面临显存与算力的双重瓶颈——7B 模型以 FP32 精度存储需 28GB 显存,170B 模型则接近 700GB。本文系统梳理了四项核心优化技术:PEFT(参数高效微调)通过低秩分解将微调参数量压缩至原模型的千分之一;模型量化以 GPTQ、AWQ、GGUF 等算法将权重精度从 FP16 降至 INT4/INT8,在精度损失可控的前提下大幅缩减显存占用;知识蒸馏利用大模型指导小模型训练,实现能力迁移;推理优化方面,KV Cache 避免重复计算,Flash Attention 通过 IO 感知优化降低显存访问,Speculative Decoding 以 draft-verify 模式加速自回归生成。这些技术的组合使用,使得百亿参数模型在消费级硬件上运行成为可能。

📄
图集速览:大模型优化——让 AI 更轻、更快、更普惠如果你对大模型优化还比较陌生,建议先读这篇图集速览。用可视化图片集合和要点摘要,帮你快速理清大模型优化路径。
MoE模型量化推理优化知识蒸馏

1. 引言

一个 7B 参数的模型以 FP32 精度存储需占用 28GB 显存,而 170B 参数的模型更是高达近 700GB。若无优化技术支撑,大模型部署将沦为少数科技巨头的"特权"。

本文介绍的每一项技术,都致力于打破这一壁垒,让大模型真正走向普惠。

2. PEFT:参数高效微调

全参数微调一个 70B 模型需要几百 GB 显存。PEFT 的目标是:只修改极少量参数,就能达到接近全参数微调的效果

2.1 LoRA(Low-Rank Adaptation)

LoRA 的核心洞察来自数学:模型在微调时,权重变化矩阵通常是低秩的,即可以用两个小矩阵的乘积来近似。

全参数微调:  ΔW ∈ R^(d×d)    →  d² 个参数需要更新

LoRA:        ΔW = A × B
              A ∈ R^(d×r), B ∈ R^(r×d)   → 2×d×r 个参数

秩 r 通常取 8~64, 远小于 d (通常 4096+)

直观对比:
  d=4096, r=16 时:
    全参数: 16,777,216 个参数需要更新
    LoRA:      131,072 个参数需要更新  (仅 0.78%!)
LoRA 示意图

    原始权重 W (冻结,不更新)

    输入 x ────────┬────→ W ──────────┬────→ 输出 h
                   │                   │
                   └──→ A ──→ B ──────┘
                       (d×r)  (r×d)
                       可训练  可训练

    h = W·x + B·A·x  = (W + ΔW)·x

    A 用高斯分布初始化, B 用零初始化 → 训练开始时 ΔW=0

为什么要用 LoRA?

  • 显存节省:只需存储和训练两个小矩阵
  • 存储节省:一个基础模型对应多个 LoRA 适配器(不同任务各存一份小权重)
  • 无推理延迟:可以将 LoRA 权重合并回原模型(ΔW 加上 W),推理速度不变

2.2 QLoRA(Quantized LoRA)

QLoRA 在 LoRA 的基础上更进一步——对基础模型本身也进行量化处理

LoRA:   基础模型 FP16 + LoRA 适配器 FP16
QLoRA:  基础模型 4-bit (NF4) + LoRA 适配器 BF16

QLoRA 的关键技术:
  1. NF4 (4-bit NormalFloat): 专为正态分布权重设计的 4-bit 格式
  2. Double Quantization: 对量化常数再做一次量化, 进一步省显存
  3. Paged Optimizers: 用统一内存处理显存溢出

QLoRA 的效果:用一个 48GB 显存的消费级 GPU(如 RTX 4090),就可以微调 65B 参数的模型,且质量接近全参数微调。这极大降低了 AI 开发的门槛。

2.3 其他 PEFT 方法对比

当前 LoRA/QLoRA 是最主流的选择,在参数效率、训练速度和最终效果之间取得了最佳平衡。

方法可训参数推理开销原理
Adapter~1-5% 参数有(额外层)在 Transformer 层间插入小网络
Prefix-Tuning~0.1% 参数占用序列长度在每层前面加可学习的虚拟 token
Prompt-Tuning~0.01% 参数占用序列长度仅输入层加可学习 token
LoRA~0.1-1% 参数无(可合并)低秩分解权重更新

3. 量化(Quantization)

3.1 什么是量化

量化(Quantization)是一种将高精度数值映射到低精度离散值的压缩技术。在深度学习中,具体指将模型的权重和激活值从高精度浮点格式(如 FP32、FP16)转换为低精度整数格式(如 INT8、INT4),以减少模型存储占用和推理计算开销。

量化的直观理解

买大米不需要精确到毫克,用"斤"这个粗粒度单位就够了。大模型太“胖”了,普通电脑根本装不下、跑不动。量化,就是给模型“脱水”,瘦瘦身。

通过降低模型里数字的精度,模型的体积就能瞬间缩小好几倍。虽然精度会有一点点损失,但这点损失几乎不影响使用,却让普通笔记本也能跑大模型成为了现实。这就是AI能真正走进千家万户的关键原因。

figure

数学形式:给定一个浮点数张量 X,量化操作可表示为:

figure

反量化(推理时恢复浮点值):

figure

量化的两种主要范式

范式说明代表方法典型用途
PTQ(Post-Training Quantization,训练后量化)模型训练完成后再做量化,无需重新训练或只需少量校准数据GPTQ、AWQ、GGUF推理部署
QAT(Quantization-Aware Training,量化感知训练)在训练过程中模拟量化误差,让模型学会适应低精度LLM-QAT追求极致精度的场景

3.2 精度级别演进

┌──────────────────────────────────────────────────────────┐
│                    数值精度对比                            │
├──────────┬──────────┬──────────┬──────────┬──────────────┤
│   FP32   │   FP16   │   BF16   │   INT8   │    INT4      │
├──────────┼──────────┼──────────┼──────────┼──────────────┤
│ 32 bits  │ 16 bits  │ 16 bits  │  8 bits  │   4 bits     │
│ 4字节     │ 2字节     │ 2字节    │  1字节    │  0.5字节     │
├──────────┼──────────┼──────────┼──────────┼──────────────┤
│ 7B模型    │ 7B 模型   │ 7B 模型  │ 7B 模型   │ 7B 模型      │
│ ~28 GB   │ ~14 GB   │ ~14 GB   │ ~7 GB    │ ~3.5 GB      │
└──────────┴──────────┴──────────┴──────────┴──────────────┘

BF16 胜过 FP16:BF16 和 FP32 有相同的指数位数(8 位),意味着动态范围相同,但精度较低(尾数只有 7 位)。在实践中,BF16 训练比 FP16 更稳定,不需要 loss scaling 技巧。

3.3 GPTQ / AWQ(GPU 推理量化)

这两种方法都针对 GPU 推理优化,目标是在保持精度的前提下量化到 INT4:

GPTQ (Post-Training Quantization):
  - 基于 OBQ (Optimal Brain Quantization) 的扩展
  - 逐列量化权重矩阵,每次量化后补偿剩余权重的误差
  - 处理策略: 先量化对误差不敏感的权重
  - 速度: 较慢(一次量化需要数小时), 但准确性高

AWQ (Activation-Aware Weight Quantization):
  - 关键洞察: 不是所有权重同等重要
  - 对"显著权重"(被大激活值使用的权重)保留更高精度
  - 通过分析激活值的分布确定哪些权重通道最重要
  - 速度: 比 GPTQ 快, 效果相当或更好

核心洞察:保护重要通道(salient channels)。AWQ 发现约 1% 的权重通道承载了绝大部分信息,只要保护好这 1%,其他 99% 量化为 4-bit 也问题不大。

3.4 GGUF(CPU 推理 / llama.cpp 生态)

GGUF 专为 CPU 推理而生:

GGUF 的特点:
  - 单文件分发: 模型权重 + tokenizer + 元数据全部打包
  - 支持多种量化级别: Q2_K, Q3_K_S/M/L, Q4_K_S/M, Q5_K_S/M, Q6_K, Q8_0...
  - K-quant: 混合精度,重要层用更高质量
  - ARM NEON / AVX2 / CUDA 多后端支持
  - 可以在 MacBook、树莓派甚至手机上运行 LLM

典型使用场景:
  用 MacBook 跑 7B 模型:
  Q4_K_M 量化后 ~4.4GB, 在 M2 MacBook 上可达 20+ tokens/s

3.5 量化对模型质量的影响

量化级别与困惑度(Perplexity)升高:

FP16 (baseline)  ─── 困惑度: 10.00
INT8             ─── 困惑度: 10.01  (几乎无影响)
INT4 (GPTQ/AWQ)  ─── 困惑度: 10.05  (轻微影响)
Q4_K_M (GGUF)    ─── 困惑度: 10.08  (可接受)
INT3             ─── 困惑度: 10.50  (明显退化)

经验法则:对于 7B 以上的模型,INT4 量化几乎不影响实际使用体验;对于 3B 以下的模型,量化到 INT4 需要谨慎评估。

4. MoE:混合专家(Mixture of Experts)

MoE 是一种通过稀疏激活来扩大模型容量但不线性增加计算成本的架构范式。

一句话理解:

把模型从一个「全部员工同时干一件事」的工厂,变成一个「每个任务只调动最相关团队」的公司。

核心思路将传统 Transformer 中单一的 FFN 层替换为多个并行的「专家」(Expert)子网络,每次推理时由一个 Router(门控网络)根据输入内容动态选择其中少数几个专家参与计算。结果是——总参数量可以做到极大(数百 B 甚至上 T),但每次推理的计算量只与选中的少数专家成正比

传统 Transformer 是密集激活(Dense)的,每次推理,所有参数都参与计算。MoE 则不同:每次只激活一部分参数(稀疏激活)。

4.1 稀疏激活原理

密集模型:
  输入 → [全部 FFN 层都计算] → 输出
  → 7B 参数全部参与每次推理

MoE 模型:
  输入 → [Router 选择 2/8 个专家] → 输出
  → 只有被选中的专家参与计算

  总参数可能有 47B, 但每次推理只激活 ~13B

工作场所类比:密集模型像一个所有员工同时处理每个任务的工厂(效率低),MoE 像一个有多个专业团队、每个任务只调用相关团队的公司(更高效)。

4.2 Router / Gating 机制

MoE 层的结构:

    输入 token x


    ┌─────────┐
    │  Router  │  ← 通常是一个简单的线性层: W_gate · x
    │  (门控)  │
    └────┬────┘
         │ 输出: 每个专家的权重分数

    ┌────▼────────────────────────┐
    │  Softmax + Top-k 选择       │
    │  保留分数最高的 k 个专家     │
    │  (通常 k=2)                 │
    └────┬────────────────────────┘

    ┌────▼────┬──────┬──────┬──────┐
    │ Expert1 │Exp-2 │Exp-3 │Exp-8 │  ← 8 个 FFN 专家
    │   ✓     │      │  ✓   │      │  ← 只计算被选中的
    └────┬────┴──────┴──┬───┴──────┘
         │              │
         └──────┬───────┘

         加权求和输出: y = Σ w_i · Expert_i(x)

负载均衡(Load Balancing)是关键挑战。如果 Router 总是选某几个"明星专家",其他专家闲置,MoE 的优势就丧失了。通常需要添加辅助损失(auxiliary loss)来鼓励均匀分配。

4.3 代表模型

模型总参数激活参数专家数Top-k
Mixtral 8x7B46.7B12.9B82
DeepSeek-V2236B21B1606
DeepSeek-V3671B37B2568
GPT-4 (传闻)~1.8T~280B8/16?2?

MoE 让"万亿参数模型"有了商业可行性——DeepSeek-V3 用 MoE 将推理成本控制到传统密集模型的约 1/10。

5. Model Distillation:模型蒸馏

模型蒸馏的思想朴素而强大:让一个大模型(Teacher)教一个小模型(Student),传递的不只是"标准答案",还有"思考过程"。

5.1 黑盒蒸馏 vs 白盒蒸馏

黑盒蒸馏——只能访问 Teacher 的输出:

Teacher 模型 (只能通过 API 调用)

    ├─→ 输入: "什么是机器学习?"
    │   输出: "机器学习是人工智能的一个分支..."

    ├─→ 教师输出 + 正确答案 → 训练 Student 模型

优点: 不依赖 Teacher 模型的内部结构
缺点: 信息有限,只能学到输出层面的知识

白盒蒸馏——可以访问 Teacher 的内部状态:

Teacher 模型 (完全可见)

    ├──→ logits (输出概率分布):   传递"软标签"
    ├──→ hidden states (中间表示): 传递"思考过程"
    └──→ attention patterns:      传递"注意力模式"

    Student 被训练去模仿 Teacher 在多个层面的行为

温度参数的重要性

Softmax 带温度 T:
  q_i = exp(z_i / T) / Σ exp(z_j / T)

Teacher 预测 "猫"(0.6), "狗"(0.3), "汽车"(0.1)

T=1:  猫 0.6,  狗 0.3,  汽车 0.1
      → Student 学会"选猫"

T=5:  猫 0.35, 狗 0.33, 汽车 0.32
      → Student 学会"即使猫最可能, 狗也很有可能, 汽车不太可能"
      → "软标签"传递了更多知识!

蒸馏效果惊人:Gemma 2 的 2.6B 模型通过蒸馏达到了接近 7B 模型的水平。DeepSeek-R1 也用蒸馏将推理能力传递到更小的模型中。

6. Flash Attention

Flash Attention 是一种通过优化 GPU 显存 I/O(而非改变数学公式)来加速 Transformer Attention 计算的算法。

核心洞察:传统 Attention 的瓶颈不在于 GPU 算力不够,而在于计算过程中需要在慢速显存(HBM)和快速片上缓存(SRAM)之间反复搬运大矩阵——这些搬运时间远超实际计算时间。 Flash Attention 通过分块计算(Tiling)和在线 Softmax(Online Softmax),让注意力矩阵的计算完全在 SRAM 内完成,避免将 n×nn \times n 大小的中间结果写回慢速显存,从而将显存复杂度从 O(n2)O(n^2) 降至 O(n)O(n),速度提升 2-7 倍,同时结果在数学上等价于标准 Attention。

一句话理解

Flash Attention 没改变 Attention 做什么,而是改变了 Attention 怎么做——数据不搬家,计算就地完成。

Transformer 的 Attention 机制时间复杂度是 O(n^2)(n 是序列长度)。Flash Attention 不是改变算法复杂度,而是通过优化 I/O(访问显存的方式)来大幅加速。

6.1 IO-aware 算子优化

GPU 的内存层次结构:

┌─────────────────────────────────────────────┐
│              GPU 内存层次                     │
│                                              │
│  ┌─────────────────────────────────────┐    │
│  │          HBM (高带宽显存)            │    │
│  │          ~80 GB, 慢 (~1.5 TB/s)     │    │
│  │  ┌─────────────────────────────┐    │    │
│  │  │     SRAM (片上缓存)          │    │    │
│  │  │     ~20 MB, 极快 (~19 TB/s)  │    │    │
│  └──┴─────────────────────────────┴────┘    │
│                                              │
│  瓶颈: 标准 Attention 需要反复                   │
│  在 HBM 和 SRAM 之间读写中间结果                 │
└─────────────────────────────────────────────┘

传统 Attention 的问题:

标准 Attention 计算:
1. 计算 Q·Kᵀ        → 写出到 HBM (O(n²) 大小)
2. 从 HBM 读回      → 做 softmax
3. 写出到 HBM       →
4. 从 HBM 读回      → 乘以 V
5. 写出最终结果到 HBM

问题: 注意力矩阵 (n×n) 在 HBM 和 SRAM 之间反复搬运
     → 大部分时间花在数据搬运而非实际计算上

Flash Attention 的核心思想:把注意力矩阵切分成小块,每个小块在 SRAM 中完整计算,不需要写回 HBM

6.2 Flash Attention 1 / 2 / 3 演进

┌──────────────┬──────────────────────────────────────┐
│ Flash Attn 1 │ 核心: Tiling + Online Softmax        │
│   (2022)     │ 将 Q,K,V 按块加载到 SRAM             │
│              │ 在 SRAM 内做逐块 softmax             │
│              │ 无需存储完整的注意力矩阵到 HBM        │
│              │ 加速: 2-4×, 显存: O(n) vs O(n²)     │
├──────────────┼──────────────────────────────────────┤
│ Flash Attn 2 │ 核心: 更好的并行 + 反向传播优化       │
│   (2023)     │ 序列长度维度并行                      │
│              │ 改进了 causal mask 的处理             │
│              │ 加速: 比 v1 快 ~2×                    │
├──────────────┼──────────────────────────────────────┤
│ Flash Attn 3 │ 核心: 适配 Hopper 架构 (H100)         │
│   (2024)     │ 利用异步执行的 warp specialization    │
│              │ FP8 支持                              │
│              │ 加速: 比 v2 快 ~1.5-2×                │
└──────────────┴──────────────────────────────────────┘

为什么这很重要? 没有 Flash Attention,长上下文就是纸上谈兵。对于 128K 的上下文窗口,如果存储完整的注意力矩阵,需要 128K × 128K × 2 bytes = 32 GB 显存——这只是一个注意力头的开销。Flash Attention 通过 O(n) 的显存需求让这成为可能。

一句话总结

**Flash Attention 不是改变了 Attention 做什么,而是改变了 Attention 怎么做——它证明了在深度学习领域,计算不仅仅是数学问题,也是 I/O 问题。