只训两个 20M 投影头:CLM-8B 业务微调全流程(冻结 Qwen3-8B + 三阶段对比训练)

发布时间:2026/10/11 22:45:59
只训两个 20M 投影头:CLM-8B 业务微调全流程(冻结 Qwen3-8B + 三阶段对比训练)
只训两个 20M 投影头CLM-8B 业务微调全流程冻结 Qwen3-8B 三阶段对比训练【免费下载链接】CLM-v0.1-8B项目地址: https://ai.gitcode.com/hf_mirrors/Contrastive-LM/CLM-v0.1-8B当 Agent 的每一步决策都要靠大模型逐 token 生成一段动作文本时延迟与成本就成了天然的瓶颈。CLM-8BContrastive Language Model给出了一个反直觉的答案把决策从生成改成匹配——冻结一个 8B 编码器只训练两个合计约 2000 万参数的投影头让状态与动作在向量空间里对齐一次前向 一次点积即完成打分。这套范式在零样本场景下与 Jev 持平但延迟低至其 1/9轻量微调后更是在 DeepSWE81.6%与 Terminal-Bench 2.187.6%上刷新 Agentic 验证 SOTA。本文不堆概念基于仓库侧真实的 README.md 与 config.json 中的声明并结合官方训练代码train/finetune.py把三个问题讲透那 20M 参数到底长什么样、三阶段训练数据如何准备、以及你的业务数据如何走完冻结编码器 → 只训投影头 → 收敛判断的完整微调流程。冻结编码器 双投影头20M 参数能干成什么事先看仓库侧 config.json 给出的模型档案一句话就能概括整个参数格局{ model_type: clm, architecture: state/action projection heads (InfoNCE), base_model: Qwen/Qwen3-8B, encoder_pooling: last-token, embedding_dim: 4096, checkpoints: [CLM_v0.1-8B.pt] }编码器是冻结的 Qwen3-8B取last-token pooling得到 4096 维嵌入可训练部分只有两个投影头state head编码当前状态action head编码候选动作。官方训练代码中的头结构train/finetune.py里的make_head是一个标准的 MLP输入hidden4096Qwen3-8B 嵌入宽度inp: Linear(4096, 1536)接 GELU中间 1 层Linear(1536, 1536)接 LayerNorm输出Linear(1536, 512)最后 L2 归一化把嵌入压进 512 维球面空间。按这套默认配置width1536, depth3, proj512核算单个投影头约 940 万参数state/action 两个头合计约 1900–2000 万——这正是两个 20M 投影头说法的由来也是 README.md 中20M-parameter trainable projection head的准确含义。打分机制本身简单到极致。状态嵌入s与候选动作嵌入a各自过投影头后得分就是score(s, a) exp(logit_scale) · cos(state_head(s), action_head(a))logit_scale初始化为log(1/0.07)即 InfoNCE 惯例的 temperature0.07训练中被限制在 100 以内对所有候选做 softmax得到的就是答案概率分布。正因为状态与动作走两条独立通路动作嵌入可以预计算并缓存复用候选集合固定时每次决策只需要编码一次新状态、做 N 次点积。README 给出的数据是约 1000 个候选时CLM 比 Jev 快 13 倍零样本评测中整体快 9 倍。值得注意的另一个细节是 checkpoint 格式。官方头文件CLM_v0.1-8B.pt约 75MB是一个torch.save的 dict包含state_head/action_head两个 state dict、logit_scale与cfg含width、depth、projection_dim、activation、layernorm、residual。这意味着微调产出的新头依然保持同一格式训练脚本、clm-serve推理服务、best-of-N 评估器可以无缝复用——你训练的业务头和官方发布头是同一物种。三阶段训练数据预训练、难负样本、轨迹微调README.md 把 CLM-8B 的训练拆成三个阶段每一阶段都是对状态-动作对齐的一次升级预训练~60M pairsNemotron DQA 问答对问题当状态、答案当动作。目标是学到宽泛的语义表示中训练~30M 难负样本用 Gemini 2.5 Flash-Lite 为 DQA 问题合成语义相似但错误的答案作为硬负样本加入 InfoNCE 损失训练细粒度的判别力后训练~1M 轨迹来自 Agent Data ProtocolADP数据集的智能体轨迹加上 Endless-Terminals 与 LiteCoder-Terminal-SFT 的终端轨迹每个轨迹步构成一个上下文状态 → 当时决策动作的训练对。为什么难负样本要放在第二阶段而不是从头训起官方实验给出了明确数字这是整个数据配方最关键的证据只在约 10 万条 held-out 问题上评估纯预训练从未见过难负样本top-1 准确率 52.1%预训练后接一段短中训练提升到69.2%若从一开始就混入难负样本准确率爬升更快但峰值只有 62.4%随后过拟合。同样的预算下两阶段策略高出约7 个点。结论很清晰难负样本是预训练之上的精修而不是替代品。后训练阶段还有一个反直觉的经验必须回放预训练数据。官方设置中 40% 的混合比例是 Nemotron DQA 回放、60% 是智能体轨迹。实验结果对比鲜明——带 40% 回放时Nemotron 难负样本 top-1 只从 69% 微降到 68.5%而同样的智能体步数、只用纯轨迹训练直接跌到56.2%。这说明 agentic 轨迹分布窄、容易让模型遗忘通用判别力回放是防止灾难性遗忘的廉价手段。训练目标本身是双向 InfoNCE。给定一个 batch 内 B 对匹配的 (状态, 动作)构造 B×B 相似度矩阵正对在两个方向都被拉近、其余被推开。中训练阶段再叠加硬负样本项状态到动作方向的损失变为只惩罚真动作 vs 硬负样本的排序。投影头极小全部模型文件才 75MB所以哪怕全流程跑完训练成本也远低于任何形式的生成模型对齐。业务微调一份可复现的脚本与收敛判断CLM 的微调脚本train/finetune.py支持两种任务正好对应两类业务诉求--task clm轨迹级微调。输入是 (state, action) 步骤对用共享的组掩码 InfoNCE 训练器适合 DeepSWE 这类从候选补丁/方案里挑最优的验证器场景--task choicetyped 决策微调。输入是LocalLLaMA/typed-decisions这类带标注分布的结构化问题训练状态头与动作头对选项打分。以 README 中复现 DeepSWE held-out-3831/38 81.6%的完整流程为例# 1. 克隆官方代码仓库并安装 git clone https://github.com/Contrastive-LM/CLM.git cd CLM pip install -e . # 2. 拉取 held-out 任务清单用于任务级隔离的验证集 hf download Contrastive-LM/deepswe-clm-heads-8k heldout_tasks.json --local-dir heads/deepswe # 3. 以官方发布的 CLM_v0.1-8B.pt 为起点只训投影头 python train/finetune.py --task clm --init-ckpt $(clm-download) --out-dir runs/deepswe \ --holdout-tasks heads/deepswe/heldout_tasks.json --batch 512脚本的数据入口有三条路任选其一互斥--emb-dir指向预处理好的嵌入目录--hf-dataset指向发布在 Hugging Face 上的嵌入数据集--data给原始步骤转移文件.json/.jsonl此时脚本会用 vLLM 离线嵌入、按训练 token 配方从零构建嵌入并缓存。微调的核心是编码器完全冻结——数据以 Qwen3-8B last-token-pooled 的 4096 维嵌入形式进入训练脚本内部只会反传投影头与logit_scale这也是为什么一张 24GB 显存的卡就能跑完整流程。训练配置里藏着不少工程细节值得逐条对照自己的场景学习率规则默认lr 2e-3 · sqrt(1024/width) · sqrt(batch/1024)宽度和 batch 变大时自动降 lr避免大 batch 微调时震荡调度与优化AdamW OneCycleLRpct_start0.1cos 退火每步梯度裁剪clip_grad_norm_(params, 1.0)batch 内组掩码同一 (task, step) 的样本在相似度矩阵中被 mask 掉防止预测自己造成虚假的 top-1 提升这是_clm_loss里same掩码的作用任务级隔离--holdout-tasks指定留出任务或用--folds K --fold-index按候选数与 pass 数分层生成任务不相交的 K 折杜绝数据泄漏验证集构造默认--val-frac 0.1在非 held-out 任务里按种子切分训练任务与验证任务完全不相交。收敛判断是这套流程里最值得借鉴的部分。脚本每 epoch 输出四类指标val_loss、val_top1batch 内检索命中率、within_task_top1任务内检索命中率与within_task_meanrank任务内归一化平均排名。其中within_task_top1更贴近真实业务——候选往往来自同一任务域跨任务的正样本检索会虚高成绩。默认以within_task_top1作为选模型指标也可切回val_loss指标改善超过 1e-4 才覆盖best_head.pt连续--patience 5个 epoch 无改善即早停。训练产物一目了然best_head.pt验证指标最优的头评估与上线用这个final_head.pt最后一个 epoch 的头summary.json/task_split.json完整训练历史与任务划分记录复现实验必备。训练完再做一次独立的 best-of-N 评估来验证业务收益DeepSWE 复现命令是python evaluation/bon_eval.py --hf-dataset Contrastive-LM/deepswe-clm-embeddings-8k \ --checkpoint heads/deepswe/best_head.pt \ --tasks-file heads/deepswe/heldout_tasks.json --n 4 --window 12每个任务采样 4 个候选方案--n 4、窗口 12 步--window 12由微调后的头从候选里挑最优31/38 任务命中即 81.6%。Terminal-Bench 2.1 的 87.6% 走的是同一套生成多个候选 → CLM 验证排序的流程。何时值得为你的业务微调一个头把 README.md 的 Limitations 读一遍就能划清这套范式的适用边界CLM 只会给你提供的候选打分不生成任何内容投影头锁死 Qwen3-8B last-token-pooled 嵌入换编码器等于从头再训而 DeepSWE、Terminal-Bench 的 SOTA 数字全部来自微调后的头而非发布检查点零样本。所以判断标准其实很朴素候选集合稳定、可枚举工具路由、best-of-N 方案筛选、工单分类、GUI 下一步动作排序→ 值得微调一次嵌入缓存换来 4–13 倍延迟收益需要自由文本生成 → 这不是 CLM 的赛道。从 60M 问答对预训练打底、30M 合成难负样本精修判别力、1M 智能体轨迹注入业务分布再到业务侧几千条轨迹只动 20M 参数——CLM 的整套设计把验证/决策从大模型的昂贵生成中剥离出来变成了一次点积。对于任何一个候选集稳定的 Agent 系统这可能是当前成本收益比最极端的微调方案。【免费下载链接】CLM-v0.1-8B项目地址: https://ai.gitcode.com/hf_mirrors/Contrastive-LM/CLM-v0.1-8B创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考