想象一条美食街:街口是“云端米其林总店”——Gemini 大模型,后厨无比宽阔,食材(参数)堆成山。街尾是千家万户的手机,像一台台小小的移动餐车。为了让顾客在街头也能吃到星级美味,总店主厨派出了年轻徒弟——Gemma。徒弟把师父的“火候心得”(知识蒸馏)、精简菜单(轻量架构)、快刀切菜术(分词器)、高汤浓缩块(4bit 量化)一一学到手,再借助便携灶台(MediaPipe / MLC-LLM)在手机上快速出餐。这篇文章就带你围观这位学徒从拜师到出摊的全过程,看懂 2B/7B 的小身材模型如何装进手机,并跑出可用的本地推理体验。

岗位关联

理解端侧 LLM 的蒸馏、量化与推理优化,是移动 AI 工程师把大模型真正落地到手机和嵌入式设备的核心能力,也是端云协同架构的必备知识。

目录
  1. 可视化演示
  2. 模型家族:两位刚出炉的学徒
  3. 知识蒸馏:师父的软标签秘方
  4. 轻量架构:小厨房的精简菜单
  5. 分词器优化:快刀切菜的艺术
  6. 量化压缩:浓缩高汤块
  7. 端侧推理引擎:街头便携灶台
  8. 推理优化:备菜盒 KV Cache
  9. 应用与局限:餐车开张与天花板
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

交互展示Gemma模型量化压缩、知识蒸馏迁移和端侧部署方案对比,通过滑块调节参数观察实时变化。

本节配有交互动效(进入视口后自动加载,约 3KB)。

量化压缩:模型瘦身核心 FP16→INT4:体积从5GB降至1.5GB GPTQ/AWQ两种量化方案可选 压缩率 = 1 - Size_quant / Size_fp16 4bit量化在精度损失极小的前提下实现3倍压缩

模型家族:两位刚出炉的学徒

星厨的厨房里有两位刚出师的学徒:二徒弟身手敏捷,专攻快手菜;七徒弟学得更全,手艺更丰满。在 Gemma 家族里,2B 和 7B 就是这两位学徒——参数量决定了他们的“脑容量”。参数量越大,能记住的菜谱细节越多,但携带行头也越重。餐车(手机)空间有限,带得越多跑得越慢,于是 2B 适合中端手机,7B 留给旗舰机和平板。

在 Gemma 系列中,2B 与 7B 的定位差异来自部署目标。2B 模型权重占用小、推理快,适合做实时性强的端侧任务;7B 模型常识更丰富,但需要更强的算力与内存带宽支撑。两者都开放权重,可商用,这让开发者不必把数据上传云端就能在设备本地完成推理,是 Google 端侧 AI 布局的重要棋子。

参数规模直接决定模型文件大小。要估算模型权重占多少内存,只需把参数量乘以每个参数占的字节数。4bit 量化下每个参数占 0.5 字节,2B 参数的权重约 1GB,7B 约 3.5GB。再算上运行时激活值和 KV Cache,就知道为什么 2B 是手机里的黄金尺寸:

这就像餐车师傅先掂量小推车能装几口锅——Gemma 家族的分寸,正是 Google 为端侧厨房设计的开场。

权重内存(GB)≈Nparam×b8×109\displaystyle \text{权重内存(GB)} \approx \frac{N_{\text{param}} \times b}{8 \times 10^9}
公式把参数量 N_param 和每参数比特数 b 换算成以 GB 为单位的内存占用。2B 参数、4bit 时约等于 1GB。
  1. 参数量 N模型里有多少个可学习权重。Gemma 2B 即约 20 亿个。
    Nparam=2×109N_{\text{param}} = 2 \times 10^9
  2. 每参数比特数 b存储一个权重需要的二进制位数。4bit 量化时 b=4,换算成字节要除以 8。
    b8=0.5 字节/参数\frac{b}{8} = 0.5\ \text{字节/参数}
  3. 最终内存估算两者相乘得到字节数,再除以 10 的 9 次方显示为 GB。
    2×109×48×109=1.0 GB\frac{2 \times 10^9 \times 4}{8 \times 10^9} = 1.0\ \text{GB}

知识蒸馏:师父的软标签秘方

要让小徒弟学会师父的独家酱料,师父不会只甩一句“好吃”或“难吃”,而是亲手在配方表上写出细腻比例:“七分咸、三分甜,还带一丝辣。”这种带程度的指导,比只给对错判断有用得多。大模型界的“师父”Gemini 对 Gemma 做的,正是这件事。

