面灵AI→

10.22 字节跳动大模型算法三面:Transformer 复杂度推导与训练工程追问

轮次
三面
结果
三面已过
时间
2026-10
来源
牛客网

《面试题目》

  1. 核心优化方案具体改了什么,用一句话说清。
  2. 这个优化对应哪个指标、涨了多少,怎么把增长归因到你的改动?
  3. 同期还上线了什么?你怎么排除是它们的功劳?
  4. 基座微调还是从零训,为什么这么选?
  5. 训练数据的清洗流程和筛选规则是什么?一条一条说。
  6. 清洗过程中有没有误删、错筛?怎么估这个误差?
  7. 完整讲一遍 Transformer 的架构和每个模块的作用。
  8. 给定头数 H、序列长度 N、嵌入维度 D、层数 L,整体计算复杂度怎么推?
  9. 这个复杂度里哪一项在长序列下会先爆?爆了之后你怎么改?
  10. MHA、MQA、GQA 三者的 KV cache 大小差多少?各自牺牲了什么?
  11. 位置编码用绝对还是相对?要外推到 32K,你会动哪里?
  12. KV cache 为什么能省计算但不能省显存?显存占用公式写一下。
  13. 手写二分类交叉熵,并说明为什么不用 MSE。
  14. 讲一下生成式模型的基本原理。
  15. 手写 VAE 的 loss,并解释 KL 项在干什么。
  16. VAE 的 KL 项如果权重给太大,会出现什么现象?
  17. 混合精度训练里,为什么需要 loss scaling?
  18. 梯度检查点省的是什么,代价是什么?
  19. ZeRO 的 1/2/3 阶段分别切了什么?
  20. 数据并行和模型并行,什么规模下必须换?
  21. 你训这个模型用了多少卡、多少 token、多久?MFU 算一下。
  22. 如果 loss 突然尖峰,你的排查顺序是什么?
  23. 算法题:给一堆长宽高各不相同的积木,上层长宽必须严格小于下层,求最大堆叠高度,允许旋转。

《参考解析》

复杂度推导与成本结构:单层注意力的 QK^T 与 AV 各是 2N²D,合计 4N²D;FFN 隐层按 4D 算,升维降维各 8ND²,合计 16ND²。全模型 L(4N²D+16ND²),分头不改变总量,因为 H 个头只是把 D 切成 H 份分别算再拼回。两项相等时 N=4D,N=2048、D=4096 正落在 FFN 主导的区间,「注意力最贵」只在长序列成立。这也解释了长上下文为什么改架构而不是加卡:加卡买的是吞吐,改的是系数——FlashAttention 降的是 HBM 读写不是 FLOPs,GQA、MLA 压的是 KV cache,只有稀疏与线性注意力真正动 N² 这一项。

KV cache 与注意力变体:解码第 t 步只需算新 token 的 Q,历史 K/V 复用,每步由 O(N²) 降到 O(N),这是省下的计算;但 K/V 必须常驻,占用 2·L·N·H_kv·d_head·bytes,MHA 下即 2·L·N·D·bytes,随 batch 和序列线性涨。MQA 把 H_kv 压到 1,cache 是 MHA 的 1/H;GQA 取 G 组,是 G/H。代价在表达力:MQA 掉点明显,GQA 用很小的质量损失换数倍显存和解码带宽,所以成了主流。解码是带宽瓶颈而非算力瓶颈,压 KV 直接换吞吐。

位置编码与外推到 32K:绝对位置编码查表,超过训练长度只能扩表重训,天然不能外推;RoPE 靠旋转内积只依赖相对位置,但直接拉长会让高频维度过快旋转、注意力熵变大,困惑度在窗口边界陡增。工程上一般三件套一起上:位置插值把 32K 压回训练长度内,NTK-aware 按频率分段调 base,YaRN 再补注意力温度修正;同时必须补长文继续预训练,只改公式不补数据,长窗口里的检索能力照样很差。

交叉熵与 VAE 的 KL:二分类交叉熵配 sigmoid 时梯度就是 p−y,错得越离谱梯度越大;换成 MSE 会多乘一个 σ′(z),预测饱和时梯度趋近 0,这是不用 MSE 的实质原因。VAE 的 loss 是重建项加 β·KL,KL 把后验拉向标准正态,保证隐空间可采样、可插值;β 过大会 posterior collapse——KL 被压到 0,encoder 退化成常数、decoder 干脆忽略 z,样本模糊而训练 loss 还很低。

训练工程:FP16 最小正规数约 6e-5,反传中的小梯度会下溢成 0,所以把 loss 乘 S、梯度同比例放大,更新前再除回来,动态缩放靠检测 inf/NaN 调 S;bf16 指数位与 fp32 相同,通常不用缩放。梯度检查点不存中间激活、反向重算,省的是激活显存,代价约三成算力,且 RNG 状态必须一并存下。ZeRO-1 切优化器状态、2 再切梯度、3 连参数一起切,切得越深通信越多,3 阶段每层都要 all-gather。MFU 是实测 FLOPs/s 除峰值,训练每 token 约 6 倍参数量;远低于峰值时先看并行切分、序列长度与通信占比。loss 尖峰的排查顺序是数据(坏样本、标签、截断)→ 梯度范数与学习率 → 数值溢出与缩放 → 单卡硬件和通信。

归因与手撕:问「涨了多少、怎么归到你」,要给对照而不是绝对值:灰度分桶或 switchback、把同期其他改动做正交拆解、看护栏指标有没有被牺牲,拿不出实验就老实说这是相关性。三维积木先把每块拆成三个底面并规范化长≥宽,按长降序、宽降序排序,退化成二维严格递增链,O(n²) DP 可过;同尺寸必须按宽降序排,否则会自己叠自己,「严格小于」不能写成 ≤。要优化就用树状数组或 CDQ 做到 O(n log²n)。