拓冰建站拓冰建站
首页 / 资讯中心 / 正文

大模型训练微调推理全链路解析:从LoRA到vLLM的工程实践

我从 2023 年起持续在做大模型训练、微调、推理框架相关的项目GitHub 上那些热门的框架基本都折腾过一轮。很多人一上来就问“用大模型跑个对话要什么显卡”“LoRA 和全量微调到底差多少”“Ollama 和 vLLM 哪个好用”但很少有人先把训练、微调、推理这条链路底层的关系理清楚。这篇文章我会按真实项目推进的顺序来写尽量把每一步的选型理由、资源计算、常见坑位都讲明白希望能帮还在门外的朋友少走一段弯路。我要覆盖的范围包括预训练和微调到底在做什么微调之前怎么算数据量、显存和时间全量微调、Freeze 微调、LoRA 微调的取舍训练框架 Llama-Factory 与分布式训练的配合推理框架 Ollama、vLLM 的适用边界以及工程落地时最容易被忽略的模型评测问题。如果你正准备训练自己的数据集或者想把开源模型部署到业务环境这篇基本能对应上你接下来要经历的过程。1. 整条链路里训练、微调、推理的分工与底层关系很多人最初接触大模型时会把“训练”“微调”“推理”这三个词混在一起。其实这是三种完全不同的操作它们处理的数据、消耗的资源、使用的软件栈都不一样。我在前面的项目里踩过最深的坑就是没把链路拆开拿到一个训练框架就以为能直接干完所有事结果卡在一堆基础概念上。1.1 预训练是在制造一个“通才”预训练的目标是让模型从海量文本中学习语言的统计规律。这个阶段的数据通常是 TB 级别的网页、书籍、论文、代码模型通过下一个词预测任务把参数逐步调整到能生成流畅自然语言的状态。你可以把它理解成培养一个知识面极宽的“通才”它知道语法、常识、推理模式但不一定知道你要它回答的具体业务问题。这个阶段不是一般团队能碰的。一张 H100 80GB 显卡跑 7B 参数模型如果用 BF16 精度光模型参数就要占 14GB 左右加上优化器状态、梯度、激活值单卡根本装不下。实际项目里做预训练至少是几十张卡起步还要考虑数据清洗、分词器训练、断点续训、训练稳定性等一系列问题。所以对大多数开发者来说预训练只需要理解原理真正动手指的是下面两个阶段。1.2 微调是把通才改造成领域专才微调是指在预训练模型的基础上用特定领域的数据继续训练模型。它和预训练最大的区别在于数据规模和训练目标。比如你手里有几千条客服问答对想让模型学会你公司的业务口径这时候模型不需要从头学习语言只需要调整一小部分能力把“说话方式”和“业务知识”对齐到你的场景。微调又有很多种做法最极端的是全量微调所有参数都会更新省钱一点的做法是 Freeze 微调冻结大部分层只训练少部分参数最流行的是 LoRA 微调额外插入少量低秩矩阵训练时只更新这些新参数。具体选哪种取决于数据量、显存、效果要求这个我在第 3 部分会详细展开。1.3 推理是把模型变成能用的服务推理是模型训练完成之后的阶段输入一段文本模型生成一段输出。它和训练完全是两个方向训练是不断调整参数让损失下降推理是固定参数做前向计算。因为参数不再变化推理框架可以针对这个特点做大量优化比如 KV Cache、批处理调度、量化加速。我早期混淆训练和推理时以为微调完模型直接拿原来的训练代码就能部署。实际上训练框架通常没有做服务化设计单卡吞吐量也不够。后来我统一用“训练框架出权重推理框架做服务”的方式把两者彻底分开问题的复杂度才降下来。1.4 三个阶段的资源消耗差异这里我用一张表把三个阶段的典型资源需求列出来方便你对照自己的硬件条件阶段典型数据规模显存需求示例7B 模型 BF16主要依赖预训练TB 级单卡不够需多卡集群数百 GB 以上显存总量分布式训练框架、大数据清洗微调千条到百万条全量约 120GBLoRA 约 20GB 左右Transformer 训练库、PEFT 库推理单次请求上下文约 14GB 以上按量化等级可降到 4-8GB推理服务框架、量化工具这张表不是精确数值但能反映一个现实同样的 7B 模型微调和推理的资源需求完全不是一个量级。所以做项目时先用推理的需求去判断“跑不跑得动”再用微调的需求去判断“练不练得起”逻辑就清楚了。2. 微调之前必须算清楚的三笔账数据、显存、时间我接手过好几个“昨天想做模型今天就想出效果”的项目。说实话这种项目很少有成的因为微调不是拿数据往模型里一灌就行它本质上是一个资源约束问题。你必须在动手前算清三笔账数据账、显存账、时间账。2.1 数据账指令微调不是简单堆文本指令微调Instruction Tuning是目前微调最主流的形态它的数据格式不是纯文本而是“指令 输入 输出”的结构。我见过太多人直接拿行业报告、产品介绍去微调结果模型学会了文本风格但问它具体问题时仍然胡说八道。根本原因是数据类型和下游任务不匹配。以 Qwen 这类模型为例标准格式大致如下{ instruction: 计算下面两个数的和, input: 3 5, output: 8 }数据量上我对普通业务场景的经验是几千条高质量数据就能看到明显效果变化几万条能把特定任务做得比较稳超过十万条之后投入产出比会明显下降。质量比数量重要得多数据里如果混着大量重复、错误、不一致的答案模型会学到“在特定对话模式下随便答一个相似内容就好”的坏习惯。2.2 显存账从 BF16 参数量推导最低显存7B 模型用 BF16 存储每个参数占 2 字节所以光权重就是 14GB。训练时还需要额外存储梯度又是 2 字节每参数以及优化器状态。以常用的 AdamW 优化器为例它要保存一阶动量 m 和二阶动量 v加起来又是 4 字节每参数。这样算下来模型权重: 7B * 2 14GB 梯度: 7B * 2 14GB 优化器状态: 7B * 4 28GB 基础训练显存需求: 56GB这还不算激活值。如果你的批次大小、序列长度稍微大一点24GB 显存的卡跑 7B 全量微调基本是做梦即使勉强塞进去也会因为激活值不够而 OOM。这也解释了一个现象很多人 3090、4090 买回来发现自己只能跑 LoRA原因就在这里。我在第 4 部分会具体说怎么通过 DeepSpeed ZeRO 或 FSDP 把优化器和梯度分散到多卡上这里先记住全量微调和 LoRA 的显存差不是 1 倍两倍而是数倍差距。2.3 时间账训练吞吐量与步数的粗算公式显存够不够看硬件训练时间则看吞吐量。你可以先用下面的粗算公式估算一次完整微调需要多长时间总步数 (数据条数 × epoch 数) / ( batch_size × 梯度累积步数 ) 训练时间 ≈ 总步数 × 单步耗时单步耗时取决于显卡算力、序列长度和模型大小。拿 A100 80GB 来说7B 模型做 LoRA序列长度 2048单步大概能跑 1-2 秒如果是全量微调单步耗时可能翻好几倍。举个例子你有 10000 条数据batch_size 是 4epoch 是 3不累计梯度那总步数就是 7500 步以单步 1.5 秒算总时间约 3.1 小时。看着不夸张但这是 LoRA 且只有 1 万条数据的情况。数据量上到十万条、序列长度再加到 4096时间就会直接炸到几十小时。2.4 算账之后发现本地跑不动怎么办算完账之后你会发现本地单卡跑微调是很痛苦的事情。我常用的调整策略有四种降低数据量和 epoch 数先跑通流程再说换 LoRA 或 QLoRA把训练显存压到 16GB 以内租用云 GPU按小时付费用完即释放如果只是推理需求就不微调直接用 RAG 或提示词工程解决。顺序也很重要先判断任务是否需要微调再用低成本方式验证最后才上大规模训练。否则一上来就往完整训练方案里冲钱和时间都消耗不起。3. 全量微调、Freeze 微调与 LoRA 微调选型逻辑和实际表现微调方式的选择不是“哪个火用哪个”它取决于你手里有什么、你想要什么。这里我把三种主流方式放在一起对比顺带说一下我在项目中各自的适用场景。3.1 全量微调效果好但多数人玩不起全量微调会更新模型所有参数理论上对“改变模型领域能力”来说效果上限最高。如果你要做的是把一个通用模型变成某个垂直行业的专家并且你有足够数据全量微调通常能带来更稳定的提升。问题是它的工程门槛。按照第 2 部分的显存估算7B 模型全量微调在 BF16 下至少要 56GB 以上显存这还不考虑激活值。单张 A100 80GB 都紧巴巴的更别说消费级显卡。我遇到真正需要全量微调的场景基本都是数据量在十万级以上、业务领域特征特别明显的项目。如果你只有几千条数据全量微调不仅慢还容易把预训练学到的通用能力冲掉出现灾难性遗忘。3.2 Freeze 微调折中方案容易被忽略Freeze 微调介于全量和 LoRA 之间它的做法是冻结大部分参数只训练最后几层或者部分层。相比全量微调显存和训练时间大幅下降相比 LoRA它没有引入新的低秩矩阵模型结构完全不变。我在一个项目里测试过只训练模型的最后 8 层7B 模型在 24GB 显卡上居然能跑起来。效果方面如果任务和输出格式强相关比如统一回复模板、格式化输出Freeze 微调足够用。但它的缺点是调整层数很依赖经验层选多了显存和耗时上升选少了效果不明显。我在实际项目中把它当成 LoRA 的辅助手段比如 LoRA 训练效果不佳时用 Freeze 微调作为对照实验。3.3 LoRA 微调低秩适配器的原理与提示LoRA 是目前最主流的微调方式。它的核心思想是冻结原模型权重在 Transformer 层里额外注入低秩矩阵只更新这些注入的参数。直观理解原模型参数动不了那我就在旁边接几个小旋钮通过调整小旋钮来影响整个模型的输出方向。LoRA 的优点非常突出显存占用小7B 模型在 24GB 显卡上可以跑训练速度快只更新极少量参数每个业务领域可以保存一个很小的 LoRA 权重文件随时切换。实际使用中我会额外配合 QLoRA也就是在 LoRA 的基础上把原模型 4bit 量化。这样一来显存占用更低但训练速度通常会下降因为 4bit 反量化需要额外计算。如果显卡只有 8GBQLoRA 几乎是唯一能训练 7B 模型的方法。3.4 我如何确定用哪种微调方式我自己的判断标准是下面这一串问题数据量是否超过 1 万条是考虑全量微调否LoRA。显卡显存是否超过 48GB是可以试 Freeze 或全量否LoRA/QLoRA。模型是否需要彻底改变领域风格需要全量或大 rank LoRA不需要小 rank LoRA。是否是多人协作、需要频繁切换任务是LoRA 更方便因为可以按任务保存不同适配器。可能有人觉得全量微调才是“真的训练”但工程上最终看的是指标不是手段。我见过不少项目用 LoRA 取得足够好的效果却因为非要全量微调而拖慢了上线节奏这是典型的决策失误。4. 训练和微调的主流框架怎么选Llama-Factory 与分布式训练的取舍训练框架是很多人开始动手时第一个纠结的地方。我的建议是不要试图自己写训练循环先用成熟框架跑通再逐步理解底层。当前生态里我最常用的是 Llama-Factory配合 DeepSpeed 或 FSDP 做分布式扩展。4.1 Llama-Factory 为什么能成为日常主力Llama-Factory 像一个微调工具箱把全量微调、Freeze、LoRA、QLoRA 都封装好了还支持很多主流的预训练模型。我最早被它吸引是因为它提供 WebUI后来真正留下来是因为它在数据格式、参数配置和断点续训上的处理都很成熟。一个很基本的启动命令是这样llamafactory-cli train \ --model_name_or_path Qwen/Qwen2.5-7B-Instruct \ --stage sft \ --finetuning_type lora \ --dataset my_dataset \ --output_dir ./output \ --per_device_train_batch_size 4 \ --learning_rate 2e-4 \ --num_train_epochs 3 \ --lora_rank 16 \ --quantization_bit 4注意几个关键参数finetuning_type控制微调方式quantization_bit 4表示使用 QLoRA 量化lora_rank是低秩矩阵的维度常用值是 8、16、32。rank 越高表示可学习的表达能力越强但也不是越高越好过高的 rank 在数据少时容易过拟合。4.2 分布式训练DeepSpeed 与 FSDP 在显存占用上的区别当单卡显存不足时需要多卡协同训练。两种主流方案是 DeepSpeed ZeRO 和 PyTorch FSDP它们都把优化器状态、梯度、模型参数分片到多张卡上。区别在于DeepSpeed ZeRO 支持 Stage 1/2/3Stage 3 把模型参数也分片显存利用率最高FSDP 是 PyTorch 原生方案和最新 PyTorch 版本兼容性好使用起来更简单。我实际用 Llama-Factory 时配 DeepSpeed 的方式是在命令里加deepspeed --num_gpus2 src/train.py \ --deepspeed ds_config.json为了便于大家理解我整理过一个对比方案可训练模型规模以单卡 24GB 为例配置复杂度适合场景单卡 LoRA7B 模型可训练低小型验证单卡 QLoRA7B-13B 模型勉强可训练低个人实验双卡 DeepSpeed Stage 313B 全量微调有一定可能中中型团队多节点 FSDP70B 级模型高正式训练任务4.3 配置要点学习率、批次大小、序列长度、epoch训练参数可以直接决定微调质量。我踩过几次坑后总结了一套默认起点学习率全量微调建议1e-5到2e-5LoRA 可以调到1e-4到3e-4。学习率过大会让损失值直接冲飞过小则收敛极慢。批次大小单卡 batch 不够时用梯度累积来等效增大批次但要记得它只是折中不会显著节省显存以外的时间。序列长度和显存强相关。2048 是常见选择如果业务问题上下文很长再用 4096。不要盲目把每个样本都截断到最大长度大量 padding 会浪费算力。epoch一般 3 个左右。如果 1 个 epoch 后损失还在持续下降可以适当增加如果验证集指标开始退步就是过拟合信号。我会在训练时同时打开日志和评估每个 epoch 存一次 checkpoint方便回滚到最佳版本。这个习惯帮我避免了好几次“训完才发现某一步参数崩了”的灾难。4.4 微调训练中的监控与断点恢复微调训练的时长通常在小时级没人能一直盯着。我从项目初期就开始做三件事打开训练日志记录 loss 和 learning rate 的变化设置 checkpoint 保存策略按步数保存而不是等训练结束才保存训练中断后使用--resume_from_checkpoint恢复。Llama-Factory 的断点续训很方便关键是配置文件里要指向同一个 output 目录。我见过有人因为改动了训练参数后再恢复结果加载旧权重和新参数不匹配直接报 shape mismatch。断点恢复时最好只恢复权重和优化器状态不要再改动模型结构。5. 推理框架不是万金油Ollama、vLLM 与本地部署的真实边界训练完成只是开始上线还得靠推理框架。这里最大的误区是“什么工具火就用什么”。Ollama 和 vLLM 解决的问题不一样面向的场景也不一样用错地方就会特别难受。5.1 从训练产物到推理服务中间还有一次转换大多数训练框架产出的 checkpoint 是模型权重文件但推理框架通常不一定能直接加载。比如你用 Llama-Factory 训练得到 LoRA 权重要先合并回原模型导出为新权重或者直接把 LoRA 适配器挂到基座上做增量加载。我在部署时常做的一步是# 以 Llama-Factory 导出合并后的模型 llamafactory-cli export \ --model_name_or_path Qwen/Qwen2.5-7B-Instruct \ --adapter_name_or_path ./lora_output \ --export_dir ./exported_model \ --export_size 4导出的模型还需要检查 tokenizer 文件和配置文件是否完整否则推理框架加载时会报一堆莫名错误。这块很容易被忽略但它决定了你能不能顺利进入下一步。5.2 vLLM 为何适合高并发PagedAttention 与 Continuous BatchingvLLM 是目前我把业务服务上线时的首选。它的核心改进来自 PagedAttention类似操作系统里的虚拟内存分页机制把每个请求的 KV Cache 切分成固定大小的块极大减少了显存碎片和浪费。另一个关键特性是 Continuous Batching意思是模型不用等当前批次所有请求都生成了再处理下一批而是一个请求完成就立刻插入新请求。这些优化直接带来的结果是同样一张卡vLLM 可以服务的并发请求数远高于原生 Transformer 推理代码。我部署 7B 模型在单张 A100 上开 vLLM 后大约能支持几十个并发请求换成原生方式没几个请求显存就满了。启动 vLLM 服务通常只需要一条命令vllm serve ./exported_model \ --tensor-parallel-size 2 \ --max-model-len 8192 \ --gpu-memory-utilization 0.9tensor-parallel-size指定使用几张卡max-model-len控制最大上下文长度gpu-memory-utilization决定给缓存留多大空间。这三个参数和显存使用量直接挂钩启动之前最好用nvidia-smi确认空闲显存。5.3 Ollama 适合个人与桌面端集成与限制Ollama 的优势是简单一条ollama run qwen2.5:7b就能把模型跑起来还能直接暴露 OpenAI 风格的 API。我在个人笔记本和快速 demo 里经常会用到它因为它把模型下载、量化、服务封装到了一起基本开箱即用。但 Ollama 在正式业务服务上并不总是最优选择。它对并发控制、前缀缓存、细粒度显存调优的控制力不如 vLLM 灵活。如果只是几个人用并发量极低Ollama 完全够如果业务要支撑几十上百个用户同时问问题vLLM 更稳。一个简单的经验法则个人玩、内网小范围 demo 用 Ollama要接线上流量用 vLLM。5.4 量化精度FP16、INT8、INT4 对结果的影响推理阶段量化是省显存最直接的手段。FP16 是标准精度INT8 能省一半显存INT4 能省到四分之一左右。代价是生成质量可能下降尤其在复杂推理和代码任务上。我做过一个对比实验同一个 7B 模型FP16 下回答数学题正确率 80%INT4 下降到了 65% 左右。这个下降幅度和任务类型有关开放对话影响小一些精确计算影响大一些。所以量化选项不是越低越好而要根据业务对精度的要求来选择。用 vLLM 时可以在模型加载阶段直接用 AWQ 或 GPTQ 格式权重。用 Ollama 则通常从模型库直接拉qwen2.5:7b-q4_K_M这类带量化标签的版本。5.5 推理环境里最容易踩的坑上下文长度、显存碎片、预热推理服务上线后我遇到的坑通常不是模型本身的问题而是环境和服务配置的问题上下文长度设得太大每请求的 KV Cache 占满显存并发直接掉到离谱。合理做法是先统计线上实际请求长度再设定一个刚好够用的上限。显存碎片在高并发下会逐渐增加。vLLM 通过 PagedAttention 已经缓解了这个问题但长时间运行时仍然建议定时观察显存利用率。冷启动问题。模型刚刚加载时第一次请求往往特别慢因为页面缓存、CUDA context、算子预热都还没完成。正式上线前我会用几个固定请求先跑一遍把预热问题解决掉。6. 大模型工程落地中最容易被忽略的评估问题很多项目死在“模型训练完却说不出它哪里好”。我并不是在讽刺而是说评估这件事如果没有在项目一开始就设计好后面根本没法判断该不该上线。这不是加分项而是大模型工程落地的基本盘。6.1 微调有没有让模型变笨微调一个常见副作用是“灾难性遗忘”模型在领域数据上表现变好了但通用能力下降。比如微调后的模型能准确回答你公司产品问题但问它“11等于几”它可能开始胡说八道。我每次微调之后都会在原模型的通用能力评测集上重新测一遍。方法很简单准备 100 道覆盖常识、数学、代码、逻辑的题目微调前后各跑一遍对比正确率。如果通用正确率下降超过 5%我就会考虑是不是数据比例有问题或者训练轮次多了。6.2 怎么构建评测集而不是拍脑袋看效果至少要在项目开始的第一天就留出一部分数据用于微调后的效果评估。我不建议用训练数据来测试模型因为模型见过这些答案会给你一种“效果很好”的错觉。我的做法是分三层通用能力集常识问答、数学运算、代码生成、逻辑推理用于检测模型是否“变笨”业务测试集和真实业务请求一致的样本覆盖不同难度数量至少 200 条对抗样本集故意设计边界情况、错误输入、长文本用来验证模型的鲁棒性。评测不一定每次都要算准确率。对于开放生成类任务可以让人工抽测对于结构化输出任务可以写脚本校验字段是否完整、格式是否正确。6.3 数据污染与遗忘灾难评估中看到的典型案例有一次我微调一个客服模型训练数据里包含了非常多“我不能回答这个问题”的样本。结果模型在测试集上的表现很好但实际线上运行时用户稍微问一个边缘问题模型就条件反射式地拒绝回答。这就是数据不均衡导致的行为偏移。另一次是处理长文档问答模型对训练集里出现过的文档摘要效果特别好但对新文档效果很差。这提醒我微调能教会模型“使用某种格式和风格”但不一定能教会模型“理解任意新文档”。如果业务数据是高度动态变化的更合理的方案可能是 RAG而不是微调。6.4 在线监控与回归测试模型上线后并不意味着一劳永逸。用户请求分布会变化模型服务组件的版本也可能升级。我会在线上维护一个请求日志系统定期抽样看回答质量同时准备一个“回归测试集”每次更新模型或推理框架版本时重新跑一遍。回归测试集不需要太大但必须覆盖核心业务场景。它最大的价值是让团队在更新模型时有客观依据而不是“呃感觉响应变好了”这种话。在我带过的项目里这个测试结果经常能拦截掉一些看似提升实际下降的更新。7. 做几个项目之后我对大模型落地顺序的判断最后分享一点个人体会算不上总结但确实是踩过坑之后沉淀下来的判断。如果你的目标是快速把一个大模型用起来我的建议顺序是先想清楚是不是真的需要微调再用提示词和 RAG 做一轮低成本验证最后才考虑微调。很多人一上来就训练模型本质上是把“训练”当成了目的而不是手段。我经手的项目里有相当一部分用提示词工程就能解决业务问题根本不需要动权重。如果真的需要微调也先从 LoRA 开始把数据清洗和质量控制放在第一位。一个高质量的小数据集效果往往好过一个充满噪声的大数据集。训练框架和推理框架的选择则取决于部署目标个人实验优先考虑 Llama-Factory 加 Ollama线上业务优先考虑 Llama-Factory 加 vLLM。评估体系一定不要等训练完再补从第一天就搭好否则你很难知道自己到底做出了什么。做这一行最重要的能力可能不是“把某个框架用得很熟”而是能清楚地计算资源、评估效果、控制风险。工具会迭代模型会更新但这条底层逻辑不会变。希望这篇内容能给你一个相对完整的参考框架。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门