知识蒸馏的核心是让教师模型(Gemini)在数据上输出“软标签”——一个覆盖所有候选词的概率分布。例如面对同一次输入,教师可能认为“答案 A 有 70% 概率、B 有 25% 概率、C 有 5% 概率”。学生 Gemma 学这个分布,就比只学硬标签“选 A”多掌握了类与类之间的细微关系,从而把教师的泛化能力迁移到自己身上。

蒸馏训练时,学生同时学两件事:一是“模仿教师”——最小化学生输出分布与教师软标签的 KL 散度;二是“不偏离真相”——最小化与真实标签的交叉熵。温度 T 先把分布调“软”,露出更多相似信息;T² 则是为了平衡温度缩放后梯度量级的改变:

小徒弟每天对着师父的手写配方反复试味,出锅的菜便越来越接近星级口感——这正是 Gemma 用 2B 参数继承 Gemini 大规模能力的秘诀。

L=α⋅T2⋅KL ⁣(σ ⁣(ztT)∥σ ⁣(zsT))+(1−α) LCE\displaystyle \mathcal{L} = \alpha \cdot T^2 \cdot \mathrm{KL}\!\left(\sigma\!\left(\frac{z_t}{T}\right) \middle\| \sigma\!\left(\frac{z_s}{T}\right)\right) + (1-\alpha)\,\mathcal{L}_{\mathrm{CE}}
第一个大项让学生分布逼近教师分布,第二个大项兜底不偏离真实答案;α 是两者的权重配比。
  1. 教师软标签教师网络的原始输出 z_t 除以温度 T 后做 softmax,得到一个更平滑的概率分布。
    pt=σ(zt/T)p_t = \sigma(z_t / T)
  2. 学生分布学生网络的输出 z_s 也除以同一个 T,得到 p_s,这样两者才能在同一“软度”下比较。
    ps=σ(zs/T)p_s = \sigma(z_s / T)
  3. KL 散度衡量两个分布的距离,KL 越小代表学生越像老师。
    KL(pt∥ps)=∑ipt(i)ln⁡pt(i)ps(i)\mathrm{KL}(p_t \| p_s) = \sum_i p_t(i) \ln \frac{p_t(i)}{p_s(i)}
  4. 温度缩放因子因为 softmax 里除过 T,梯度会多出 1/T 的衰减,乘回 T² 让梯度量级恢复。
    T2⋅KL(pt∥ps)T^2 \cdot \mathrm{KL}(p_t \| p_s)
  5. 权重混合α 控制“学老师”与“学正确答案”的比例,通常取 0.5 到 0.8 之间。
    α∈[0,1],(1−α) LCE\alpha \in [0,1],\quad (1-\alpha)\, \mathcal{L}_{\mathrm{CE}}

轻量架构:小厨房的精简菜单

餐车厨房很小,不能把总店的五百道菜全搬来,但出餐逻辑和招牌菜必须保留。Gemma 的架构正是为小厨房定制的精简菜单:Transformer 解码器层数更少、隐层维度更小,但注意力、前馈网络、残差连接这些关键“灶具”一样不少。

具体来说,Gemma 2B 约 18 层、隐层维度约 2048;7B 约 28 层、隐层维度约 3072。相比 Gemini 的超大尺寸,Gemma 是刻意缩小的密集 Transformer。它还引入了分组查询注意力(GQA):把多个注意力头分为几组,每组共享一份 Key/Value 投影。这样既保留多头的表达能力,又显著减少需要缓存和计算的 KV 矩阵大小,尤其利于端侧内存受限的场景。

从参数公式看,Transformer 参数量与层数 n_layer 和隐层维度 d_model 呈近似平方关系。这意味着把层数从 28 减到 18,参数量不是线性下降,而是大幅缩水:

少了几口大锅,但小灶台火力集中,照样能炒出像样的菜——这就是架构精简设计的智慧。

PTransformer≈12⋅nlayer⋅dmodel2\displaystyle P_{\text{Transformer}} \approx 12 \cdot n_{\text{layer}} \cdot d_{\text{model}}^2
粗略估算 Transformer 模型的参数量:每层包含自注意力、前馈网络等若干权重矩阵,合计系数约 12。
  1. 层数Transformer 堆叠的解码器块数量,Gemma 2B 约 18 层。
    nlayer≈18n_{\text{layer}} \approx 18
  2. 隐层维度每一层向量表示的宽度,Gemma 2B 约为 2048。
    dmodel≈2048d_{\text{model}} \approx 2048
  3. 系数 12每层注意力 Q/K/V/输出投影与前馈网络的权重总和折算到 d² 的近似倍数。
    P≈12×18×20482≈9.1×108P \approx 12 \times 18 \times 2048^2 \approx 9.1 \times 10^8
  4. GQA 的效果KV 投影参数从多头各自一份变成每组一份,缓存量近似除以组数。
    MKV∝nheadngroupM_{\text{KV}} \propto \frac{n_{\text{head}}}{n_{\text{group}}}

