ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

大模型训练、微调与推理:从数据工程到部署的完整实践指南

大模型训练、微调与推理:从数据工程到部署的完整实践指南 大模型训练、微调与推理这三件事放在一起写的人很多但能把它们拆开讲清楚的很少。我见过不少人一上来就问“我这张卡能微调多大的模型”结果跑起来才发现真正的瓶颈压根不在显卡而在数据、框架选型、并行策略和评测方法这些“看不见的地方”。这篇文章不打算做教科书式的罗列而是以一名一线开发者的视角把训练、微调、推理从底层逻辑到工程落地的完整链路捋一遍同时把我在实际项目中踩过的坑和验证过的经验一起放进来。如果你正准备做自己的第一个大模型应用想知道该把精力花在哪如果你已经在微调模型但遇到“loss降了、效果却变差”这种诡异问题如果你在犹豫推理框架该怎么选vLLM、Ollama、llama.cpp到底有什么区别接下来的内容应该能帮上忙。1. 先把概念账算清训练、微调、推理到底分别在做哪件事在谈任何框架、显存、数据集之前我建议把“训练、微调、推理”这三个词的含义彻底对齐。很多工程混乱、选型错误根源就是这三个概念在团队内部没对齐。这里我说的不是名词解释层面的对齐而是它们在算力消耗、数据需求、容错率、工程目标这几个维度上的巨大差异。1.1 训练让模型从零长出一个“大脑”训练是让模型在大规模语料上学习语言规律、知识结构、推理能力的过程。预训练阶段模型看到的是TB级别的文本目标是预测下一个token这个过程本质是在做“压缩”——把互联网级别的文本规律压缩进几百GB甚至几十GB的参数里。关键点在于预训练是成本最昂贵、最难调试、周期最长的阶段。拿一张H100举例训练一个7B模型动辄需要数天到数周中间一旦出现loss爆炸、梯度消失、数据质量问题可能要回滚重来。我看过不少团队在预训练阶段错误地启动了太多实验用掉了大量算力最后发现真正有效的数据配比调整其实只需要几轮实验就能定下来。所以我的建议是普通团队如果没有“从零造模型”的绝对必要不要碰预训练。你真正需要的几乎都是微调和推理。1.2 微调用更小的成本给模型“定向塑形”微调是在一个已经预训练完成的基座模型上用特定领域的数据继续训练让模型适配你的任务风格、领域知识或输出格式。这个过程比预训练便宜得多。即便是全量微调一个7B模型在消费级大显存显卡上也可以跑如果使用LoRA这类参数高效微调方法单张24GB显卡就能处理不少场景。很多人对微调有个误解以为微调是“让模型变聪明”实际上微调最擅长的是“让模型听话”。比如你希望模型按照固定JSON结构输出、模仿某种风格、回答某个垂直领域的标准话术这些是微调擅长解决的。但如果你期望微调能让14B模型拥有70B的推理能力那基本是在做梦。微调是塑形不是重新投胎。1.3 推理真正考验工程水平的环节推理阶段考验的是系统设计、并发处理、显存规划、延迟优化。同样一个模型在不同推理框架上的吞吐量可能差出数倍响应时间也可能从“基本不可用”变成“丝滑”。我见过太多团队花大量精力微调模型结果部署上线时才发现问题单实例QPS低得可怜显存占用翻倍batch一开延迟暴增。这些问题的根源往往不是模型本身而是推理框架与硬件/任务的匹配度不够。推理不是训练的反义词它是一套独立的工程学问。在理清这三个概念之后后面所有技术选型就都有了坐标体系。下面按数据工程、微调方法、推理框架、硬件规划、实战排坑这几个维度展开。2. 训练效果的起点不在模型结构而在数据工程我先说一个可能有点反直觉的结论在大模型时代模型结构的作用正在被数据工程稀释。同样的基座模型喂给它什么样的数据、用什么顺序喂、踩不踩得准数据的雷直接决定了微调效果的上限。这也是为什么我看任何项目的第一步永远是看它的数据方案而不是看它用的什么框架。2.1 数据的“三明治”结构预训练、指令微调与偏好对齐一个成熟的大模型数据体系通常是“三层三明治”。最底层是预训练语料也就是海量的网页、书籍、代码、论文。做预训练时数据清洗的核心矛盾是既要保留足够丰富的语言模式和世界知识又要清洗掉重复、低质、有毒的内容。这一层的工程实践普遍会用minhash做去重用质量分类器做打分过滤再用perplexity做一轮筛选。这里有个经验值去重比例通常在10%到30%之间如果去重率超过50%说明语料来源过于单一需要重新审视爬取策略。中间层是指令微调数据SFT数据形式是一组组“指令-回答”对。这一层的核心不是量大而是多样性、正确性和格式一致性。很多团队喜欢拼命堆数据量但SFT阶段的数据量在几千到几万条高质量样本时往往就已经能覆盖大部分任务场景堆得太猛反而容易让模型产生“话痨”或“复读机”倾向。最上层是偏好对齐数据RLHF/DPO数据通常是“同一个指令的多个回答按人类偏好排序”。偏好数据的质量直接影响模型“有礼貌不胡说”的程度是提升体验的胜负手。之所以强调这个三明治结构是因为很多人做微调时只盯着SFT数据却忽略了预训练数据阶段已经形成的“底子”。如果基座在某个领域压根没有足够的语料你再怎么微调也是地基上造楼——上层再精致底层知识是缺的。2.2 为什么数据质量比数量更关键Scaling Law的本意是模型参数量、训练数据量和最终效果之间存在幂律关系。但Scaling Law有个隐含前提数据质量必须足够高。当你喂进去一堆重复、错误、格式混乱的数据时Scaling Law会失效甚至出现数据越多、效果越差的反常现象。我自己的体会是一份高质量微调数据集至少应该满足五个条件覆盖你目标场景的绝大多数输入形态不能只有一种“标准问法”每条样本的“标准答案”必须是领域内共识正确的而非个人偏好指令和回答之间不能存在明显的因果倒置或缺失上下文数据集的格式保持统一换行、标点、特殊符号不要混用训练集和评测集不能有交叉否则评测就是自欺欺人在真实项目里我用过一个比较笨但有效的办法把数据集按来源聚类每个类目抽5%人工检查重点看三类问题——错误答案、重复样本、格式错乱。只要这三类问题的比例可控我一般控制在1%以内这个数据集就算合格。2.3 数据工程的通用方法论从文本到视觉任务很多做视觉任务的朋友会有一个疑问方法论能跨领域通用吗答案是能。比如现在大量存在的“用YOLO训练自己的数据集”的场景和“微调大模型”在数据工程上的核心套路是一模一样的。你标注好一批图像做了数据增强划分了train/val/test集然后开始训练。如果发现模型在val上指标很高、但真实场景里很差你通常会怀疑是过拟合或者数据分布不一致。同样的问题在大模型微调里也存在只是迁移到文本层面了模型在评测集上表现很好一上线面对真实用户就胡言乱语这种情况最常见的成因就是评测集和训练集的分布太相近模型根本没有学会泛化。数据工程的底层方法论是可以跨模态迁移的。无论是文本、图像还是点云数据的旋转框检测解决的核心问题永远是同一个让模型的训练分布尽可能贴近真实推理时的分布。只要把握好这个原则你在任何领域都不会走太偏。顺便提一句现在有一些开源训练平台会标榜“一键标注、一键训练”它们确实能降低入门门槛但数据质量把关这件事千万别托付给自动化工具。自动化能帮你筛掉明显垃圾但筛不掉“看起来正确、实际上错误”的样本。这类样本才是模型训练中最隐蔽的毒药。3. 微调方法论全量、Freeze与LoRA不是选择题是成本表微调是目前绝大多数团队唯一真正会跑的“训练”环节但很多人在选择微调方式时是靠“听说”而不是靠“账本”。全量微调、Freeze微调、LoRA微调各自的原理不同适用场景不同成本差异也可能超出预期。本节把这三种方式从原理到工程选择讲透。3.1 三种微调方式的底层原理差异先说全量微调Full Fine-tuning。它的做法是把预训练模型的所有参数都作为可训练参数在整个训练过程中全量更新。全量微调的优势是理论上限最高模型能够完全适应新任务的分布在某些垂直领域效果确实比参数高效方法更好。问题是它的显存开销和训练时间都很大。以7B模型为例全量微调需要存储的参数包括模型参数、梯度、优化器状态AdamW需要保存一阶动量和二阶动量这三者合计的显存占用会达到模型参数量的16到20倍。也就是说7B模型的全量微调实际需要大约112GB到140GB的显存空间单张A100 80GB根本不够必须做多卡并行或者依赖CPU offload。再说Freeze微调。它的思路是冻结模型大部分层只微调最后几层或者部分特定模块。这个方案的显存开销比全量小不少因为它只需要为可训练层保存梯度和优化器状态。但它的局限也很现实如果你需要模型掌握的是全新的知识或全新的输出格式只微调最后几层往往学不进去信息瓶颈就卡在中间层。Freeze微调更适合“风格迁移”而非“知识注入”。最后是LoRALow-Rank Adaptation。它的核心思想是在预训练模型的基础上为每个需要适配的权重矩阵添加一个低秩分解的增量矩阵。训练时只更新这个低秩矩阵原始权重完全冻结。LoRA的最大吸引力在于显存占用和可插拔性。同样是7B模型LoRA微调可能只需要10GB到16GB的显存取决于序列长度和batch消费级显卡就能跑。而且训练产物是一个小体量的LoRA权重文件随时可以摘掉或换一个对于多任务并行实验极其友好。3.2 从Qwen实操看LoRA的完整链路如果只能用一句话推荐微调方式我的答案是绝大多数场景先无脑选LoRA跑通后根据效果再决定要不要升级为Freeze或全量。以Qwen系列模型为例一个标准的LoRA微调流程通常包含几步第一准备SFT数据集。格式通常为JSON列表每个元素包含instruction、input和output三个字段。这里特别强调一下input字段的处理很多开源数据集把问题拆成instruction和input两个字段如果你的场景不需要这种拆分建议把内容合并写进instruction否则模型会出现“该听哪个字段”的混淆。第二加载基座模型和分词器。以Qwen为例建议在加载时显式指定trust_remote_codeTrue并设置模型为bfloat16精度。第三配置LoRA参数。最重要的几个参数包括r秩的大小、alpha缩放系数、target_modules要注入LoRA的模块列表。用一份我跑过多次的简化配置举例from transformers import AutoModelForCausalLM, AutoTokenizer from peft import LoraConfig, get_peft_model, TaskType model AutoModelForCausalLM.from_pretrained( Qwen/Qwen2-7B-Instruct, torch_dtypeauto, device_mapauto ) tokenizer AutoTokenizer.from_pretrained(Qwen/Qwen2-7B-Instruct) lora_config LoraConfig( task_typeTaskType.CAUSAL_LM, r32, lora_alpha64, target_modules[q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj], lora_dropout0.05, biasnone ) model get_peft_model(model, lora_config)这里面的经验是target_modules不要只盯着注意力层的q_proj、v_proj把o_proj和FFN层的gate_proj、up_proj、down_proj也加进去效果通常更稳。而r值的选择16到64是一个比较make sense的区间。r太小会限制模型适配新任务的能力上限r太大则显存和过拟合风险同步上升。lora_alpha设成r的两倍是很多项目的默认值我的经验是任务需要更大幅度变化时再适当调高alpha。第四训练参数设置。对于SFT场景learning rate通常在1e-5到1e-4之间batch size根据显存尽量拉大epoch次数看数据集规模。一个7B模型配1万条SFT数据3个epoch是一个比较稳妥的起步配置。第五合并权重并测试。LoRA训练完成后可以用merge_and_unload把LoRA权重合并回原始模型导出成一个完整的模型文件便于后续用vLLM等推理框架部署。3.3 增量训练和微调千万别混为一谈增量训练Continue Pre-training是另一类操作它和微调的差别在数据形态上增量训练用的是“纯文本”没有指令对结构目标是让模型继续学习一段新的领域语料比如企业内部文档、法律条文、医学论文库。很多人问“AnythingLLM能训练模型吗”之类的工具困惑本质上就是没分清知识库问答工具的底层用的是检索增强生成RAG它在查询时动态把相关文档拼进上下文而增量训练是把文档内化进模型参数。前者适合知识频繁更新的场景后者适合格式固定、风格统一、需要离线响应的场景。在工程资源有限的情况下我更倾向于先用RAG解决知识问题只有当RAG的效果明显不够上下文长度塞不下完整知识、检索命中率低、输出格式不稳定时才去考虑增量训练。这个选择的判断标准不是技术优劣而是成本和可维护性。4. 推理框架博弈Ollama、vLLM、llama.cpp各自在解决什么问题推理框架是工程落地的临门一脚。很多人在本地部署大模型时会首选Ollama因为它界面友好、命令行简单。但到了生产环境Ollama未必是最优选择。本节不打算做无意义的框架论战而是把主流推理方案的底层逻辑和适用边界讲清楚。4.1 连续批处理是性能分水岭先抛一个核心概念连续批处理Continuous Batching。传统推理框架处理请求是静态批处理的一组请求同时开始、同时结束如果某个请求特别长其他短请求就得等它。连续批处理的做法是在token生成过程中动态组织计算当一个请求生成完成立刻把新的请求加入到batch中当一个请求还在生成第10个token时另一个可能已经生成到第100个token两者并行处理。vLLM的PagedAttention也是异曲同工。它借鉴了操作系统的虚拟内存管理方式把KV Cache切成固定大小的块按需分配从而解决显存碎片化问题。这套机制的收益非常直观在相同显存和相同模型下使用连续批处理的vLLM通常能比朴素的HuggingFace Transformers推理高出数倍到十倍的吞吐量。这也是为什么我建议但凡你的服务需要同时服务多个用户就不要直接用transformers的generate接口做生产部署除非请求量真的很低。4.2 量化到底“伤”了什么、省了什么推理阶段的另一个关键决策是量化。把模型从FP16降到INT8参数体积直接减半降到INT4体积再减半。显存占用大幅下降推理速度在某些硬件上也会提升。但量化不是免费的午餐。你实际上在交换“模型精度”和“工程代价”。我在对比QWEN等模型在不同量化位数下的输出时发现4bit量化对复杂推理任务数学、逻辑、代码生成的负面影响确实存在但很多场景下它是可以接受的。关键要看你的任务对生成质量的边际敏感度有多高。这里给出一个经验排序7B模型在FP16下需要约14GB显存INT8下约7GBINT4下约4GB70B模型在FP16下需要约140GB显存INT8下约70GBINT4下约35GB如果你的消费级显卡只有24GB显存想本地跑70B模型基本只有INT4量化一条路。而如果你只跑7B模型24GB显存可以做到FP16甚至FP8完全没有必要牺牲精度去量化。4.3 按场景选框架的实用对照测试过多个主流框架后我总结出一张“按场景选型”的对照表基本覆盖常见的部署需求场景推荐方案原因本地快速体验、个人学习Ollama安装简单模型管理友好支持一键拉取运行高性能生产服务、高并发vLLM连续批处理和PagedAttention带来高吞吐适合API化移动端、边缘设备、CPU推理llama.cpp对CPU友好支持内存映射量化方案成熟多模型灵活切换、原型验证llama.cpp或Ollama灵活性高改配置就能换模型超低显存跑超大模型llama.cpp GGUF量化通过层式加载和MMap把部分权重放在内存里我在生产项目中最常用的组合是用vLLM起一个高吞吐的OpenAI兼容API服务配合显存较小的边缘设备上用llama.cpp做轻量推理。两者的优缺点互补能覆盖大多数业务场景。还有一点容易忽略推理框架与微调框架之间的衔接。用LoRA微调出来的增量权重能合并进原始模型后导成GGUF格式再被llama.cpp或Ollama加载也可以直接用vLLM加载合并后的Safetensors模型。如果团队同时做微调和部署建议在模型产物格式上提前约定好免得微调团队交付的产物部署团队加载不了。5. 显存账本一张多大的卡才能干活显存是大模型项目最贵的稀缺资源也是最容易拍脑袋估算出错的部分。这里我给出一个可以直接套用的估算思路同时解释并行策略中容易被忽略的通信开销。5.1 推理、微调、训练三个环节的显存估算公式推理阶段显存由三部分构成模型权重 KV Cache 激活值通常可忽略权重这块可以用“参数量 × 每参数字节数”来估算。7B模型FP16约14GBINT8约7GBINT4约4GB。KV Cache取决于序列长度、batch size和模型结构粗略估算可以用“每请求每token几百KB到几MB”量级去看实际最好用框架自带分析工具或试跑一次来确定。微调阶段要更复杂。全量微调动辄需要模型参数量的16到20倍显存没法在消费级显卡上跑。LoRA微调则只需要“模型权重冻结 LoRA增量参数 梯度 优化器状态 激活值”显存占用可以降到模型参数量的2到3倍左右。这也是LoRA最大的工程价值所在。训练阶段如果做预训练显存账本基本呈指数级膨胀。7B模型的预训练、混合精度加ZeRO优化通常需要至少40GB到80GB显存且必须多卡并行。这也是为什么普通团队不要轻易碰预训练。5.2 并行策略里最容易忽略的通信开销数据并行、张量并行、流水线并行是大模型训练显存规划里绕不开的三个词。数据并行最简单每张卡持有完整模型副本数据分批喂入每步训练后做梯度同步。它的通信开销和batch大小、梯度大小相关随着卡数增加通信会成为瓶颈。张量并行是把一个Transformer层内的矩阵计算拆分到多张卡上例如把hidden state的维度切成多段。它的单卡显存压力下降明显但每层都需要做all-reduce通信通信频繁是它的代价。流水线并行是把模型的不同层分配到不同卡上前向和反向像流水线一样推进。它的通信频率最低但可能出现GPU空载的“气泡”需要合理切分micro-batch来优化。通信是并行策略里最容易背忽略的成本。很多团队看理论吞吐觉得8卡应该达到单卡的8倍实际跑下来能到6倍就已经不错一部分算力就是消耗在梯度同步和数据传输上。所以如果你的模型一张卡能塞下就先别上多卡一张卡塞不下时优先考虑ZeRO优化把优化器状态、梯度分片到多卡再考虑张量并行和流水线并行通信开销从低到高排序也基本是这样。5.3 一张卡和八张卡的现实中位线基于我见到的真实项目情况给一个粗略的现实参考单张4090 24GB可以跑7B模型的LoRA微调可以部署7B模型的FP16推理需要控制并发也可以跑14B模型的低比特量化推理单张A100 80GB可以全量微调7B模型可以LoRA微调13B到34B模型可以部署34B模型的FP16推理单张H100 80GB比A100的显存带宽有提升适合做训练和推理混合场景四卡A100/H100可以尝试全量微调13B到34B模型适合中等规模团队的日常实验八卡A100/H100跑70B级别的全量微调比较从容也是绝大多数开源模型训练复现的基础配置如果你手里的算力低于这张表中线我的建议就是把方案往LoRA和量化方向靠。先跑通一个小模型验证效果再决定要不要升级硬件。一上来就追求70B全量微调很可能在算力规划和成本控制上就失控了。6. 实战中反复出现的三个坑过拟合、数据泄露、评测幻觉前面讲的都是方法论下面聊几个我在实际操作中反复遇到过的问题。这些问题在网上很少被系统整理但几乎每个做过微调的人都会撞上。6.1 loss降了、样本输出却像“背诵”——过拟合的识别与止损第一次做微调时我最兴奋的瞬间是看到训练loss一路走低评测集准确率也接近满分。但上线后随机抽测了几个真实问题模型输出的答案句式高度雷同甚至直接在“背诵”训练集里的原文这就是典型的过拟合信号。在大模型微调里过拟合最明显的特征是验证集loss先降后升或者验证loss在降低但生成文本出现明显重复、缺乏多样性。这背后的机制是模型在大量重复数据上记住了答案而不是学会泛化规律。止损策略就三条一是降低epoch数SFT阶段通常1到3个epoch就够二是提高数据质量把重复样本清掉三是适当增加dropout或加大LoRA的lora_dropout。如果是在做增量训练记住“数据里面的重复片段比你想的更致命”行业里有Shannon熵的统计方法可以评估语料多样性你可以用类似手段给语料库做个体检。6.2 数据泄露比过拟合更隐蔽比起过拟合数据泄露更危险因为它会让你的评测数据全面失真。所谓数据泄露是指评测集里混入了训练集中出现过的数据或者训练集和评测集的数据来源高度同源。一个典型场景从某个公开数据集里随机划分出训练集和测试集但这份数据本身收集自同一个论坛或同一个时间段的话题测试集和训练集在语义分布上高度相似。模型在评测集上跑出95%的准确率以为效果极好部署后面对真实用户输出却大跌眼镜。真实世界中用户的问题分布和你训练的领域分布往往存在不小的偏移这不叫模型变笨了而是评测体系一开始就失真了。排查方法也不复杂训练结束后随机从评测集抽几道题去训练集里做模糊匹配或embedding相似度搜索看最相似的top1样本。如果相似度极高基本可以判定数据泄露。6.3 微调后“智商下降”先别骂基座检查评测集另一个高频现象是LoRA微调一个通用大模型之后发现模型在原本擅长的通用问答、数学推理任务上变笨了。许多人第一时间归因于“微调破坏了原有能力”然后考虑做“模型合并”或“回放”。但在我排查过的案例里有很大比例其实是评测集没设计好。微调后的模型输出风格、回复长度、甚至标点习惯都变了而你还在用微调前的提示词去调用它导致输出明显不对题。这就好比一个人换了一副说话习惯但你的考题仍然是按旧习惯出的他答得再好也给你感觉“跑偏”。正确的做法是在微调前后分别固定一套评测集包含通用能力和领域能力两部分评测时使用完全相同的提示词模板和采样参数。如果通用能力确实下降再考虑用较低学习率、减少微调层数或混合通用数据来抑制。RAG方案在技术上更保守但知识管理上的可控性更强配合微调使用并不冲突。另外团队内部做微调评测时我非常建议大家建立一个“回归评测集”。它不一定要很大但要覆盖你业务最核心的20个场景每次微调后在同一个提示词下对比跑分和输出样例。我在实际项目中用这一招抓到过好几次“微调后效果看似提升但回归场景恶化”的问题省下了大量返工时间。7. 写在最后一些操作性很强的小建议这篇文章写到这该讲的原理和链路基本都覆盖了。最后分享几条我每次带项目都会反复强调的落地建议都是比较琐碎但实际能省时间的经验。第一次微调别求大先拿几百条数据跑通全链路确认数据格式、训练代码、推理服务这一套能串起来再上完整数据集。训练过程中的loss曲线和样本输出一定要同时盯。只看loss会骗自己只看样本输出又容易被个例带偏。推理服务的压测不要只测吞吐还要测长序列场景下的显存占用和延迟。很多服务在短文本下表现不错一上长文档就崩。部署前固定好随机种子保证微调结果可复现。这个动作看似简单但能让你和团队同事之间少吵很多架。每次实验记录三样东西数据集版本、模型版本、训练参数。哪怕只是随手记在一个文档里也比三个月后对着一个模型文件猜它是怎么来的强得多。大模型的训练、微调与推理本质上是一套“数据、算力、工程”三者相互钳制的系统。任何单独一方面的极致优化都可能在另一方面制造隐性成本。把这些底层逻辑理顺再去做工程决策你会发现大多数选型问题不需要靠“感觉”只需要把账算清楚。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进