舒菀菀 发表于 2026-3-9 16:15:54

监督微调 SFT 学习笔记

<h2 id="sft-简介">SFT 简介</h2>
<p><strong>(1) 什么是监督微调</strong></p>
<p>监督微调(SFT)通过利用特定于任务的标签数据集将预训练的 LLM 适应特定任务。SFT 的数据集通常组织如下,一条样本包含一个指令和对应的回答:\(D=\{(I_K,A_K)\}_{K=1}^N\)</p>
<p><strong>(2) 监督微调和预训练的区别</strong></p>
<p>在训练方式上没有任何区别,损失函数一样,主要区别在于数据的组成形式上:</p>
<ul>
<li>
<p>预训练的每条数据都是满长度,即达到模型设置的输入长度上限;SFT 的每条数据原本多长就是多长,不需要做 packing,即每条数据不需要拼接起来</p>
</li>
<li>
<p>SFT 会引入预训练阶段从未见过的 special_token,来让它们学习全新的语义,借助 special_token,SFT 会把语料切分成不同的角色,标配的有 system/user/assistant。此外,SFT 会让模型见到最重要的 eos_token,预训练模型因为没有见过该 token 而无法停止生成</p>
</li>
<li>
<p>SFT 的 prompt 部分对应的输出不做 loss,主要原因是 prompt 的同质化比较严重,不做 loss_mask 的话,同一句话就会被翻来覆去的学</p>
</li>
</ul>
<p>此外,它们的训练目的也不一样:预训练是在背书,纯粹的学习知识;SFT 则是在做题,学习的是指令遵循能力。切勿在 SFT 阶段强行给模型做知识注入,所有的知识注入工作应该采用 continue-pretrain 的思路进行,否则都会使得模型的通用能力掉点明显</p>
<h2 id="sft-数据处理">SFT 数据处理</h2>
<p><strong>(1) 业内共识</strong></p>
<ul>
<li>
<p>prompt 的质量和多样性远重要于数据量级,微调一个 30b 量级的 base model 只需要 10w 量级的数据即可</p>
</li>
<li>
<p>合成数据很重要!一般需要通过不同的方式进行多路合成,减少合成数据的 bias</p>
</li>
<li>
<p>可以加点预训练的数据,减轻灾难性遗忘现象</p>
</li>
<li>
<p>一般训练一个 epoch,垂域模型数据少训练 3 epoch 去过拟合</p>
</li>
<li>
<p>可以做全量微调就不要做 PEFT</p>
</li>
<li>
<p>由于在 pretrain 的退火阶段(有的基座会称为 enhance,即知识富集)会加入高质量的 SFT、Math、Code、STEM、Agent 等数据,所以 SFT 阶段不需要做过多的工作</p>
</li>
</ul>
<p><strong>(2) 数据飞轮</strong></p>
<p>最简单的做法,拉取线上近半个月的真实用户 prompt,先用启发式规则进行清洗,然后 GPT-4o 打标,留下可用的数据</p>
<p>为什么要用数据飞轮:prompt 的生产是需要有 seed 种子的,而 seed 的数据量和多样性有限,数据合成的质量不够高;可以利用数据飞轮收集线上真实的日志,基于 bad case(可来源于用户反馈、模型打标)构建高质量 SFT 数据修复 bad case</p>
<p><strong>(3) 数据生产合成</strong></p>
<p>一句话总结:通过不同的数据合成方法确保 prompt 的多样性,满足大模型在各个专项能力的需求</p>
<p><strong>生产合成 prompt:</strong>比较有名的工作 self-instruct,划分技能库,即给每个数据打上 task_type,越细越好,然后每个 task_type 准备一些 seed propmt,然后随机采样 seed,再喂给一个能力很强的模型,让它基于这些 seed 问题再续写出一些问题;或者利用各种启发式规则合成数据造 prompt,然后用强大模型来做改写</p>
<p><strong>生产合成 answer:</strong>GPT4 is all your need,用一个效果好的模型来生产 answer;也可以利用 GPT4 生产 1000 条 answer 然后去训小模型</p>
<p><strong>工业界做法:拒绝采样,</strong>通过 Bon 或者其他 Won 等方式对同一个 prompt 采样多个推理路径,通过人工或者 verifiers 挑选出最佳路径为 response,或者构造 chosen 和 rejected 偏好数据。最后基于这些数据进行 SFT 或者 DPO 训练</p>
<h2 id="数据质量过滤">数据质量过滤</h2>
<p><strong>(1) IFD 过滤</strong></p>
<p>在应用 IFD 过滤前,需要用<strong>精心选择的指令数据</strong>对模型进行初步训练,使模型具备基本的指令跟随能力。这样,模型才能有效地判断不同指令的难度。</p>
<p>核心点:根据指令跟踪难度筛选 SFT 数据</p>
<p><strong>总体流程:</strong></p>
<ul>
<li>
<p>第一步从简单经验中学习:从目标数据集中抽取一个多样性较高的子集,对<strong>指令嵌入</strong>使用 K-Means 聚类,建立基本的指令跟随能力</p>
</li>
<li>
<p>第二步评估指令执行难度:用第一步微调后的模型计算两个得分,带指令损失(衡量模型在给定指令 \(Q\) 的情况下,模型生成正确答案 \(A\) 的难度)和直接答案得分(衡量模型在没有指令的情况下,单独生成正确答案的难度)</p>
</li>
</ul>
<p>最终指令跟踪难度(IFD)定义为:\(r_\theta(Q,A)=\frac{s_\theta(A)}{s_\theta(A|Q)}\)。该比值越高,说明指令对生成答案的帮助越大,代表指令执行根据挑战性和价值</p>
<p><strong>(2) MoDS 过滤</strong></p>
<p>主要通过质量过滤、多样性筛选、必要性筛选三个方面来进行数据的筛选</p>
<p><strong>(3) 数据多样性探索</strong></p>
<p>数据多样性主要包含三个维度:数据用途、数据形式和数据语义</p>
<ul>
<li>
<p>数据用途(也叫 task_type):在实际工作中,双层 task_type 都很常见,例如 "逻辑推理—常识推理"、"逻辑推理—COT 多步骤推理"。一般难 task_type 数据多点,简单 task_type 数据少点</p>
</li>
<li>
<p>数据形式:数据形式不能让模型找到规律,关键信息在 prompt 中的位置分布要足够随机。目的是避免模型在训练时退化,只聚焦于某些位置的 token</p>
</li>
<li>
<p>数据语义:嵌入在空间中的分布多样性变化,向量平均距离等等</p>
</li>
</ul>
<h2 id="sft-训练">SFT 训练</h2>
<p><strong>(1) 训练框架</strong></p>
<p>建议使用 OpenRLHF 框架(https://github.com/OpenRLHF/OpenRLHF),简单易用,核心是 Ray+DeepSpeed</p>
<p>一般而言我们很少在 SFT 的部分魔改损失函数和训练策略,一般就改改 <code>checkpoint_path, model_path, data_path, dp, pp, lr</code> 这些参数</p>
<p><strong>(2) 参数设置</strong></p>
<p>不管使用哪个框架,有几个参数是着重需要注意的</p>
epoch: "一般就 1 epoch,如果微调垂域模型且数据量较少,可以 3 epoch"
gradient_accumulation_steps: "表示在更新模型参数之前,梯度会在多少个小批次上累积"
global_batch_size: "训练过程中所有设备上的总批量大小"
learning_rate: "SFT 阶段的 lr 一般是 Pretrain 阶段的 10 倍左右"
lr_scheduler_type: "学习率调度器的类型,主要分为 constant/linear/cosine/exponential,一般用 cosine 比较多"
dropout: "一般不用,主要因为没啥用,并且还会拖累训练效率"

max_seq_len: "模型可以处理的输入序列的最大长度,一般设置 4K 就行"
offload: "用于将部分计算或数据从 GPU 专业到 CPU 中,一般不设置"
gradient_checkpointing: "通过在前向传播中节省部分中间计算结果的存储,降低内存使用量"
seq_parallel_size: "序列并行的分块大小,用于分布式训练时将输入序列分成更小的块以实现并行化"

per_device_train_batch_size: "每个 GPU 上的训练批量大小,一般就设置为 1"
weight_decay: "权重衰弱参数,默认设置为 0.01"
num_warmup_steps: "通常设置为总训练部步数的 5%-10%"
<p><strong>(3) 训练技巧</strong></p>
<p>不建议在 SFT 阶段使用 packing,不少实验表明 SFT packing 后削弱了模型对难的短 query 和短答案的拟合</p>
<p><strong>(4) 训练策略</strong></p>
<ul>
<li>
<p><strong>多任务学习:</strong>直接混合不同的 SFT 数据源并引用 SFT,如果将每个数据源视为不同的任务,这就可以视为多任务学习</p>
</li>
<li>
<p><strong>顺序训练:</strong>在每个数据集上依次应用 SFT</p>
</li>
<li>
<p><strong>混合序列训练:</strong>先在专业数据集(代码、数学)上应用多任务学习,然后在通用能力数据集上应用 SFT</p>
</li>
<li>
<p><strong>双阶段混合微调(DMT):</strong>首先在专业数据集上应用 SFT,在第二阶段使用混合数据源应用 SFT</p>
</li>
</ul>
<p><strong>(5) 多轮对话专项提升</strong></p>
<p>主题没有变化的真多轮数据直接加入训练数据,主图发生变化的伪多轮数据选取一小部分加入到训练数据中;可以用一些单轮对话合成多轮对话数据;多轮计算 loss</p>
<h2 id="sft-评估">SFT 评估</h2>
<p>不同于 Pretrain 只需要看知识能力,SFT 的评估需要看经典的 3H 原则:<strong>Helpfulness、Honesty、Harmlessness</strong>,或者按需求制定指标</p>
<p>评估的时候每个唯独有一个单独的得分,根据相应的加权公式来确定这条回复的可用性</p>
<p>目前的评估方式主要是机评和人评</p><br>来源:程序园用户自行投稿发布,如果侵权,请联系站长删除<br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

柴古香 发表于 2026-3-12 04:12:55

感谢,下载保存了

孟茹云 发表于 2026-3-12 04:31:08

分享、互助 让互联网精神温暖你我
页: [1]
查看完整版本: 监督微调 SFT 学习笔记