分词器优化:快刀切菜的艺术

切菜有多快,直接决定出餐速度。Gemma 的分词器像一位刀工精湛的师傅:用 SentencePiece 把原文切成大小合适的“食材块”,而不是一个字一个字地磨。更妙的是,这刀法对中英日韩都通用,因为他学的是“子词”这种跨语言的通用切法。

分词器把文本切成 token 序列,直接决定输入序列长度和词表内存。Gemma 使用基于 SentencePiece 的子词分词器,词表约 25.6 万 token。相比逐字切分,子词切分既能覆盖绝大多数词汇,又能把生词拆成已知子词的组合,大幅降低未登录词(OOV)问题。词表大小需要平衡:太小则序列变长、语义碎片化;太大则嵌入层占内存、解码变慢。

子词分词器常用 BPE(Byte Pair Encoding)算法训练。它从字符级语料出发,反复统计相邻子词对的共现频率,把最高频的合并成新词,直到词表达到目标大小。合并准则就是“哪对食材经常一起出现,就把它们预先捆成一捆”:

刀工越好,备菜越省时间,省下的词表内存刚好让餐车多塞几块冰——Gemma 的端侧体验从切菜环节就开始优化。

(a,b)∗=arg⁡max⁡(a,b)count⁡(a⊕b)\displaystyle (a,b)^* = \arg\max_{(a,b)} \operatorname{count}(a \oplus b)
其中 a⊕b 表示相邻的两个子词对,count 统计它们在训练语料中相邻出现的次数。每次迭代合并最高频的一对。
  1. 候选子词对遍历语料中所有相邻子词组合,如 “go“ 与 ”ing” 相邻出现。
    (a,b),a,b∈Vcurrent(a, b),\quad a, b \in V_{\text{current}}
  2. 共现计数统计这一对在当前语料里一起出现的次数,次数越高越值得合并。
    count⁡(a⊕b)=∑sentence1[a b∈sentence]\operatorname{count}(a \oplus b) = \sum_{\text{sentence}} \mathbb{1}[a\,b \in \text{sentence}]
  3. 取最大值每次从全部候选对里挑出现次数最多的一对合并成新子词。
    (a,b)∗=arg⁡max⁡(a,b)count⁡(a⊕b)(a,b)^* = \arg\max_{(a,b)} \operatorname{count}(a \oplus b)
  4. 多语言效果子词共享使不同语言相似的音素组合复用同一 token,词表不必为每种语言单独扩容。
    ∣V共享∣≪∣V中文∣+∣V英文∣+⋯|V_{\text{共享}}| \ll |V_{\text{中文}}| + |V_{\text{英文}}| + \cdots

量化压缩:浓缩高汤块

星级高汤要炖八小时,无法带在身边。师父的办法是把它煮成浓缩高汤块:巴掌大小,到街上一冲开水就还原七分味道。模型量化做的正是这件事——把 32 位浮点的权重压成 4bit 的“浓缩块”。

4bit 量化意味着每个权重只有 16 个离散档位可用来近似原值,内存直接降到 1/8。Gemma 落地时常用对称或非对称量化:通过缩放因子 scale 与零点 zero_point,把浮点权重映射到整数区间 [0, 15]。推理时再把整数还原成近似的浮点值参与计算。整个环节里,决定“高汤块味道”的关键是 scale 选得准不准——通常用一小批校准数据统计权重分布的 min/max 来确定。

量化不是无损操作,但现代神经网络的权重存在大量冗余,压缩后精度损失往往很小。用校准集细心挑选每层 scale,可以让 2B 模型 4bit 量化后依然保持大部分任务性能:

高汤块虽不是原汤,但对小餐车来说,省出的冰柜空间能装更多配菜,整体体验更超值——这就是量化在端侧部署中的独特地位。

Δ=rmax⁡−rmin⁡2b−1,r^=q×Δ+rmin⁡\displaystyle \Delta = \frac{r_{\max} - r_{\min}}{2^b - 1}, \qquad \hat{r} = q \times \Delta + r_{\min}
Δ 是相邻档位之间的刻度,q 是四舍五入后的整数,乘以 Δ 再加最小值就能还原近似原值。
  1. 值域范围先找出权重矩阵的最小值和最大值,量化刻度就在这个范围内展开。
    rmax⁡−rmin⁡r_{\max} - r_{\min}
  2. 档位数量4bit 只能表达 0 到 15 共 16 个档次,所以分母是 2^b − 1。
    2b−1=152^b - 1 = 15
  3. 刻度 Δ把整个值域切成 15 格,每格宽度就是缩放精度,Δ 越小量化越精细。
    Δ=rmax⁡−rmin⁡15\Delta = \frac{r_{\max} - r_{\min}}{15}
  4. 量化与反量化原始权重除以 Δ 后四舍五入得到整数 q,再用 q×Δ+r_min 还原近似值。
    q=round⁡ ⁣(r−rmin⁡Δ),r^=q×Δ+rmin⁡q = \operatorname{round}\!\left(\frac{r - r_{\min}}{\Delta}\right), \quad \hat{r} = q \times \Delta + r_{\min}

