1. 大模型学习进入深水区后的路线选择
走到大模型系统学习的第21个节点,基本上已经脱离了“跑通一个Demo就发朋友圈”的阶段。这个阶段最明显的特征是:你开始关心显存为什么莫名其妙就爆了、推理延迟为什么忽高忽低、微调后的模型为什么在真实业务里像个“偏科生”。如果你正处在这个状态,那这篇内容就是写给你的。我会把这一节定位成整个学习路径里的“分水岭”——前面20节解决的是“能跑起来”,从这一节开始解决的是“跑得稳、跑得省、跑得对”。
先把这一节的核心范围说清楚。它主要覆盖三块内容:大模型推理与部署的工程化认知、微调策略从全参到参数高效方法的取舍逻辑、以及评测与迭代闭环的搭建思路。这三块不是孤立的,它们共同回答一个问题——当你手里有一个能用的基座模型时,怎么把它变成一个在特定场景下真正可交付的系统。适合的读者是已经掌握Transformer基本结构、跑过至少一次LoRA微调、对显存和吞吐有初步感知的开发者。如果你还没到这一步,建议先回头把前面关于注意力机制和训练循环的内容补扎实,否则这一节里的很多取舍你会觉得“凭什么是这样”。
我个人的判断是,2026年这个时间点上,大模型学习的重心已经从“模型结构创新”明显转向了“系统工程能力”。基座模型的差距在缩小,真正拉开交付质量的是你怎么做量化、怎么做批处理调度、怎么设计评测集。这一节的内容,本质上是在帮你建立一套工程直觉,而不是再教你一个新模型的名字。
2. 推理部署的工程化认知:从能跑到跑得省
2.1 显存占用的构成拆解与估算方法
很多人第一次部署模型时,最困惑的就是“为什么模型权重只有十几个G,显存却要吃掉几十个G”。这里必须把显存占用拆开看,它至少包含四部分:模型权重、KV Cache、激活值、框架与CUDA上下文开销。权重是最直观的,一个70亿参数的模型,FP16精度下大约占14GB,这个用参数量乘以2字节就能估出来。但KV Cache经常被忽略,它的计算公式是:2 × 层数 × 注意力头数 × 头维度 × 序列长度 × 批大小 × 精度字节数。以一个32层、32头、头维度128的7B模型为例,单条2048长度序列的KV Cache大约是2×32×32×128×2048×2字节,算下来接近1GB。如果你并发16条,光KV Cache就16GB,这还没算权重。
激活值和框架开销相对隐蔽,但在长序列和大batch下会迅速膨胀。我实测下来,PyTorch加CUDA上下文本身就会占掉1到2GB,这个数字在容器环境里还会更高。所以一个粗略的工程估算公式是:总显存 ≈ 权重 + KV Cache × 并发数 + 2GB基础开销 + 激活余量。激活余量我一般留权重的20%到30%作为安全垫。这个公式不精确,但足够你在选卡和设并发时有个底。
注意:不要用“模型大小”直接等同于“显存需求”,这是新手最容易踩的坑。一个14GB的模型在FP16下跑2048长度、8并发,实际显存需求往往在24GB以上。
2.2 量化方案的取舍:INT8、INT4与GPTQ的适用边界
量化是省显存最直接的手段,但不同量化方案的代价差异很大。INT8量化通常能把权重压到原来的一半,精度损失在大多数任务上几乎感知不到,适合对质量敏感但显存紧张的场景。INT4量化能把权重压到四分之一,但精度损失开始变得不可忽略,尤其是在数学推理和代码生成这类对数值敏感的任务上。GPTQ这类训练后量化方法的好处是不需要重新训练,直接对权重做校准,落地成本低;缺点是校准集的选择会显著影响量化后的表现,校准集和实际业务分布偏差大时,掉点会很严重。
我的经验是,量化方案的选择要跟着业务容错率走。如果是客服问答这类容错率高的场景,INT4加GPTQ完全够用,吞吐能翻倍;如果是医疗、金融这类对准确性要求极高的场景,宁可多花显存上INT8,甚至保持FP16。还有一个容易被忽略的点:量化后的模型在长序列上的表现往往比短序列更差,因为误差会随序列累积。所以如果你的业务是长文档处理,量化前一定要用长序列样本做验证。
2.3 批处理调度与吞吐优化的实操思路
吞吐优化的核心是让GPU尽量不空转。最朴素的做法是静态批处理,攒够一批再送进去,但这样首条请求的延迟会很高。更实用的是连续批处理(continuous batching),它允许新请求在旧请求还没结束时插入,把GPU的利用率拉满。vLLM这类推理框架之所以流行,很大程度上就是因为它把连续批处理做成了默认能力。
但连续批处理不是银弹。它会让单条请求的延迟变得不可预测,因为你的请求可能和一堆长序列挤在一起。所以如果你的业务对P99延迟有硬要求,就需要在吞吐和延迟之间做权衡。我一般的做法是给不同优先级的请求分队列,高优先级走小batch低延迟通道,低优先级走大batch高吞吐通道。另外,prefill和decode阶段的资源竞争也很关键,长prompt的prefill会阻塞decode,导致已经在生成的请求卡顿。把prefill和decode分离部署,或者用chunked prefill把长prompt切块,都是实测有效的缓解手段。
3. 微调策略的取舍:全参、LoRA与更多选择
3.1 全参微调的代价与适用场景
全参微调是最“暴力”也最直接的方法,所有参数都参与梯度更新。它的优势是模型容量完全释放,理论上能拟合最复杂的任务分布。但代价也很明显:显存需求大约是推理的3到4倍,因为除了权重还要存梯度、优化器状态和激活值。一个7B模型全参微调,FP16下没有80GB显存基本不用想。而且全参微调容易过拟合,尤其是在数据量不足万条的情况下,模型会迅速记住训练集,泛化能力断崖式下跌。
那什么时候该用全参?我的判断标准是:任务和基座模型的预训练分布差异极大,且你有至少十万条高质量标注数据。比如你要把一个通用对话模型改造成特定领域的结构化信息抽取模型,任务形态变化很大,LoRA的低秩假设可能不够用,这时候全参微调才值得上。否则,绝大多数场景下LoRA是更理性的起点。
3.2 LoRA的秩选择与目标模块配置
LoRA的核心思想是用低秩矩阵近似参数更新,从而大幅减少可训练参数量。秩(rank)是最关键的参数,它决定了低秩近似的表达能力。秩太小,模型学不动,loss降不下去;秩太大,参数量上去了,LoRA的优势就没了。我的经验是,秩从8开始试,任务简单就4,任务复杂就16或32,超过64的秩在大多数场景下收益递减明显。你可以做一个简单的消融:固定其他条件,只改秩,看验证集loss的下降曲线,拐点就是合适的值。
目标模块的选择同样重要。早期实践只对注意力层的q和v做LoRA,后来发现把k、o以及FFN层也加进去,效果会更好,但参数量也会增加。我一般先对q、v、k、o四个注意力投影层做LoRA,如果效果不够再扩展到FFN。还有一个细节是LoRA的缩放系数alpha,它和秩配合决定更新幅度,常见做法是设成秩的两倍,但这个不是铁律,任务差异大时需要调。
3.3 数据质量对微调结果的决定性影响
这一条我要单独拎出来说,因为它是被低估最严重的因素。很多人花大量时间调秩、调学习率,却用着格式混乱、标注不一致的数据,最后效果不好还以为是方法问题。实际上,在微调这件事上,数据质量的权重远大于超参数。一千条干净、格式统一、覆盖任务边界的样本,效果往往好过一万条噪声数据。
具体怎么做?第一,统一指令格式,输入输出的模板必须严格一致,不要一会儿用“问题:”一会儿用“Q:”。第二,做数据去重和去泄漏,训练集里不能出现和验证集高度相似的样本,否则评测结果虚高。第三,控制类别平衡,如果任务有多个意图,每个意图的样本量不要差太多,否则模型会偏向多数类。第四,留出足够的困难样本,全是简单样本训出来的模型在真实场景里会崩得很快。我踩过的坑是:早期用爬来的数据直接微调,loss降得很漂亮,上线后才发现模型学会了数据里的各种脏格式,输出乱七八糟。
4. 评测闭环:让迭代有据可依
4.1 自动评测与人工评测的分工
评测不是训完模型跑个分数就完事,它应该是一个持续闭环。自动评测适合快速迭代,比如用BLEU、ROUGE这类指标看生成质量的大致趋势,或者用规则匹配看格式合规率。但自动指标和人类感知的相关性经常不高,尤其是开放式生成任务。所以人工评测不可省,但也不能全量人工,成本扛不住。
我的做法是分层:自动评测做全量回归,人工评测做抽样验证。每次迭代先跑自动指标,如果指标明显下降就直接回滚,不用浪费人力;如果指标持平或上升,再抽100到200条做人工打分,重点看边界case和失败模式。人工评测的维度要固定,比如相关性、流畅度、事实准确性、格式合规,每个维度1到5分,评分标准要写成文档,避免不同标注者理解不一致。
4.2 构建领域评测集的实操要点
通用评测集(如MMLU、C-Eval)能反映基座能力,但反映不了你的业务表现。所以必须构建自己的领域评测集。构建时要注意几点:第一,评测集要从真实业务分布里采样,不能只用公开数据,否则评测和上线是两回事。第二,评测集要覆盖任务的各个子类型,比如你的业务有五种意图,每种都要有足够样本。第三,评测集要定期更新,因为业务分布会漂移,半年前的评测集可能已经不代表当前场景了。第四,评测集要严格隔离,绝不能出现在训练数据里,这个前面提过,但值得再强调一次。
我一般会维护一个“黄金评测集”,规模在500到1000条,由业务专家标注,作为最终验收标准。同时维护一个更大的“回归评测集”,规模几千条,用自动指标跑,用于日常迭代的快速反馈。两套集子分工明确,黄金集不轻易动,回归集可以随业务扩展。
4.3 失败模式分析与迭代优先级排序
评测的价值在于暴露失败模式,而失败模式决定了下一轮迭代的方向。我习惯把失败样本按类型归类:是事实错误、格式错误、指令遵循失败,还是拒答不当?每类的占比是多少?然后按“影响面×修复成本”排序。影响面大且修复成本低的先做,比如格式错误往往改改prompt或加几条格式样本就能解决;影响面大但修复成本高的,比如事实错误,可能需要引入检索增强或重新微调,排后面但要立项。
这里有个反直觉的经验:不要试图一次性解决所有失败模式。大模型的失败模式是长尾的,你修好一类,另一类可能冒出来。正确的做法是每轮迭代聚焦一到两个主要问题,验证有效后再推进下一个。贪多求全的结果往往是改了一堆东西,最后不知道哪个起了作用,也没法归因。
5. 常见问题与排查技巧实录
5.1 显存溢出与性能异常的排查路径
显存溢出(OOM)是最常见的报错,但原因可能有很多。我的排查顺序是:先看是不是batch或序列长度设太大,这是最常见的原因,把batch减半或序列截断试试;再看是不是KV Cache没释放,有些框架在请求结束后缓存没清,跑久了就爆;然后看是不是有内存泄漏,比如在推理循环里不断创建新tensor没释放;最后才怀疑框架本身的显存管理问题。性能异常(比如吞吐突然下降)的排查类似,先看GPU利用率,如果利用率低但延迟高,多半是CPU侧的数据预处理成了瓶颈;如果利用率高但吞吐低,可能是batch太小或kernel效率问题。
下面这张表是我整理的常见问题速查,覆盖了大部分高频故障:
| 现象 | 可能原因 | 排查动作 | 解决方向 |
|---|---|---|---|
| 启动即OOM | 权重加载精度过高 | 检查加载时的dtype | 改用INT8或INT4加载 |
| 运行中OOM | KV Cache累积 | 监控显存随请求数变化 | 限制并发或启用分页缓存 |
| 吞吐低但GPU空闲 | 数据预处理瓶颈 | 看CPU利用率和IO等待 | 预取数据或异步加载 |
| 延迟抖动大 | 长短请求混批 | 统计请求长度分布 | 分离长短请求队列 |
| 微调loss不降 | 学习率过小或秩过小 | 打印梯度范数 | 调大学习率或秩 |
| 微调后泛化差 | 过拟合或数据泄漏 | 对比训练验证loss | 加正则或清洗数据 |
5.2 微调不收敛与过拟合的应对
微调不收敛通常有几个信号:loss震荡剧烈、loss下降极慢、或者loss降了但验证集不降。震荡剧烈多半是学习率太大,LoRA的学习率一般比全参微调大一个量级,但也不是越大越好,1e-4到3e-4是常见区间,超过就容易震荡。下降极慢可能是秩太小或者目标模块没选对,试着加秩或扩展LoRA到FFN层。验证集不降就是过拟合的典型表现,这时候要么加数据,要么加dropout,要么早停。
过拟合还有一个隐蔽的原因:训练轮数太多。LoRA微调通常1到3个epoch就够,超过3个epoch基本就是在记忆训练集了。我见过有人训10个epoch,训练loss降到接近0,验证loss却一路飙升,这就是典型的过拟合。早停策略一定要有,验证loss连续两轮不降就停。
5.3 推理结果不稳定的归因方法
推理结果不稳定,同一个输入两次输出差异很大,这个问题在生成任务里很常见。首先要区分是采样策略导致的还是模型本身的问题。如果temperature设得高,输出本来就有随机性,这是正常的。如果temperature设成0(贪心解码)还不稳定,那可能是数值精度问题,比如量化后的模型在logits上有微小扰动,导致argmax结果跳变。这时候可以试试提高精度或者用beam search稳定输出。
还有一种不稳定是“时好时坏”,同一批请求里有的质量高有的质量低。这往往和输入长度有关,长输入的注意力被稀释,模型容易丢失关键信息。解决办法包括:在prompt里把关键信息前置、用检索增强补充上下文、或者对长输入做分段处理再汇总。我实测下来,把关键指令放在prompt最前面,比放在中间或最后,遵循率能高出一截。
6. 工程直觉的建立比工具记忆更重要
走到这个阶段,你会发现工具和框架更新得飞快,今天流行的推理框架明天可能就被替代,但底层的工程直觉是相对稳定的。什么是工程直觉?就是看到一个模型规模,能大致估出显存需求;看到一个任务描述,能判断该用全参还是LoRA;看到一组评测结果,能定位到问题出在数据还是方法。这些东西没有捷径,只能靠一次次踩坑和复盘积累。
我自己的习惯是每次部署或微调后都写一份简短的复盘,记录当时的配置、遇到的问题、解决过程和最终效果。时间长了,这份复盘就成了我自己的“经验库”,遇到新问题先翻一翻,往往能找到相似的场景。这个习惯看起来笨,但比任何教程都管用,因为它是你自己的数据。
最后分享一个我常用的判断准则:当你在两个方案之间犹豫时,选那个更容易回滚、更容易归因的方案。大模型系统的不确定性太高,能快速试错、快速定位问题的方案,长期看比理论最优的方案更有价值。这个准则帮我省下了大量在“调参玄学”里打转的时间。