
1. 大模型全链路任务平台化为什么值得认真对待大模型从训练到上线中间隔着的不是一条直线而是一整条流水线。做过的人都知道光是让一个 LLaMA-Factory 的 SFT 任务跑起来就得先配环境、拉镜像、挂数据、调参数、盯显存、看日志等 SFT 跑完想接着做 PPO 或者 reward 模型训练又是一轮新的环境折腾再往后还有蒸馏、剪枝、量化、安全评估每一步都像在换一条赛道重新起跑。CubeStudio 这类平台做的事情本质上就是把这些散落在不同脚本、不同容器、不同人手里的环节收敛成一套可以复用、可以编排、可以追溯的任务模板。我最早接触这类需求是因为团队里同时有三四个方向在推进有人在做 SFT 微调有人在试 PPO 对齐还有人在搞 int8 量化部署。每个人都有自己的 conda 环境、自己的启动脚本、自己的日志目录结果就是同一个基座模型被反复下载了七八遍数据预处理逻辑各写各的出了问题谁也说不清是哪一步引入的。后来把这些任务统一搬到 CubeStudio 上用大模型任务模板来承载才真正把“从微调到量化剪枝一站式”这件事跑通。这篇文章想聊的就是这套一站式流程到底怎么落地。核心会围绕 LLaMA-Factory 的 SFT、PPO、reward 训练以及后续的蒸馏、剪枝、量化、安全评估展开重点讲清楚每个环节在平台上怎么配置、参数怎么选、坑在哪里。适合已经跑过单机微调、想往工程化方向走的人也适合团队里负责搭训练平台、需要把零散脚本标准化的人。读完你应该能直接照着搭出一套可复现的流水线而不是停留在“知道有这么回事”的层面。2. 整体设计思路把流水线拆成可编排的任务节点2.1 为什么不是写一个大脚本从头跑到尾很多人第一反应是写一个 shell 脚本把 SFT、PPO、量化全串起来nohup 一挂就完事。我试过短期能跑长期一定崩。原因很简单大模型任务不是线性执行的中间任何一步失败你都需要单独重跑那一步而不是从头再来。SFT 跑了 20 个小时PPO 阶段 OOM 了如果是一个大脚本你得重新加载 SFT 的 checkpoint重新初始化时间全浪费在重复劳动上。CubeStudio 的任务模板思路是把每个阶段做成独立节点节点之间通过模型路径、数据路径、配置参数来衔接。SFT 节点产出 LoRA 权重或者全量权重PPO 节点消费这个权重继续训练量化节点再消费 PPO 的输出做压缩。每个节点有自己的镜像、资源规格、启动命令失败只影响当前节点。这种设计的好处是你可以针对不同阶段用不同的 GPU 规格——SFT 用 A100 80G量化用单张 4090 就够资源不浪费。另一个关键考量是版本管理。大模型训练最怕的就是“这个权重到底是哪版数据、哪版参数跑出来的”。平台化之后每个节点的输入输出都有记录模型路径带时间戳和任务 ID回溯的时候直接看任务 DAG 就行不用再翻聊天记录找“上次那个脚本”。2.2 任务模板的抽象层次CubeStudio 的大模型任务模板抽象层次大概是这样最底层是镜像里面装好了 LLaMA-Factory、DeepSpeed、vLLM 这些框架中间层是任务模板定义了启动命令、参数占位符、资源需求最上层是流水线把多个任务模板按依赖关系串起来。你实际用的时候大部分时间是在填参数和调资源而不是从零写 Dockerfile。这里有个经验不要把镜像做得太“胖”。我见过有人把 PyTorch、TensorFlow、JAX 全塞一个镜像里结果 40 个 G每次拉镜像都要等半天。正确的做法是按任务类型分镜像——SFT 一个镜像PPO 一个镜像量化一个镜像各自只装需要的依赖。CubeStudio 支持在任务模板里指定镜像切换起来很方便。2.3 从微调到量化的完整链路整条链路我习惯分成四段第一段是数据准备和 SFT把基座模型调成能听懂指令的版本第二段是对齐用 reward 模型和 PPO 把输出质量往上提第三段是压缩蒸馏、剪枝、量化三选一或者组合第四段是评估包括安全评估和性能评估。这四段在平台上就是四组任务节点每组内部可以并行组之间串行。为什么要强调这个分段因为每段的资源瓶颈不一样。SFT 吃显存和通信带宽PPO 吃显存和采样效率量化吃 CPU 和内存评估吃推理吞吐。分段之后你可以针对性地优化每一段而不是用一个通用配置硬扛所有场景。3. LLaMA-Factory 微调实操SFT、PPO、Reward 三件套3.1 SFT 阶段数据格式与关键参数SFT 是整个链路的地基。LLaMA-Factory 支持的数据格式有好几种我常用的是 alpaca 格式字段就是 instruction、input、output 三个。实际用的时候input 可以为空但字段得留着不然解析会报错。数据量方面我的经验是至少 5000 条以上才能看到明显效果低于这个量级模型基本学不到什么新东西还不如直接 prompt engineering。关键参数里cutoff_len是最容易踩坑的。默认 2048但如果你数据里有长文本比如超过 2048 token 的会被直接截断模型学到的就是半截话。我一般会先统计一下数据集的 token 分布取 95 分位数作为 cutoff_len这样既不会截断太多也不会因为个别超长样本把显存撑爆。统计方法很简单用 tokenizer 跑一遍from transformers import AutoTokenizer import numpy as np tokenizer AutoTokenizer.from_pretrained(meta-llama/Llama-3-8B) lengths [] with open(train.jsonl) as f: for line in f: item json.loads(line) text item[instruction] item[input] item[output] lengths.append(len(tokenizer.encode(text))) print(np.percentile(lengths, 95))learning_rate这块LoRA 微调我一般用 1e-4 到 5e-5全量微调用 1e-5 到 2e-5。LoRA 的lora_rank默认 8如果任务比较复杂比如要学新的知识而不是只调风格可以加到 32 甚至 64但显存占用会上去。lora_target建议设成all把所有线性层都加上 LoRA效果比只加 q_proj、v_proj 好不少代价是训练慢一点。注意LLaMA-Factory 的template参数必须和基座模型匹配。LLaMA-3 用llama3Qwen 用qwen设错了模型会学不到正确的对话格式loss 降不下去。3.2 Reward 模型训练打分器的正确打开方式Reward 模型的作用是给 PPO 提供奖励信号。训练数据是偏好对格式是 chosen 和 rejected 两条回复。LLaMA-Factory 里用reward任务类型来跑基座一般选和 SFT 同源的模型比如 SFT 用的是 LLaMA-3-8Breward 也用 LLaMA-3-8B这样表征空间一致PPO 阶段更稳。Reward 模型的 loss 是 pairwise ranking loss核心是让 chosen 的得分比 rejected 高。训练时learning_rate要小我一般用 1e-5太大了容易过拟合。batch_size可以大一点因为 reward 模型通常比 PPO 好训。评估指标看 accuracy也就是 chosen 得分高于 rejected 的比例能到 70% 以上就算可用。有个坑是数据质量。如果 chosen 和 rejected 的差异太小比如只是换了个同义词reward 模型学不到有意义的信号。我一般会人工筛一遍确保 rejected 确实有明显的质量问题比如事实错误、逻辑混乱、格式不对。数据量 1 万条左右能训出一个可用的 reward 模型再多边际收益递减。3.3 PPO 阶段显存、采样与稳定性PPO 是整条链路里最吃资源的。它同时需要四个模型actor、critic、reward、reference。actor 和 critic 要训练reward 和 reference 只推理。8B 模型全量 PPO四份权重加起来A100 80G 都够呛。所以实际生产里actor 和 critic 一般用 LoRAreward 和 reference 用全量但可以量化到 int8 推理。LLaMA-Factory 的 PPO 配置里ppo_buffer_size和mini_batch_size是关键。buffer 太小采样效率低太大显存扛不住。我一般设 buffer 为 128mini batch 为 8这样在 8 卡 A100 上能跑。ppo_epochs设 4太多容易过拟合当前 batch 的奖励。kl_coef控制 KL 散度惩罚默认 0.1如果发现模型输出开始胡言乱语说明 KL 约束太松可以加到 0.2。提示PPO 训练不稳定是常态loss 突然飙升或者 reward 断崖式下跌先检查 reward 模型是不是给了异常高分。我遇到过 reward 模型对某些模板化回复打高分导致 actor 学会了一直输出那个模板这时候需要重新清洗 reward 训练数据。3.4 在 CubeStudio 上编排三件套在 CubeStudio 里SFT、reward、PPO 是三个独立的任务模板。SFT 节点输出 LoRA 权重到指定路径reward 节点读取 SFT 的基座模型注意 reward 一般不用 SFT 后的权重而是用原始基座避免偏好被 SFT 带偏PPO 节点同时读取 SFT 的 LoRA 和 reward 的全量权重。节点之间的依赖用 DAG 定义SFT 和 reward 可以并行跑PPO 等两者都完成后再启动。资源分配上SFT 给 8 卡 A100reward 给 4 卡 A100PPO 给 8 卡 A100。如果集群资源紧张reward 可以和 SFT 错峰跑。CubeStudio 支持任务排队提交的时候指定优先级就行。4. 蒸馏、剪枝、量化模型压缩的三条路4.1 蒸馏让小模型学会大模型的行为蒸馏的核心是让一个小模型student去模仿大模型teacher的输出分布。LLaMA-Factory 本身不直接支持蒸馏但可以在 CubeStudio 里用自定义任务模板来做。我一般用 KL 散度作为损失teacher 的输出 logits 除以温度 T 后做 softmaxstudent 同样处理然后算 KL。T 一般设 2 到 4太小了分布太尖学不到暗知识太大了分布太平学不到重点。数据方面可以用 teacher 在无标注数据上生成的回复作为训练数据也可以用带标注的数据。我试过用 teacher 生成 10 万条回复然后 student 在这上面做 SFT效果比直接用原始数据好因为 teacher 的回复质量更高。但要注意如果 teacher 本身有幻觉student 会把这些幻觉也学过去所以生成数据后最好过一遍安全评估。4.2 剪枝结构化与非结构化的取舍剪枝分两种非结构化剪枝是把个别权重置零结构化剪枝是直接砍掉整个注意力头或者 FFN 维度。非结构化剪枝压缩率高但需要专门的稀疏计算库才能加速实际部署麻烦结构化剪枝压缩率低一些但直接就能在标准框架里跑出加速比。我常用的是结构化剪枝基于重要性评分砍注意力头。评分可以用头输出的方差或者梯度大小。LLaMA-Factory 没有内置剪枝我一般用torch.nn.utils.prune配合自定义脚本。剪枝后必须做恢复训练用原来的 SFT 数据再训 1 到 2 个 epoch把掉下去的精度拉回来。剪枝比例我一般控制在 20% 以内超过 30% 精度掉得太厉害恢复训练也救不回来。4.3 量化int8 与 int4 的实际效果量化是部署阶段最实用的压缩手段。int8 量化基本不掉精度int4 会掉一些但显存占用减半。LLaMA-Factory 支持导出时做量化也可以用 GPTQ、AWQ 这些工具单独做。我实测下来8B 模型 int8 量化后显存从 16G 降到 8G推理速度基本不变int4 量化后显存降到 5G 左右但生成质量在复杂任务上会有可感知的下降比如数学推理容易出错。量化校准集的选择很关键。一般用 128 到 256 条代表性数据就够了太多没必要太少校准不准。校准集要覆盖实际使用场景比如你的模型主要做代码生成校准集里就得多放代码数据。我见过有人用新闻数据校准一个代码模型结果量化后代码生成能力暴跌。注意量化后的模型在 vLLM 里部署时要确认 vLLM 版本支持对应的量化格式。GPTQ 和 AWQ 支持得比较好int4 的 bitsandbytes 格式在 vLLM 里支持有限部署前先查文档。4.4 在 CubeStudio 上串联压缩流程在 CubeStudio 里蒸馏、剪枝、量化可以做成三个独立任务模板也可以合并成一个压缩流水线。我的做法是分开因为三者不一定都用。比如有时候只做量化有时候蒸馏加量化。分开之后每个模板的输入输出清晰复用性高。蒸馏任务需要 teacher 和 student 两个模型路径资源给 4 卡 A100。剪枝任务需要原始模型和校准数据资源给 2 卡 A100。量化任务最轻1 卡 4090 就够但如果是 GPTQ 量化需要跑校准时间会长一些。CubeStudio 的任务模板里可以指定nproc_per_node和CUDA_VISIBLE_DEVICES灵活控制用几张卡。5. 安全评估与 Open 系列模型适配5.1 安全评估不能省的最后一道关模型训完、压缩完上线前必须做安全评估。评估维度包括有害内容生成率、偏见程度、隐私泄露风险、越狱攻击抵抗力。我一般用两类方法自动化评估和人工抽检。自动化评估可以用现成的安全分类器比如把模型输出喂给一个专门的有害内容检测模型统计触发率。人工抽检就是随机抽 200 到 500 条输出人工看有没有问题。CubeStudio 里可以把安全评估做成一个任务模板输入是模型路径和测试 prompt 集输出是评估报告。测试 prompt 集要覆盖各类风险场景比如诱导生成违法内容、诱导泄露训练数据、诱导输出歧视性言论。评估结果如果触发率超过阈值就得回到 SFT 或者 PPO 阶段重新调整不能带病上线。5.2 Open 系列模型的适配要点Open 系列模型比如 OpenLLaMA、OpenChat和 LLaMA-Factory 的适配主要注意 tokenizer 和 template。OpenLLaMA 的 tokenizer 和 LLaMA 基本一致template 可以用llama2或者llama3具体看版本。OpenChat 有自己的对话格式template 要设成openchat不然对话历史会解析错。另一个点是模型结构。Open 系列有些版本改了 attention 实现或者 FFN 结构LLaMA-Factory 的默认配置可能不兼容。遇到加载报错先检查model_type和architectures字段必要时在配置里手动指定。我遇到过 OpenLLaMA 的 3B 版本因为num_key_value_heads和 LLaMA 不一致导致 LoRA 注入失败后来在配置里显式覆盖了这个参数才跑通。5.3 评估结果如何反哺训练安全评估不是走形式评估结果要能指导下一轮训练。如果发现某类风险触发率高比如模型容易被诱导生成暴力内容那就在 SFT 数据里增加这类场景的安全回复或者在 PPO 阶段给这类输出更低的奖励。我一般会建一个“风险-数据-奖励”的映射表评估发现什么问题就对应调整哪个环节的数据或奖励函数。这个闭环在 CubeStudio 上可以通过任务依赖来实现评估任务输出报告如果触发率超标自动触发一个数据增强任务把风险样本加进训练集然后重新跑 SFT 或 PPO。当然全自动闭环风险较大我建议至少人工确认一步避免误判导致训练方向跑偏。6. 常见问题与排查技巧实录6.1 显存不够从 OOM 到稳定运行OOM 是大模型训练最常见的报错。排查顺序一般是先看 batch_size 是不是太大再看 cutoff_len 是不是太长然后看有没有开 gradient_checkpointing。LLaMA-Factory 里gradient_checkpointing默认开着如果关了显存占用会翻倍。DeepSpeed 的 ZeRO stage 也很关键stage 2 比 stage 1 省显存stage 3 更省但通信开销大。我一般 SFT 用 stage 2PPO 用 stage 3。如果这些都调了还是 OOM那就得考虑用 LoRA 代替全量微调或者换更小的基座模型。8B 全量 SFT 在 A100 80G 上batch_size 只能开到 2 到 4LoRA 可以开到 16 甚至 32。实际效果上LoRA 在大多数指令跟随任务上已经够用没必要死磕全量。6.2 训练不收敛loss 震荡与 reward 崩溃SFT 的 loss 应该是稳定下降的如果震荡厉害先检查学习率是不是太大可以试试减半。如果 loss 降到一定程度就不动了可能是数据量不够或者任务太简单模型已经学饱和了。PPO 的 reward 曲线更复杂初期上升、中期平稳、后期可能下降如果一开始就下降多半是 reward 模型有问题。我遇到过一次 PPO reward 一直上不去排查发现是 reward 模型的 tokenizer 和 actor 不一致导致 reward 打分完全错位。统一 tokenizer 后问题解决。所以 PPO 阶段一定要确认四个模型的 tokenizer 完全一致包括 padding token 和 special token 的设置。6.3 量化后精度暴跌校准集与格式的坑量化后精度暴跌九成是校准集的问题。校准集太小、太偏、和实际场景不匹配都会导致量化参数估计不准。我一般会从训练集里分层抽样确保各类样本都有。另外量化格式也要和推理框架匹配GPTQ 量化出来的模型用 vLLM 加载要指定quantizationgptq不指定的话会按 FP16 加载显存反而更大。还有一个隐蔽的坑是量化后的模型在长文本生成时容易重复。这是因为量化误差在自回归生成中累积导致模型陷入循环。缓解办法是调低 repetition_penalty或者用 beam search 代替 greedy search。如果还是不行就得考虑用更保守的量化配置比如 group_size 设小一点。6.4 任务编排失败依赖与路径问题CubeStudio 上任务编排失败常见原因是路径没对齐。SFT 输出的模型路径PPO 节点读取时如果路径写错会直接报文件不存在。我一般会在任务模板里用环境变量来传路径而不是硬编码。比如 SFT 节点输出到$OUTPUT_DIR/sft_modelPPO 节点读$INPUT_DIR/sft_model平台会自动把上游的输出目录挂载到下游的输入目录。另一个原因是资源竞争。多个任务同时提交如果集群资源不够任务会排队。这时候要检查任务的优先级设置重要的任务给高优先级。CubeStudio 支持抢占式调度低优先级任务会被高优先级任务打断适合跑一些不紧急的实验。问题现象可能原因排查方法解决措施SFT loss 不降学习率过大、数据格式错检查 template 和数据字段调小 lr核对数据格式PPO reward 崩溃reward 模型 tokenizer 不一致对比四个模型的 tokenizer统一 tokenizer 配置量化后精度暴跌校准集不匹配检查校准集分布重新分层抽样校准集任务编排失败路径未对齐检查上下游路径变量用环境变量传路径显存 OOMbatch_size 过大逐步调小 batch_size开 gradient_checkpointing6.5 独家避坑经验第一个经验SFT 之前先跑一个小的 sanity check用 100 条数据训 10 步看 loss 能不能降下去。如果能降说明配置没问题再上全量数据。这样能避免跑了 20 小时才发现配置错了。第二个经验PPO 的 reward 模型最好用和 actor 同源的基座不要用不同家族的模型。比如 actor 是 LLaMA-3reward 也用 LLaMA-3不要用 Qwen 做 reward。同源模型的表征空间一致reward 信号更可靠。第三个经验量化之前先做一轮评估记录 FP16 的基线指标。量化后再评估一次对比掉点情况。如果掉点超过 5%就得调整量化配置或者换量化方法。不要量化完直接上线出了问题再回滚成本很高。第四个经验CubeStudio 的任务模板要版本化。每次改配置新建一个版本不要直接改旧的。这样出问题可以快速回滚到上一个可用版本。我一般用日期加序号来命名版本比如sft-v20240115-01。7. 我个人在实际操作中的体会这套流程跑下来最大的感受是平台化不是为了炫技而是为了减少重复劳动和人为失误。以前每个任务都要手动配环境、手动传路径、手动记参数现在把这些都固化到任务模板里新人来了直接填参数就能跑不用再问“那个脚本在哪”“这个参数填多少”。CubeStudio 的任务编排能力让 SFT、PPO、量化这些环节真正串成了一条线而不是各自为战。另一个体会是压缩和评估不能省。很多人训完模型就直接上线结果要么显存不够部署不了要么输出有问题被用户投诉。蒸馏、剪枝、量化是让模型能落地的必要步骤安全评估是让模型能放心落地的必要步骤。这两块在 CubeStudio 上做成标准任务模板后执行成本很低没有理由跳过。最后分享一个小技巧把常用的任务模板导出成 JSON存到 Git 仓库里。这样换集群、换环境的时候直接导入就能用不用重新配。模板里的参数用占位符实际运行时再填具体值。这个做法让我在多个集群之间迁移流水线的时间从半天缩短到十分钟。