端侧推理引擎:街头便携灶台

刀工、菜单、高汤块都齐了,还缺一口能架在小推车上的便携灶台。MediaPipe LLM 是 Google 自家的原厂一体灶,专为 LLM 推理设计;MLC-LLM 是社区万能灶,能适配多种火力;ONNX 则是通用的“菜谱交换格式”,任何灶台照着就能做。

端侧推理引擎负责在 CPU/GPU/NPU 上高效执行量化后的模型。MediaPipe LLM Inference 提供面向 Android/iOS 的 LLM 专用 API 与 GPU 委托加速;MLC-LLM 借助 TVM 编译器把模型统一优化到 Vulkan、OpenCL、Metal 等后端,真正做到一套模型多端部署;ONNX 则把 PyTorch 等框架训练好的模型导出为跨平台中间格式,方便后续接入各类移动推理库。选择哪口灶台,决定了同等模型在不同手机上的实际表现差异。

推理引擎的算力决定了理论出餐速度。自回归生成每生成一个 token,都要做一次完整的前向计算,计算量约等于两倍参数量乘以序列长度。将设备算力代入,就能估算出延迟下限:

灶台选得好不好,直接决定同一锅食材在小厨房里能否快速出锅——端侧部署一半的功夫都在选对推理引擎。

tdecode≈2⋅P⋅LFLOPS设备\displaystyle t_{\text{decode}} \approx \frac{2 \cdot P \cdot L}{\mathrm{FLOPS}_{\text{设备}}}
P 是模型参数量,L 是当前序列长度,FLOPS 是设备可用算力。这个公式给出单 token 生成时间的大致理论下界。
  1. 分子中的 2一次前向包含权重矩阵的正向乘法和残差/归一化等附带开销,折算为 2 倍参数量。
    计算量≈2⋅P⋅L\text{计算量} \approx 2 \cdot P \cdot L
  2. 参数量 P模型权重总数,Gemma 2B 即 2×10^9。
    P=2×109P = 2 \times 10^9
  3. 序列长度 L当前上下文 token 数。序列越长,单次生成越慢,这也是 KV Cache 优化的动因。
    L=ncontextL = n_{\text{context}}
  4. 设备算力分母手机 GPU/NPU 的每秒浮点运算次数 FLOPS 越高,延迟越低。
    tdecode≈2×2×109×LFLOPS设备t_{\text{decode}} \approx \frac{2 \times 2 \times 10^9 \times L}{\mathrm{FLOPS}_{\text{设备}}}

推理优化:备菜盒 KV Cache

大厨炒菜时会把提前切好的葱姜蒜放进小料盒,下一道菜直接取用,而不是每道菜都重新切一遍。KV Cache 就是大模型的备菜盒:把已经算过的 Key 和 Value 矩阵存下来,供后续 token 复用。

自回归生成是逐 token 进行的。每生成一个新 token,都需要计算它与前面所有 token 的注意力分数。如果不缓存,前面 token 的 K/V 每次都要重新投影计算,总开销随序列长度平方增长。KV Cache 把每一层的 K、V 矩阵保存在内存里,生成新 token 时只做一次增量前向计算,复杂度从 O(n²) 降到 O(n)。代价是缓存本身也占内存,而且序列越长占得越多。

缓存大小是可以预估的。每一层需要缓存 K 和 V 两份矩阵,大小等于序列长度乘以 KV 维度;再乘层数和每元素字节数,就得到总缓存占用。这也是为什么 Gemma 用 GQA 减少 KV 头数后,端侧推理更吃香的原因:

备菜盒让餐车在高峰期越炒越快,也让模型的“记忆力”变成了一笔清晰可计算的内存账——这正是端侧推理优化最核心的工程点。

