背景我在 8GB 显存的 RTX 4060 Laptop 上跑一个小型后训练研究的评测管线Qwen3-0.6B三个数学基准共 2119 题greedy 解码最长 512 新 token。第一版实现慢到不可用本文记录完整的归因过程哪些假设被排除了、真正的瓶颈在哪、为什么看起来显然的优化只拿到 1.7 倍收益、最终方案为什么成立。所有数字均为本机实测测试条件统一为 SFT-2K LoRA 适配器 GSM8K 子集。1. 症状评测 2119 题要一天半第一版评测实现是最朴素的写法逐题构造输入、model.generate()单条贪心、写文件。跑起来的实测速度是4-bit 量化权重下单条约 18 秒/题。按 2119 题算一轮评测 10 小时以上——而我的实验设计里有五轮评测Base 两个 SFT 两个 DPO评测总时间会超过全部训练时间。更糟的是我一度用三个评测进程并行来救实测单题速度反而恶化到约 24 秒——三个进程在一张卡上互相踩总吞吐不升反降。先杀掉并行回到单进程从头归因。2. 归因三个假设两个被排除假设一有残留进程在抢卡。排除。用nvidia-smi和进程命令行逐个核对 GPU 上的计算进程确认测试期间独占。假设二KV Cache 没开生成退化了 O(n²)。这是最可疑的一个——因为训练脚本里明确写着model.config.use_cache False梯度检查点的要求。如果这个状态被带进评测加载的模型每生成一个 token 都要重算整个前缀。实测在评测加载路径上打印model.config.use_cache结果为True。假设排除Cache 正常工作。假设三真凶Windows 显示驱动模型WDDM下的内核启动开销 bitsandbytes 反量化成本。这两个因素单独看都合理合起来解释了全部现象WDDM 的每次内核启动有额外调度开销而 HFgenerate()的解码循环是逐 token 驱动的——每个 token 都要过一遍启动采样核 → 启动量化/反量化核 → 启动注意力核的循环。0.6B 的小模型计算本身只要几毫秒每步的固定开销占了绝对大头4-bitbitsandbytes NF4线性层在每次前向都要做反量化这既是额外的内核数量也是随批量线性增长的计算量。3. 四组对照把两个变量拆开控制变量同一适配器、同一 8 题 GSM8K 子集、同一 greedy 与 512 token 上限只改量化与否和批量大小配置总耗时8 题折算相对提速4-bit batch 1原始实现141.8s17.7s/题1×4-bit batch 883.5s10.4s/题1.7×bf16 batch 196.2s12.0s/题1.5×bf16 batch 8最终方案20.1s2.5s/题7×这张表里有两个反直觉的地方值得展开。反直觉一4-bit 下批量化几乎没用只有 1.7 倍。直觉上批量 8 应该接近 8 倍——每步的固定调度开销被 8 个样本摊薄。但 4-bit 线性层的反量化计算量随批量线性增长batch 8 时每步的矩阵计算变成了 batch 1 的约 8 倍把摊薄固定开销省下的时间又吃回去了。实测每步耗时batch 1 约 63ms → batch 8 约 163ms。固定开销主导的场景下只有固定开销小的方案bf16 融合内核才能兑现批量化收益——bf16 batch 8 每步约 39ms摊薄效应才显现出来。反直觉二bf16 比 4-bit 慢不了反而快。评测时把权重从 4-bit 换成未量化 bf160.6B 模型仅 1.2GB 显存8GB 卡毫无压力单条 batch 1 从 17.7s/题 降到 12.0s/题——原因是 bf16 线性层的内核数更少、没有反量化步骤。量化 更快是小模型推理里的常见误区量化省的是显存和大模型的访存当瓶颈根本不在显存和算力、而在每步固定开销时量化的额外内核反而是纯负担。4. 方案落地与协议一致性最终评测实现bf16 非量化权重 batch 8 左填充left padding批量贪心解码批量大小走配置文件训练侧的 4-bit QLoRA 协议一字未动。批量贪心有一个必须诚实交代的细节左填充 批处理会引入浮点级数值漂移。填充位参与注意力掩码屏蔽但反量化与矩阵归约的顺序变了512 步解码下来贪心路径可能分叉。我的 A/B同 8 题分别用 batch 1 与 batch 8 跑7 题输出完全一致、1 题生成路径分叉导致答案翻转。处理方式不是消除差异消除不了而是协议一致性所有参与对比的模型Base / SFT×2 / DPO×2使用完全相同的批量评测实现——行级输出可能和假想的单条评测不同但五组数字之间的对比是公平的。这在一个以对比为核心的研究里是底线。5. 意外收获小模型上 KV Cache 是负收益归因过程中顺手跑了一个补充实验用我自己从零实现的 30M 参数 Decoder Transformer训练细节见系列第三篇之外的小仓库测 KV Cache 的收益结果是负的模型规模有 Cache无 Cache“加速比”3.3M 参数142 tok/s474 tok/s0.30×30M 参数65.7 tok/s93.4 tok/s0.70×KV Cache 省的是重复计算代价是每步额外的缓存读写和缓存管理逻辑。当模型小到无缓存单步计算 缓存管理开销时Cache 就是纯亏的——再加上 WDDM 的启动开销放大了每步的固定成本负收益更明显。**教科书上的KV Cache 加速自回归生成是有适用域的这个域的左边界比多数教程暗示的要靠右得多。**这个数据放在报告里比放在教程里有价值——它提醒读者性能结论必须带规模和环境。6. 经验清单先归因再优化。三个假设排掉两个剩下的才值得动代码。use_cache那次排查花了十分钟救了我一次错误的修复。小模型 WindowsWDDM场景下每步固定开销是第一瓶颈计算量和显存反而次要。量化的收益要看瓶颈在哪省显存是真的提速在小模型上不成立甚至为负。批处理收益 摊薄的固定开销 − 随批量增长的计算量两者谁主导取决于实现有没有反量化这类随批量线性增长的步骤。对比实验的公平性来自协议一致不是来自和教科书写法一致。行级浮点差异无法消除但可以让所有被比较的对象共享它。并行不是万能药GPU 已饱和时三个评测进程并行只会互相踩——总吞吐不变尾延迟变差。硬件RTX 4060 Laptop 8GB软件栈PyTorch 2.8.0cu126、transformers 5.6.1、bitsandbytes 0.49。本文的完整评测管线与五组对比数据https://github.com/fangjianzhi/small-llm-post-training文中的从零 Transformer 与 KV Cache 实测https://github.com/fangjianzhi/tiny-transformer-lab系列文章①《Qwen3-0.6B 后训练实践一次被数据否定的预注册假设》③《LLM 数据管线缺陷实录》