MKV≈2×nlayer×nseq×dkv×b8\displaystyle M_{\text{KV}} \approx 2 \times n_{\text{layer}} \times n_{\text{seq}} \times d_{\text{kv}} \times \frac{b}{8}
近似计算 KV Cache 的字节数:2 代表 K、V 两份,乘层数、序列长度、KV 维度和每元素字节数。
  1. 两份矩阵K 和 V 各有独立存储,这是常数 2 的来源。
    M一份=nseq×dkvM_{\text{一份}} = n_{\text{seq}} \times d_{\text{kv}}
  2. 所有层叠加每层都要缓存一份,所以要乘以 Transformer 层数。
    M全部=nlayer×nseq×dkvM_{\text{全部}} = n_{\text{layer}} \times n_{\text{seq}} \times d_{\text{kv}}
  3. 单位换算b bit 除以 8 变为字节,若缓存也用 8bit 量化,b=8。
    b8=1 字节\frac{b}{8} = 1\ \text{字节}
  4. 综合估算把 K、V、层数、序列长度、维度和字节数全部乘起来。
    MKV=2×nlayer×nseq×dkv×1M_{\text{KV}} = 2 \times n_{\text{layer}} \times n_{\text{seq}} \times d_{\text{kv}} \times 1

应用与局限:餐车开张与天花板

小餐车终于摆好摊,顾客围上来。优点很明显:锅气不外送,所有食材都在本地处理,隐私数据不出手机;没有网络也能营业,离线可用;顾客随点随吃,响应延迟低。但摊子终究小,无法复刻总店的满汉全席。

Gemma 端侧适配的实际应用收益集中在三处:本地智能(输入法、翻译、摘要)、隐私保护(医疗、金融等敏感数据不出设备)和零推理成本(省去云端 API 费用)。局限也同样清晰:7B 及以下的参数规模,在复杂推理、长上下文理解和编码能力上仍远低于云端旗舰模型;知识截止时间较早,无法实时更新;对高并发、超长任务依然力不从心。因此业界主流做法是端云协同——手机本地先快速出首 token 保证响应感,复杂请求再悄悄交给云端补全。

判断一个模型能否在端侧跑起来,需要同时满足内存和速度两个约束:权重能装进可用内存,且每秒生成 token 数达到交互可接受的门槛:

餐车有餐车的市场,它服务的是“手机里的家常小炒”,而不是云端宴席——Gemma 与 Gemini 是互补而非替代,这正是端侧 AI 的清醒定位。

B内存b/8≥Nparam,vtoken≥vmin\displaystyle \frac{B_{\text{内存}}}{b/8} \geq N_{\text{param}},\qquad v_{\text{token}} \geq v_{\text{min}}
左边保证权重塞得进内存,右边保证生成速度达标。两者都满足,端侧部署才算真正可用。
  1. 内存上限可用内存 B 除以每参数的字节数 b/8,得到最多能装下的参数量。
    Nmax⁡=B内存b/8N_{\max} = \frac{B_{\text{内存}}}{b/8}
  2. 参数门槛模型参数量不能超过 N_max,否则装不下或运行即崩溃。
    Nparam≤Nmax⁡N_{\text{param}} \leq N_{\max}
  3. 速度门槛实测生成速度 v_token 必须不低于产品要求的最低速度 v_min,通常 10 tokens/s 左右。
    vtoken=生成 token 数耗时秒数≥10v_{\text{token}} = \frac{\text{生成 token 数}}{\text{耗时秒数}} \geq 10
  4. 综合判断两个条件同时满足,才适合做纯端侧方案;否则应考虑端云协同。
    可用  ⟺  Bb/8≥N ∧ vtoken≥vmin⁡\text{可用} \iff \frac{B}{b/8} \geq N \ \wedge\ v_{\text{token}} \geq v_{\min}

AI 应用场景

离线翻译与智慧输入法

阶段:模型量化 + 端侧推理部署

解决的问题:传统翻译 App 依赖云端,弱网环境下反应慢,且输入内容要上传服务器,隐私风险高。Gemma 2B 经 4bit 量化后约 1GB,可随输入法 App 内置在手机本地。推理引擎首选用 MediaPipe LLM,利用手机 GPU 加速;没有网络时依然能实时实现“边说边译”。上传隐私数据的担忧被直接消解,因为所有文本都在本地处理。

具体案例:开发者在输入法中集成 Gemma 2B 量化版,用户输入“明天下午三点和客户开会”,本地模型直接生成会议摘要与英文翻译,整个过程 500ms 内完成,飞行模式下同样可用。

医疗问诊隐私助手

阶段:知识蒸馏 + KV Cache 优化 + 端侧部署

解决的问题:医院问诊记录属于高度敏感数据,传统云端大模型方案需把病历上传,合规成本高。医疗团队用 Gemini 蒸馏出的 Gemma 7B 模型,配合 GQA 减少 KV Cache 占用,在平板设备上离线运行。医生口述病情,本地模型实时生成结构化病历草稿与鉴别诊断提示,数据全程不出医院内网。

具体案例:某三甲医院试点端侧 Gemma 辅助门诊:医生说完“患者间断性右上腹痛三天,进食油腻后加重”,本地模型自动输出病历结构、拟诊问题和检查建议,单次推理约 1.2 秒,夜间无网值班场景也能稳定使用。

智能车载语音代理

阶段:ONNX 导出 + MLC-LLM 部署 + 推理优化

解决的问题:车载场景中,驾驶员的语音指令必须毫秒级响应且不能掉线。传统方案依赖车机联网,穿越隧道时语音助手就瘫痪。工程师将 Gemma 2B 通过 ONNX 导出,再用 MLC-LLM 编译到高通 GPU 的 Vulkan 后端,实现全离线语音指令理解。结合 KV Cache 设计,多轮对话“调空调”、“导航到公司”等指令可连续快速执行,无需重复计算历史。

具体案例:某车厂在智能座舱中部署 Gemma 2B 量化版,平均指令响应 800ms,隧道、地库无信号环境下语音助手依旧正常工作,且所有语音数据不出车机。

Python 演示

python83 行
import numpy as np  def softmax(z, temp=1.0):    z = z / temp - z.max(axis=1, keepdims=True) / temp    e = np.exp(z)    return e / e.sum(axis=1, keepdims=True)  class SimpleNN:    """两层网络, 用于演示知识蒸馏的教师与学生模型"""     def __init__(self, in_dim, hidden, out_dim, seed=0):        rng = np.random.default_rng(seed)        self.w1 = rng.normal(0, 0.5, (in_dim, hidden))        self.b1 = rng.zeros(hidden)        self.w2 = rng.normal(0, 0.5, (hidden, out_dim))        self.b2 = rng.zeros(out_dim)     def forward(self, x):        h = np.tanh(x @ self.w1 + self.b1)        return h @ self.w2 + self.b2  class DistillLab:    """把大模型能力蒸馏到小模型, 再量化对比精度"""     def __init__(self):        self.teacher = SimpleNN(4, 16, 8, seed=42)        self.student = SimpleNN(4, 4, 8, seed=7)     def generate_data(self, n=256):        rng = np.random.default_rng(2024)        x = rng.normal(size=(n, 4))        y = softmax(self.teacher.forward(x), temp=1.0).argmax(axis=1)        return x, y     def train_student(self, x, y, epochs=300, lr=0.2, temp=3.0):        n = len(x)        y_onehot = np.eye(8)[y]        alpha = 0.6        for _ in range(epochs):            h = np.tanh(x @ self.student.w1 + self.student.b1)            s_logits = h @ self.student.w2 + self.student.b2            t_logits = self.teacher.forward(x)            s_prob = softmax(s_logits, temp)            t_prob = softmax(t_logits, temp)            d_out = (alpha * temp * temp * (s_prob - t_prob) +                     (1 - alpha) * (softmax(s_logits) - y_onehot)) / n            grad_h = d_out @ self.student.w2.T * (1 - h * h)            self.student.w2 -= lr * h.T @ d_out            self.student.b2 -= lr * d_out.sum(axis=0)            self.student.w1 -= lr * x.T @ grad_h            self.student.b1 -= lr * grad_h.sum(axis=0)     def quant4bit(self):        """把学生权重压成 4bit 再还原, 模拟端侧低精度模型"""        for name in ("w1", "w2"):            w = getattr(self.student, name)            w_min = w.min()            w_max = w.max()            scale = (w_max - w_min) / 15.0            if scale == 0:                continue            q = np.round((w - w_min) / scale).astype(np.uint8)            setattr(self.student, name, w_min + q * scale)     def accuracy(self, x, y):        pred = softmax(self.student.forward(x)).argmax(axis=1)        return float((pred == y).mean())  if __name__ == "__main__":    lab = DistillLab()    x, y = lab.generate_data()    before = lab.accuracy(x, y)    lab.train_student(x, y)    after = lab.accuracy(x, y)    lab.quant4bit()    quant = lab.accuracy(x, y)    print("初始学生准确率 {:.1f}%".format(before * 100))    print("蒸馏后准确率 {:.1f}%".format(after * 100))    print("4bit 量化后准确率 {:.1f}%".format(quant * 100))
目的:用两层神经网络模拟“知识蒸馏 + 4bit 量化”全流程:先让大模型当教师生成软标签,再让小模型学习软分布,最后压缩成 4bit 权重观测精度变化。
  1. self.teacher = SimpleNN(4, 16, 8, seed=42)教师网络更大(隐层 16),相当于云端 Gemini。
  2. self.student = SimpleNN(4, 4, 8, seed=7)学生网络更小(隐层 4),相当于端侧 Gemma。
  3. y = softmax(self.teacher.forward(x), temp=1.0).argmax(axis=1)用教师预测生成硬标签,模拟训练数据。
  4. s_prob = softmax(s_logits, temp)学生输出除以温度 T 变成软分布,与教师在同一尺度下比较。
  5. t_prob = softmax(t_logits, temp)教师软标签,是知识蒸馏中“师父的细腻配方”。
  6. alpha * temp * temp * (s_prob - t_prob)蒸馏损失对输出的梯度,让学生分布向教师分布靠拢。
  7. self.student.w2 -= lr * h.T @ d_out梯度下降更新学生最后一层权重。
  8. setattr(self.student, name, w_min + q * scale)权重“量化-还原”,模拟 4bit 低精度存储。
  9. pred = softmax(self.student.forward(x)).argmax(axis=1)推理时用 softmax 取最大概率类别。

常见误区

误区“Gemma 应该就是把 Gemini 的层砍掉几层,做个剪枝,得到一个小一号的版本,所以它和 Gemini 结构完全一样。”

正解Gemma 其实是“重新拜师学艺”的结果,而非对 Gemini 做减法。它用 Gemini 作为教师模型,通过知识蒸馏生成软标签,再从头预训练出一个全新架构的轻量模型。两者网络结构、词表、训练方式各不相同。剪枝是保留原权重删结构,蒸馏是全新学生向教师学习,本质区别就像“砍掉大树的枝干”和“让徒弟重新跟师父学一遍”。

为何常见:两者都得到“更小的模型”且都由大模型而来,初学者很容易把衍生方式混为一谈。

误区“把权重从 32bit 压缩成 4bit,等于丢掉了 87% 的信息,模型在任务上的表现一定大幅下滑。”

正解4bit 量化用缩放因子和零点把浮点权重映射到 16 个离散档位,并非简单截断高位。现代 LLM 权重存在大量冗余,且量化时会用校准集精心挑选每层刻度。实践中,2B 模型 4bit 量化后多数任务精度下降不到 1-2%,有些任务几乎无损。就像高汤块,浓缩过程有损失,但还原后的菜仍然八九分接近原味。

为何常见:直觉上“压缩必损”,但忽略了模型本身的冗余和量化校准环节的补偿作用。

误区“既然历史信息都缓存了,每次生成新 token 直接查缓存就行,复杂度应该降到常数级。”

正解KV Cache 消除的是历史 Key/Value 的重复计算,但新 token 仍然要和全部历史 KV 做一次注意力运算,这是 O(n) 的向量-矩阵操作。整体复杂度只是从“每步重算历史”的 O(n²) 降为“每步增量计算”的 O(n),并非 O(1)。缓存空间本身也要线性增长,属于典型的内存换时间。

为何常见:看到“缓存”就联想到哈希表查表 O(1),忽略了注意力机制需要扫描所有历史 KV 的本质。

误区“把老师输出的答案当成普通标签,喂给学生训练就行,蒸馏和普通训练没啥区别。”

正解蒸馏的关键是软标签——完整的概率分布,而非唯一的硬标签。比如老师对一张图输出“70% 猫、25% 狗、5% 狐狸”,学生从这个分布里学到“猫和狗有点相似”这种隐藏知识。这正是硬标签无法提供的类间相似度信息。蒸馏让学生泛化性更强,就好比徒弟从师父细腻的手法中悟出规律,而不是死记一个结论。

为何常见:硬标签直观简单,初学者容易忽略软标签里蕴含的丰富分布信息。

误区“2B 模型 4bit 后只有 1GB,手机 12GB 内存绰绰有余,跑起来一定很流畅。”

正解权重文件大小只是入场券。推理时还需要 KV Cache、激活值、推理引擎和系统开销,实际可用内存远小于标称值。更关键的是内存带宽和算力——中端机运行 2B 模型可能只有 3-5 tokens/s,体验接近“幻灯片”。端侧部署要综合评估内存容量、带宽、算力和散热,就像餐车能不能开张,要看场地、灶具、原料存放三项条件,而非只看一口锅。

为何常见:只按模型文件大小做判断,忽略了推理是计算密集和内存密集的双重任务。

面试题

Q1. Gemma 系列面向端侧的主力参数量是哪两个版本?

单选题 · easy

  • A.2B 与 7B← 正确答案
  • B.3B 与 13B
  • C.1B 与 4B
  • D.8B 与 70B

答案:A。Gemma 官方发布 2B 和 7B 两个版本,分别面向中端手机与旗舰设备。3B/13B、1B/4B、8B/70B 都不是 Gemma 的标准配置。这就像餐车师傅带两个徒弟,一个快手一个全能,不会带一个扛不动的大块头。

Q2. 知识蒸馏中,学生模型主要模仿教师的什么?

单选题 · easy

  • A.深层网络权重参数
  • B.输出层软标签分布← 正确答案
  • C.训练数据的原始样本
  • D.优化器中的学习率

答案:B。学生模仿的是教师输出的概率分布,即软标签,而非权重或数据。软标签携带类间相似度的细腻信息,是蒸馏优于普通训练的关键。学习率只是训练配置,和模仿无关。

Q3. 4bit 量化后,每个权重参数占多少位二进制?

单选题 · easy

  • A.4 位二进制数位← 正确答案
  • B.8 位二进制数位
  • C.16 位二进制数位
  • D.32 位二进制数位

答案:A。4bit 量化顾名思义每个权重只保留 4 位二进制,总共 2^4=16 个离散档位。8bit 是 256 档,32bit 是浮点原始格式。位宽越小省内存越多,但档位越粗、近似误差越大,需要在压缩率和精度间取平衡。

Q4. 推理时 KV Cache 主要缓存了什么内容?

单选题 · mid

  • A.每层注意力的 K 与 V← 正确答案
  • B.每层的激活函数输出
  • C.优化器的梯度与状态
  • D.原始输入文本的编码

答案:A。KV Cache 缓存的是自注意力计算中的 Key 和 Value 矩阵,让后续 token 不必重复计算历史投影。激活函数输出不需要长期缓存,梯度与优化状态属于训练阶段概念,原始文本编码在输入阶段完成后也不再需要保存。

Q5. 下列哪些属于 Gemma 的端侧适配手段?

多选题 · mid

  • A.知识蒸馏继承于 Gemini← 正确答案
  • B.4bit 量化压缩权重内存← 正确答案
  • C.ONNX 导出跨平台模型← 正确答案
  • D.将所有数据上传到云端

答案:ABC。知识蒸馏让学生继承老师能力,4bit 量化把权重压到 1/8 内存,ONNX 导出让模型能跨平台部署,三者都是端侧适配的核心手段。将数据上传云端与端侧本地推理的初衷背道而驰,因此 D 错误。

Q6. ONNX 在端侧部署流程中扮演什么角色?

单选题 · mid

  • A.跨平台模型交换的格式← 正确答案
  • B.手机芯片中的专用架构
  • C.训练大模型的分布式框架
  • D.在线推理的负载均衡器

答案:A。ONNX 是一种开放的模型交换格式,让 PyTorch 等框架训练好的模型导出后能被多种移动推理引擎读取。它不是硬件架构、训练框架,更不是负载均衡工具。它像菜谱的通用排版,任何灶台都能照着做菜。

Q7. MLC-LLM 可以编译部署到下列哪些后端?

多选题 · mid

  • A.移动端 Vulkan 图形接口← 正确答案
  • B.OpenCL 通用计算接口← 正确答案
  • C.浏览器端 WebGPU 接口← 正确答案
  • D.仅限 Windows 专用接口

答案:ABC。MLC-LLM 基于 TVM 编译器,支持 Vulkan、OpenCL、WebGPU 等多种后端,覆盖手机、浏览器等多元设备。它讲究跨平台通用性,并非限定单一桌面系统,因此 D 错误。

Q8. 蒸馏损失里乘上 T 的平方是为了什么?

单选题 · hard

  • A.平衡温度缩放后的梯度量级← 正确答案
  • B.让学生的网络层级变得更深
  • C.减少训练过程中显存占用
  • D.把教师输出离散化为整数

答案:A。softmax 里除以温度 T 后,梯度会附带 1/T 的缩放,乘回 T² 能让蒸馏损失的梯度量级恢复平衡,训练更稳定。T² 与层数、显存、离散化都无关。这就像师父把菜谱放大缩小时,会自动校正配料比例,不会越抄越走样。

Q9. 下列哪些方法可以降低端侧推理的内存占用?

多选题 · hard

  • A.对 KV Cache 采用 8bit 量化← 正确答案
  • B.采用 GQA 分组查询注意力← 正确答案
  • C.增大上下文长度至 32768
  • D.对全部权重做 4bit 量化← 正确答案

答案:ABD。KV Cache 量化直接压缩缓存体积,GQA 通过共享 KV 头减少缓存量,整型量化则压缩权重存储,三者都降低内存。增大上下文长度会线性增加 KV Cache 规模,反而推高内存占用,因此 C 错误。

Q10. 7B 参数模型用 4bit 量化后,权重文件最小约多少?

单选题 · extreme

  • A.约 1.8 GB 的权重文件
  • B.约 3.5 GB 的权重文件← 正确答案
  • C.约 7.0 GB 的权重文件
  • D.约 14 GB 的权重文件

答案:B。7B 参数即 7×10^9 个权重,每个 4bit = 0.5 字节,7×10^9 × 0.5 = 3.5×10^9 字节 ≈ 3.5GB。这是纯权重文件的理论最小值,实际部署还需额外加上 KV Cache 与运行时开销。选 7GB 是误以为每参数 1 字节,14GB 则错当成 2 字节。