基于千问的白盒蒸馏 SOP

理论笔记: 蒸馏原理与公式详见 /root/autodl-tmp/Distillation.md,本 SOP 聚焦第六节「四步实战」的工程落地。

手把手教学: 逐步操作与脚本说明见 <TUTORIAL.md>

互补项目: /root/autodl-tmp/Distill/ 已实现黑盒蒸馏 (API 生成数据 → SFT);本目录 Distill2 实现白盒蒸馏(Logits 对齐)。


一、理论背景与白盒蒸馏原理

1. 核心目标

知识蒸馏(Knowledge Distillation)通过迁移大模型(教师 Teacher )的知识,训练出推理更快、资源占用更小的模型(学生 Student)。

白盒蒸馏的前提:教师模型结构开源可见,可获取 forward 过程中的 Logits 或中间层特征,作为比硬标签更丰富的监督信号。

2. 白盒蒸馏的三类方法

类型 核心 本 SOP 是否采用
响应式 (Response-Based) 匹配最终输出 Logits 分布 是(本 SOP 采用)
特征式 (Feature-Based) 对齐中间层特征图(FitNet 等)
关系式 (Relation-Based) 对齐样本间/层间关系矩阵(RKD 等)

3. 响应式蒸馏的损失函数

经典 Hinton 蒸馏损失:

Total Loss = α ⋅ L distill + ( 1 − α ) ⋅ L student \text{Total Loss} = \alpha \cdot L_{\text{distill}} + (1-\alpha) \cdot L_{\text{student}} Total Loss=α⋅Ldistill+(1−α)⋅Lstudent

  • L distill L_{\text{distill}} Ldistill :对教师/学生 Logits 施加温度 T T T 软化后,计算 KL 散度
    • p ( z i , T ) = exp ⁡ ( z i / T ) ∑ j exp ⁡ ( z j / T ) p(z_i, T) = \dfrac{\exp(z_i/T)}{\sum_j \exp(z_j/T)} p(zi,T)=∑jexp(zj/T)exp(zi/T)
    • T T T 越大,分布越平滑,学生能学到更多类间关系
  • L student L_{\text{student}} Lstudent :学生预测与数据集硬标签的 交叉熵 (CE)
  • α \alpha α:蒸馏项权重,通常 0.1--0.5

KL 散度(离散):

D K L ( P ∥ Q ) = ∑ x P ( x ) log ⁡ P ( x ) Q ( x ) D_{KL}(P \| Q) = \sum_x P(x) \log \frac{P(x)}{Q(x)} DKL(P∥Q)=x∑P(x)logQ(x)P(x)

4. 与黑盒蒸馏(Distill/)的对比

#mermaid-svg-7eiNmDIuFgzpaKzH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7eiNmDIuFgzpaKzH .error-icon{fill:#552222;}#mermaid-svg-7eiNmDIuFgzpaKzH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7eiNmDIuFgzpaKzH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7eiNmDIuFgzpaKzH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7eiNmDIuFgzpaKzH .marker.cross{stroke:#333333;}#mermaid-svg-7eiNmDIuFgzpaKzH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7eiNmDIuFgzpaKzH p{margin:0;}#mermaid-svg-7eiNmDIuFgzpaKzH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH .cluster-label text{fill:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH .cluster-label span{color:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH .cluster-label span p{background-color:transparent;}#mermaid-svg-7eiNmDIuFgzpaKzH .label text,#mermaid-svg-7eiNmDIuFgzpaKzH span{fill:#333;color:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH .node rect,#mermaid-svg-7eiNmDIuFgzpaKzH .node circle,#mermaid-svg-7eiNmDIuFgzpaKzH .node ellipse,#mermaid-svg-7eiNmDIuFgzpaKzH .node polygon,#mermaid-svg-7eiNmDIuFgzpaKzH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7eiNmDIuFgzpaKzH .rough-node .label text,#mermaid-svg-7eiNmDIuFgzpaKzH .node .label text,#mermaid-svg-7eiNmDIuFgzpaKzH .image-shape .label,#mermaid-svg-7eiNmDIuFgzpaKzH .icon-shape .label{text-anchor:middle;}#mermaid-svg-7eiNmDIuFgzpaKzH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7eiNmDIuFgzpaKzH .rough-node .label,#mermaid-svg-7eiNmDIuFgzpaKzH .node .label,#mermaid-svg-7eiNmDIuFgzpaKzH .image-shape .label,#mermaid-svg-7eiNmDIuFgzpaKzH .icon-shape .label{text-align:center;}#mermaid-svg-7eiNmDIuFgzpaKzH .node.clickable{cursor:pointer;}#mermaid-svg-7eiNmDIuFgzpaKzH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7eiNmDIuFgzpaKzH .arrowheadPath{fill:#333333;}#mermaid-svg-7eiNmDIuFgzpaKzH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7eiNmDIuFgzpaKzH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7eiNmDIuFgzpaKzH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7eiNmDIuFgzpaKzH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7eiNmDIuFgzpaKzH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7eiNmDIuFgzpaKzH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7eiNmDIuFgzpaKzH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7eiNmDIuFgzpaKzH .cluster text{fill:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH .cluster span{color:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7eiNmDIuFgzpaKzH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7eiNmDIuFgzpaKzH rect.text{fill:none;stroke-width:0;}#mermaid-svg-7eiNmDIuFgzpaKzH .icon-shape,#mermaid-svg-7eiNmDIuFgzpaKzH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7eiNmDIuFgzpaKzH .icon-shape p,#mermaid-svg-7eiNmDIuFgzpaKzH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7eiNmDIuFgzpaKzH .icon-shape .label rect,#mermaid-svg-7eiNmDIuFgzpaKzH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7eiNmDIuFgzpaKzH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7eiNmDIuFgzpaKzH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7eiNmDIuFgzpaKzH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Distill2 白盒
教师 LoRA SFT

alpaca_gpt4_zh
合并教师权重
学生 LoRA + Logits 对齐

ref_model=教师
合并学生权重
Distill 黑盒
DeepSeek-R1 API

文本输出
学生 Full SFT

维度 Distill/ 黑盒 Distill2/ 白盒
教师来源 闭源 API(DeepSeek-R1) 本地开源模型(Qwen3-4B)
监督信号 教师生成的文本(软标签文本) 教师 forward 的 Logits 概率分布
是否需要先训教师 否(API 直接调用) (教师须先 SFT 再蒸馏)
训练框架 LLaMA-Factory Full SFT LLaMA-Factory LoRA + ASFT
技术门槛 较低(本质是 SFT) 较高(需加载双模型、配置 ref_model)

核心逻辑(来自笔记第六节): 「教师模型先基于业务数据进行 SFT 微调,再拿着这个懂业务的教师去教小模型。」若直接用未微调的基础模型当教师,特定业务场景下蒸馏效果会大打折扣。


二、任务配置总览

本节参数直接对应 Distillation.md 第六节

配置项
蒸馏方法 白盒 - 响应式(Logits 对齐)
教师模型 Qwen/Qwen3-4B-Instruct-2507
学生模型 Qwen/Qwen3-1.7B(LLaMA-Factory 内置别名 Qwen3-1.7B-Thinking
数据集 alpaca_gpt4_zh(公开中文指令集,Alpaca 格式)
训练方式 LoRA 微调
训练轮数 30 Epoch(教师、学生各 30)
工程框架 LLaMA-Factory(独立 clone 至 Distill2/LLaMA-Factory

与笔记的差异说明: Distillation.md 第六节 示例使用定制 identity_modify.json;本 SOP 选用 LLaMA-Factory 已内置注册的公开数据集 alpaca_gpt4_zh,避免手写样本,同时完整走通「下载 → 校验 → 训练 → 蒸馏」链路。若你的业务有私有语料,可替换为同格式的自建 JSON,四步流程不变。

规模建议:

阶段 max_samples num_train_epochs 目的
冒烟 50 1 验证数据链路与四步流程
正式 不设置(全量 ~4.8 万条) 30 对齐笔记第六节参数

三、环境准备

1. 工作目录与网络加速

工作目录: /root/autodl-tmp/Distill2

AutoDL 网络加速(访问 GitHub / Hugging Face / ModelScope 前执行):

bash 复制代码
source /etc/network_turbo

开启后 pip 源等非 GitHub/HF 资源可能变慢,建议仅在 clone / 下载模型时使用。

2. 克隆并安装 LLaMA-Factory

bash 复制代码
mkdir -p /root/autodl-tmp/Distill2
cd /root/autodl-tmp/Distill2

source /etc/network_turbo
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git

cd LLaMA-Factory
pip install -e ".[torch,metrics]"
llamafactory-cli version   # 验证安装

实测问题与解决:

问题 现象 解决方案
torchaudio 版本冲突 OSError: libcudart.so.13: cannot open shared object file pip install "torchaudio==2.8.0" --index-url https://download.pytorch.org/whl/cu128
OMP 警告 libgomp: Invalid value for environment variable OMP_NUM_THREADS 可忽略;或 export OMP_NUM_THREADS=1

3. 下载教师与学生模型

在 ModelScope 搜索并确认 Model ID 后,执行:

python 复制代码
# 可在 python 交互环境或临时脚本中运行
from modelscope import snapshot_download

TEACHER_ID = "Qwen/Qwen3-4B-Instruct-2507"
STUDENT_ID = "Qwen/Qwen3-1.7B"
LOCAL_DIR = "/root/autodl-tmp/Distill2/models"

teacher_path = snapshot_download(TEACHER_ID, cache_dir=LOCAL_DIR)
student_path = snapshot_download(STUDENT_ID, cache_dir=LOCAL_DIR)
print("Teacher:", teacher_path)
print("Student:", student_path)

ModelScope 典型缓存路径(配置 YAML 时使用完整绝对路径):

复制代码
/root/autodl-tmp/Distill2/models/models/Qwen--Qwen3-4B-Instruct-2507/snapshots/master
/root/autodl-tmp/Distill2/models/models/Qwen--Qwen3-1.7B/snapshots/master

下文 YAML 中以 <TEACHER_PATH><STUDENT_PATH> 代指上述实际路径。

4. 准备训练数据集(公开集 alpaca_gpt4_zh

选用 Alpaca-GPT4-Data-ZH 的中文子集,经 LLaMA-Factory 维护为 Hub 数据集,适合 Qwen3 中文 Instruct 模型的 SFT 与白盒蒸馏。

属性
LLaMA-Factory 注册名 alpaca_gpt4_zh
HuggingFace llamafactory/alpaca_gpt4_zh
ModelScope llamafactory/alpaca_gpt4_zh
格式 Alpaca(instruction / input / output
规模 约 4.8 万条

#mermaid-svg-qbcj77y8PsTmOVfV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qbcj77y8PsTmOVfV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qbcj77y8PsTmOVfV .error-icon{fill:#552222;}#mermaid-svg-qbcj77y8PsTmOVfV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qbcj77y8PsTmOVfV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qbcj77y8PsTmOVfV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qbcj77y8PsTmOVfV .marker.cross{stroke:#333333;}#mermaid-svg-qbcj77y8PsTmOVfV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qbcj77y8PsTmOVfV p{margin:0;}#mermaid-svg-qbcj77y8PsTmOVfV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qbcj77y8PsTmOVfV .cluster-label text{fill:#333;}#mermaid-svg-qbcj77y8PsTmOVfV .cluster-label span{color:#333;}#mermaid-svg-qbcj77y8PsTmOVfV .cluster-label span p{background-color:transparent;}#mermaid-svg-qbcj77y8PsTmOVfV .label text,#mermaid-svg-qbcj77y8PsTmOVfV span{fill:#333;color:#333;}#mermaid-svg-qbcj77y8PsTmOVfV .node rect,#mermaid-svg-qbcj77y8PsTmOVfV .node circle,#mermaid-svg-qbcj77y8PsTmOVfV .node ellipse,#mermaid-svg-qbcj77y8PsTmOVfV .node polygon,#mermaid-svg-qbcj77y8PsTmOVfV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qbcj77y8PsTmOVfV .rough-node .label text,#mermaid-svg-qbcj77y8PsTmOVfV .node .label text,#mermaid-svg-qbcj77y8PsTmOVfV .image-shape .label,#mermaid-svg-qbcj77y8PsTmOVfV .icon-shape .label{text-anchor:middle;}#mermaid-svg-qbcj77y8PsTmOVfV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qbcj77y8PsTmOVfV .rough-node .label,#mermaid-svg-qbcj77y8PsTmOVfV .node .label,#mermaid-svg-qbcj77y8PsTmOVfV .image-shape .label,#mermaid-svg-qbcj77y8PsTmOVfV .icon-shape .label{text-align:center;}#mermaid-svg-qbcj77y8PsTmOVfV .node.clickable{cursor:pointer;}#mermaid-svg-qbcj77y8PsTmOVfV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qbcj77y8PsTmOVfV .arrowheadPath{fill:#333333;}#mermaid-svg-qbcj77y8PsTmOVfV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qbcj77y8PsTmOVfV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qbcj77y8PsTmOVfV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qbcj77y8PsTmOVfV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qbcj77y8PsTmOVfV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qbcj77y8PsTmOVfV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qbcj77y8PsTmOVfV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qbcj77y8PsTmOVfV .cluster text{fill:#333;}#mermaid-svg-qbcj77y8PsTmOVfV .cluster span{color:#333;}#mermaid-svg-qbcj77y8PsTmOVfV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qbcj77y8PsTmOVfV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qbcj77y8PsTmOVfV rect.text{fill:none;stroke-width:0;}#mermaid-svg-qbcj77y8PsTmOVfV .icon-shape,#mermaid-svg-qbcj77y8PsTmOVfV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qbcj77y8PsTmOVfV .icon-shape p,#mermaid-svg-qbcj77y8PsTmOVfV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qbcj77y8PsTmOVfV .icon-shape .label rect,#mermaid-svg-qbcj77y8PsTmOVfV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qbcj77y8PsTmOVfV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qbcj77y8PsTmOVfV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qbcj77y8PsTmOVfV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Hub 公开数据集

alpaca_gpt4_zh
确认 dataset_info.json

内置注册
预下载到本地缓存
抽样预览与字段校验
LLaMA-Factory

max_steps=1 加载冒烟
Step1~4 训练/蒸馏

以下子步骤均需执行 (冒烟时可限制 max_samples,但不可跳过下载与校验)。

4.1 确认数据集已在 LLaMA-Factory 中注册

clone 完成后检查 data/dataset_info.json 是否含以下条目(官方仓库默认已有,无需手写注册):

bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
python3 -c "
import json
info = json.load(open('data/dataset_info.json'))
assert 'alpaca_gpt4_zh' in info, '缺少 alpaca_gpt4_zh 注册项'
print(json.dumps(info['alpaca_gpt4_zh'], indent=2, ensure_ascii=False))
"

预期输出含 hf_hub_urlms_hub_url

json 复制代码
{
  "hf_hub_url": "llamafactory/alpaca_gpt4_zh",
  "ms_hub_url": "llamafactory/alpaca_gpt4_zh"
}
4.2 预下载数据集到本地缓存

AutoDL 环境优先走 ModelScope;若 MS 不可用再回退 HuggingFace。

bash 复制代码
source /etc/network_turbo
cd /root/autodl-tmp/Distill2/LLaMA-Factory

方式 A(推荐,ModelScope):

python 复制代码
from modelscope.msdatasets import MsDataset

ds = MsDataset.load("llamafactory/alpaca_gpt4_zh", split="train")
print("下载完成,样本数:", len(ds))

方式 B(回退,HuggingFace Datasets):

python 复制代码
from datasets import load_dataset

ds = load_dataset("llamafactory/alpaca_gpt4_zh", split="train")
print("下载完成,样本数:", len(ds))

首次下载耗时数分钟,缓存默认位于 ~/.cache/modelscope~/.cache/huggingface/datasets。后续训练会直接命中缓存。

4.3 抽样预览与字段校验

确认字段完整、无大量空 output,并保存一条验证 prompt 供 Step 4 推理对比(从真实数据中读取,非手写):

python 复制代码
# 接续 4.2,变量 ds 已加载
required = {"instruction", "output"}
for i in range(3):
    row = ds[i]
    assert required.issubset(row.keys()), f"样本 {i} 缺少必要字段"
    print(f"--- sample {i} ---")
    print("instruction:", row["instruction"][:120])
    print("input:", (row.get("input") or "")[:80])
    print("output:", row["output"][:120])

# 写入验证 prompt,供第四节推理使用
val = ds[0]
prompt = val["instruction"]
if val.get("input"):
    prompt = prompt + "\n" + val["input"]
with open("/root/autodl-tmp/Distill2/validation_prompt.txt", "w", encoding="utf-8") as f:
    f.write(prompt)
print("验证 prompt 已写入 Distill2/validation_prompt.txt")
print("全量样本数:", len(ds))

检查点: 终端无报错;validation_prompt.txt 已生成。

4.4 LLaMA-Factory 数据加载冒烟(max_steps: 1)

在正式四步训练前,用极小训练步数 验证框架能正确读取 Hub 数据集并完成 tokenize → dataloader → forward。创建临时配置 examples/train_lora/smoke_data_load.yaml

yaml 复制代码
### model
model_name_or_path: <STUDENT_PATH>
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset
dataset: alpaca_gpt4_zh_local
template: qwen3_nothink
cutoff_len: 2048
max_samples: 5
overwrite_cache: true

### output
output_dir: saves/smoke/data-load
overwrite_output_dir: true
report_to: none

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 1
learning_rate: 1.0e-4
max_steps: 1
bf16: true
bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
llamafactory-cli train examples/train_lora/smoke_data_load.yaml

检查点: 日志出现 Running training 且 1 step 正常结束;无 Dataset ... not found 或字段映射错误。

4.5 可选:导出本地 JSON 副本(离线复现)

若需在无网环境复现,可将 Hub 数据原样导出为本地文件(内容来自下载结果,非手写):

python 复制代码
ds.select(range(min(50, len(ds)))).to_json(
    "data/alpaca_gpt4_zh_smoke.json",
    force_ascii=False,
)
print("已导出冒烟子集 -> data/alpaca_gpt4_zh_smoke.json")

若使用本地副本,在 dataset_info.json 增加:

json 复制代码
  "alpaca_gpt4_zh_smoke": {
    "file_name": "alpaca_gpt4_zh_smoke.json"
  }

训练时将 YAML 中 dataset 改为 alpaca_gpt4_zh_smoke 即可。实测主流程使用 alpaca_gpt4_zh_local(见 4.6)。

4.6 实测推荐:导出本地副本(AutoDL 环境强烈建议)

2026-07-08 冒烟实测: 在未开启 source /etc/network_turbo 时,LLaMA-Factory 加载 Hub 数据集默认走 HuggingFace,报错 [Errno 101] Network is unreachable即使 ModelScope 已缓存,训练阶段仍可能触发 HF 请求。

推荐做法(与实测一致): 预下载后导出本地 JSON,并注册为 alpaca_gpt4_zh_local

python 复制代码
# 4.2 下载完成后执行(需 pip install addict)
import json
from modelscope.msdatasets import MsDataset

ds = MsDataset.load("llamafactory/alpaca_gpt4_zh", split="train")
records = [dict(ds[i]) for i in range(len(ds))]
with open("/root/autodl-tmp/Distill2/LLaMA-Factory/data/alpaca_gpt4_zh.json", "w", encoding="utf-8") as f:
    json.dump(records, f, ensure_ascii=False)
print(len(records), "records exported")

data/dataset_info.json 添加:

json 复制代码
  "alpaca_gpt4_zh_local": {
    "file_name": "alpaca_gpt4_zh.json"
  }

所有训练 YAML 的 dataset 字段改用 alpaca_gpt4_zh_local 备选方案:训练前 export USE_MODELSCOPE_HUB=1(仍建议本地副本,离线更稳)。

实测样本规模: 全量 42,677 条(非文档估计的 4.8 万,属正常偏差)。


四、四步实战操作

整体流程:
#mermaid-svg-PDRQGN0ryrH0q0uO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PDRQGN0ryrH0q0uO .error-icon{fill:#552222;}#mermaid-svg-PDRQGN0ryrH0q0uO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PDRQGN0ryrH0q0uO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PDRQGN0ryrH0q0uO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PDRQGN0ryrH0q0uO .marker.cross{stroke:#333333;}#mermaid-svg-PDRQGN0ryrH0q0uO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PDRQGN0ryrH0q0uO p{margin:0;}#mermaid-svg-PDRQGN0ryrH0q0uO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO .cluster-label text{fill:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO .cluster-label span{color:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO .cluster-label span p{background-color:transparent;}#mermaid-svg-PDRQGN0ryrH0q0uO .label text,#mermaid-svg-PDRQGN0ryrH0q0uO span{fill:#333;color:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO .node rect,#mermaid-svg-PDRQGN0ryrH0q0uO .node circle,#mermaid-svg-PDRQGN0ryrH0q0uO .node ellipse,#mermaid-svg-PDRQGN0ryrH0q0uO .node polygon,#mermaid-svg-PDRQGN0ryrH0q0uO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PDRQGN0ryrH0q0uO .rough-node .label text,#mermaid-svg-PDRQGN0ryrH0q0uO .node .label text,#mermaid-svg-PDRQGN0ryrH0q0uO .image-shape .label,#mermaid-svg-PDRQGN0ryrH0q0uO .icon-shape .label{text-anchor:middle;}#mermaid-svg-PDRQGN0ryrH0q0uO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PDRQGN0ryrH0q0uO .rough-node .label,#mermaid-svg-PDRQGN0ryrH0q0uO .node .label,#mermaid-svg-PDRQGN0ryrH0q0uO .image-shape .label,#mermaid-svg-PDRQGN0ryrH0q0uO .icon-shape .label{text-align:center;}#mermaid-svg-PDRQGN0ryrH0q0uO .node.clickable{cursor:pointer;}#mermaid-svg-PDRQGN0ryrH0q0uO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PDRQGN0ryrH0q0uO .arrowheadPath{fill:#333333;}#mermaid-svg-PDRQGN0ryrH0q0uO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PDRQGN0ryrH0q0uO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PDRQGN0ryrH0q0uO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PDRQGN0ryrH0q0uO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PDRQGN0ryrH0q0uO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PDRQGN0ryrH0q0uO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PDRQGN0ryrH0q0uO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PDRQGN0ryrH0q0uO .cluster text{fill:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO .cluster span{color:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PDRQGN0ryrH0q0uO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PDRQGN0ryrH0q0uO rect.text{fill:none;stroke-width:0;}#mermaid-svg-PDRQGN0ryrH0q0uO .icon-shape,#mermaid-svg-PDRQGN0ryrH0q0uO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PDRQGN0ryrH0q0uO .icon-shape p,#mermaid-svg-PDRQGN0ryrH0q0uO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PDRQGN0ryrH0q0uO .icon-shape .label rect,#mermaid-svg-PDRQGN0ryrH0q0uO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PDRQGN0ryrH0q0uO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PDRQGN0ryrH0q0uO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PDRQGN0ryrH0q0uO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Step1

教师 LoRA SFT

30 Epoch
Step2

合并教师权重
Step3

学生 LoRA 蒸馏

30 Epoch
Step4

合并学生 + 验证


第一步:训练教师模型(LoRA SFT)

目标:alpaca_gpt4_zh 上微调 Qwen3-4B-Instruct-2507,得到 4B LoRA 适配器

创建配置文件 LLaMA-Factory/examples/train_lora/qwen3_4b_teacher_lora.yaml

yaml 复制代码
### model
model_name_or_path: <TEACHER_PATH>
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset
dataset: alpaca_gpt4_zh_local
template: qwen3_nothink
cutoff_len: 2048
max_samples: 50          # 冒烟;正式训练删除此行
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output
output_dir: saves/qwen3-4b/lora/teacher-sft
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 1.0      # 冒烟;正式改为 30.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000

冒烟时 YAML 已含 max_samples: 50num_train_epochs: 1.0正式训练 删除 max_samples 行,并将 num_train_epochs 改为 30.0

执行训练:

bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
llamafactory-cli train examples/train_lora/qwen3_4b_teacher_lora.yaml

产出: saves/qwen3-4b/lora/teacher-sft/(含 LoRA adapter 与 checkpoint)


第二步:合并教师 LoRA 权重

目标: 将 LoRA 适配器与基座合并,得到全参数教师模型 ,供第三步作为 ref_model 提供准确软标签。

创建配置文件 LLaMA-Factory/examples/merge_lora/qwen3_4b_teacher_merge.yaml

yaml 复制代码
### Note: DO NOT use quantized model or quantization_bit when merging lora adapters

### model
model_name_or_path: <TEACHER_PATH>
adapter_name_or_path: saves/qwen3-4b/lora/teacher-sft
template: qwen3_nothink
trust_remote_code: true

### export
export_dir: saves/qwen3-4b/merged-teacher
export_size: 5
export_device: cpu
export_legacy_format: false

执行合并:

bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
llamafactory-cli export examples/merge_lora/qwen3_4b_teacher_merge.yaml

产出: saves/qwen3-4b/merged-teacher/(可直接加载的全参数 safetensors 模型)

为何必须合并? 第三步蒸馏需加载冻结的教师模型做 forward 取 Logits;合并后的全参数模型路径可直接作为 ref_model,软标签与业务 SFT 后的教师行为一致。


第三步:执行白盒知识蒸馏(学生 LoRA + Logits 对齐)

目标: 用合并后的教师,在 alpaca_gpt4_zh 上对 Qwen3-1.7B 做 LoRA 蒸馏,得到 1.7B LoRA 适配器

工程实现说明

LLaMA-Factory 通过 use_asft_loss: true + ref_model 实现 Logits 级对齐:

  • 训练时教师模型 eval() 冻结,对学生每个 token 位置输出 ref_logits
  • 损失 = CE(硬标签)+ asft_alpha × KL(学生 Logits vs 教师 Logits)
  • 源码:src/llamafactory/train/sft/trainer.pycompute_loss 中调用 asft_loss_func

⚠️ LoRA 蒸馏必须显式配置 ref_modelfinetuning_type: lora 且未指定 ref_model 时,框架会将 ref_model 设为 None,蒸馏不生效(见 trainer_utils.pycreate_ref_model)。

理论 vs 实现的差异
经典 KD(笔记公式) LLaMA-Factory ASFT
显式温度 T T T 软化 Logits 当前实现无独立 T T T 参数
α ⋅ L distill + ( 1 − α ) ⋅ L student \alpha \cdot L_{\text{distill}} + (1-\alpha) \cdot L_{\text{student}} α⋅Ldistill+(1−α)⋅Lstudent CE + asft_alpha × KL(ref_logits)
--- asft_alpha 建议范围 0.05--0.3,默认 0.1

创建配置文件 LLaMA-Factory/examples/train_lora/qwen3_1.7b_distill_lora.yaml

yaml 复制代码
### model
model_name_or_path: <STUDENT_PATH>
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all
use_asft_loss: true
asft_alpha: 0.1
ref_model: saves/qwen3-4b/merged-teacher

### dataset
dataset: alpaca_gpt4_zh_local
template: qwen3_nothink
cutoff_len: 2048
max_samples: 50          # 冒烟;正式训练删除此行
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output
output_dir: saves/qwen3-1.7b/lora/distill
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 1.0      # 冒烟;正式改为 30.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000

显存不足时可尝试:

  • 减小 per_device_train_batch_size 为 1(已是最小)
  • 增大 gradient_accumulation_steps
  • 在 method 段添加 DeepSpeed:deepspeed: examples/deepspeed/ds_z3_offload_config.json

执行蒸馏训练:

bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
llamafactory-cli train examples/train_lora/qwen3_1.7b_distill_lora.yaml

产出: saves/qwen3-1.7b/lora/distill/(1.7B LoRA 适配器)


第四步:合并学生模型与效果验证

4.1 合并学生 LoRA 权重

创建配置文件 LLaMA-Factory/examples/merge_lora/qwen3_1.7b_student_merge.yaml

yaml 复制代码
### Note: DO NOT use quantized model or quantization_bit when merging lora adapters

### model
model_name_or_path: <STUDENT_PATH>
adapter_name_or_path: saves/qwen3-1.7b/lora/distill
template: qwen3_nothink
trust_remote_code: true

### export
export_dir: saves/qwen3-1.7b/merged-student
export_size: 2
export_device: cpu
export_legacy_format: false
bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
llamafactory-cli export examples/merge_lora/qwen3_1.7b_student_merge.yaml

产出: saves/qwen3-1.7b/merged-student/(约 1.7B 全参数模型,可直接部署为 safetensors / 转 gguf)

4.2 推理验证

方式 A:LLaMA-Factory 交互对话

bash 复制代码
cd /root/autodl-tmp/Distill2/LLaMA-Factory
llamafactory-cli chat examples/inference/qwen3_lora_sft.yaml

将 chat 配置中的 model_name_or_path 改为 saves/qwen3-1.7b/merged-studenttemplate 保持 qwen3_nothink

方式 B:Transformers 脚本(使用 4.3 节保存的验证 prompt)

python 复制代码
from transformers import AutoModelForCausalLM, AutoTokenizer

MODEL_PATH = "/root/autodl-tmp/Distill2/LLaMA-Factory/saves/qwen3-1.7b/merged-student"
PROMPT_FILE = "/root/autodl-tmp/Distill2/validation_prompt.txt"

model = AutoModelForCausalLM.from_pretrained(
    MODEL_PATH, torch_dtype="auto", device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)

with open(PROMPT_FILE, encoding="utf-8") as f:
    user_content = f.read().strip()

messages = [{"role": "user", "content": user_content}]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer([text], return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=256)
print(tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))

验收要点:

  • 使用同一条 来自 alpaca_gpt4_zh 的验证 prompt,分别对 基座 1.7B合并教师蒸馏学生 推理,对比回答质量
  • 蒸馏学生在指令遵循、回答完整度上应更接近教师,优于未蒸馏基座
  • 教师与学生在同一 prompt 下的 Logits 分布差异,即 Step 3 ASFT 所要对齐的目标

五、目录结构与产物清单

执行完整流程后,Distill2/ 预期结构:

复制代码
Distill2/
├── SOP.md                          # 本文档
├── validation_prompt.txt           # 4.3 节从数据集导出的验证 prompt
├── models/                         # ModelScope 下载缓存
│   └── models/
│       ├── Qwen--Qwen3-4B-Instruct-2507/snapshots/master/
│       └── Qwen--Qwen3-1.7B/snapshots/master/
└── LLaMA-Factory/
    ├── data/
    │   └── dataset_info.json       # 内置 alpaca_gpt4_zh 注册
    ├── examples/
    │   ├── train_lora/
    │   │   ├── smoke_data_load.yaml    # 4.4 数据加载冒烟
    │   │   ├── qwen3_4b_teacher_lora.yaml
    │   │   └── qwen3_1.7b_distill_lora.yaml
    │   └── merge_lora/
    │       ├── qwen3_4b_teacher_merge.yaml
    │       └── qwen3_1.7b_student_merge.yaml
    └── saves/
        ├── smoke/data-load/            # 4.4 冒烟产出
        ├── qwen3-4b/
        │   ├── lora/teacher-sft/       # Step1 产出
        │   └── merged-teacher/         # Step2 产出 → ref_model
        └── qwen3-1.7b/
            ├── lora/distill/           # Step3 产出
            └── merged-student/         # Step4 产出 → 最终部署模型

产物路径对照表:

步骤 产物 路径
1 教师 LoRA adapter saves/qwen3-4b/lora/teacher-sft/
2 合并后全参数教师 saves/qwen3-4b/merged-teacher/
3 学生 LoRA adapter saves/qwen3-1.7b/lora/distill/
4 合并后全参数学生 saves/qwen3-1.7b/merged-student/

六、硬件与显存估算

步骤 加载模型 建议 GPU 显存
Step 1 教师 LoRA SFT 4B + LoRA ≥ 16 GB(24 GB 较稳妥)
Step 2 合并教师 4B(CPU export) 主要占用内存,GPU 可选
Step 3 白盒蒸馏 4B 教师(冻结)+ 1.7B 学生 + LoRA ≥ 24 GB
Step 4 合并学生 1.7B(CPU export) 主要占用内存
Step 4 推理验证 1.7B ≥ 8 GB

LoRA 显存参考(来自 LLaMA-Factory 社区经验):

模型参数量 LoRA 训练(约)
4B ~10--16 GB
1.7B ~6--10 GB
4B + 1.7B 同卡蒸馏 ~20--28 GB

云平台: AutoDL(https://www.autodl.com/)、魔搭社区(https://www.modelscope.cn/)


七、故障排查

问题 可能原因 解决方案
蒸馏等同普通 SFT,loss 无 KL 效果 LoRA 未配置 ref_model 在蒸馏 YAML 中添加 ref_model: saves/qwen3-4b/merged-teacher
ref_model 路径找不到 Step 2 未执行或路径错误 确认 merged-teacher/ 存在且含 model.safetensors
CUDA OOM(Step 3) 双模型同卡显存不足 减小 batch、启用 DeepSpeed ZeRO-3 offload、或使用更大显存 GPU
数据集加载失败 Hub 未下载或 dataset_info.json 无注册项 重跑 4.2 预下载;执行 4.1 确认 alpaca_gpt4_zh 存在
模板不匹配 / 生成乱码 教师/学生 template 不一致 统一使用 qwen3_nothink
合并失败 使用了量化模型 merge 时不要 设置 quantization_bit
蒸馏后效果接近基座 教师 SFT 不充分、epoch 不足或 asft_alpha 过小 检查 Step 1/3 loss;正式训练用 30 epoch;尝试 asft_alpha: 0.2
torchaudio / CUDA 版本冲突 pip 拉取了不兼容包 见第三节依赖问题表
ModuleNotFoundError: addict ModelScope MsDataset 依赖缺失 pip install addict
训练时 HF 数据集 unreachable 默认走 HuggingFace Hub 改用 alpaca_gpt4_zh_local 本地 JSON(见 4.6)或 export USE_MODELSCOPE_HUB=1
合并/export 报 No space left on device /root/autodl-tmp 仅 50GB,双模型+合并产物占满 见第九节磁盘策略;合并前 df -h 确保 ≥8GB 可用

八、验收标准与实施检查清单

验收标准

  • 教师 LoRA 训练 loss 收敛;合并后(或 LoRA)在验证 prompt 上给出结构化中文回答
  • 蒸馏训练 YAML 中 use_asft_loss: trueref_model 指向合并教师(日志含 Created reference model
  • 学生合并后参数量约 1.7B(all params: 1,720,574,976
  • 基座 / 教师 / 学生三者对比已完成(见 validation_prompt.txt

实施检查清单

环境:

  • Distill2/LLaMA-Factory 已 clone 且 llamafactory-cli version 正常(v0.9.6.dev0)
  • 教师、学生模型已下载至 Distill2/models/

数据集(第三节 4.1--4.4,不可跳过):

  • 4.1 确认 alpaca_gpt4_zh 已在 dataset_info.json 注册
  • 4.2 预下载完成(ModelScope;需 pip install addict
  • 4.3 抽样预览通过,validation_prompt.txt 已生成
  • 4.4 smoke_data_load.yaml 跑通 max_steps: 1(train_loss≈2.11)
  • 4.6 导出 alpaca_gpt4_zh_local 本地 JSON(42,677 条)

四步流程(冒烟 2026-07-08):

  • Step 1:教师 LoRA SFT(50 samples, 1 epoch, train_loss≈2.54, 18s)
  • Step 2:教师合并(首次因磁盘满失败,清理后成功)
  • Step 3:ASFT 蒸馏(train_loss≈0.94, 17s, ref_model 加载成功)
  • Step 4:学生合并 + 三路推理验证

冒烟(推荐先做):

  • max_samples: 50num_train_epochs: 1 跑通 Step 1 → 4 全流程
  • 冒烟通过后再改为 30 Epoch 正式训练(本次未执行)

附录:命令速查

bash 复制代码
# 环境
cd /root/autodl-tmp/Distill2/LLaMA-Factory

# 4.4 数据加载冒烟
llamafactory-cli train examples/train_lora/smoke_data_load.yaml

# Step 1 教师 LoRA SFT
llamafactory-cli train examples/train_lora/qwen3_4b_teacher_lora.yaml

# Step 2 合并教师
llamafactory-cli export examples/merge_lora/qwen3_4b_teacher_merge.yaml

# Step 3 白盒蒸馏
llamafactory-cli train examples/train_lora/qwen3_1.7b_distill_lora.yaml

# Step 4 合并学生
llamafactory-cli export examples/merge_lora/qwen3_1.7b_student_merge.yaml

九、实测执行记录(冒烟全流程 2026-07-08)

硬件:NVIDIA RTX 3090 24GB · PyTorch 2.8.0+cu128 · LLaMA-Factory 0.9.6.dev0

日志目录:Distill2/logs_*.log · 配置已写入 LLaMA-Factory/examples/

9.1 环境与路径(实测)

项目 实测值
教师路径 /root/autodl-tmp/Distill2/models/models/Qwen--Qwen3-4B-Instruct-2507/snapshots/master
学生路径 /root/autodl-tmp/Distill2/models/models/Qwen--Qwen3-1.7B/snapshots/master
本地数据集 LLaMA-Factory/data/alpaca_gpt4_zh.json(42,677 条,26MB)
验证 prompt Distill2/validation_prompt.txt保持健康的三个提示。

9.2 遇到的问题与解决方案

# 阶段 问题 解决方案
1 4.2 预下载 ModuleNotFoundError: No module named 'addict' pip install addict
2 Step 1 训练 HF Hub unreachable,无法加载 alpaca_gpt4_zh 导出本地 JSON + 注册 alpaca_gpt4_zh_local;YAML 改 dataset: alpaca_gpt4_zh_local
3 Step 2 合并 SafetensorError: No space left on device 清理磁盘:删除 Distill/modelsDistill/saves(~5.8GB)、seg-ui.zip(1.2GB);合并前保持 ≥8GB 可用
4 Step 4 合并 同上磁盘满(教师+学生+双份合并产物) 蒸馏完成后删除 saves/qwen3-4b/merged-teacher(~7.6GB)再合并学生;或磁盘扩容至 ≥100GB
5 推理验证 双模型同时加载 OOM 风险 逐模型加载 ,每次 torch.cuda.empty_cache();教师用 PeftModel+LoRA,无需保留合并教师
6 学生回答 蒸馏后仍输出 `` 思维链 Qwen3-1.7B 为 Thinking 基座,1 epoch/50 样本冒烟不足以对齐 Instruct 风格;正式训练需 30 epoch 或换 Instruct 学生

磁盘规划建议(50GB 数据盘): 无法同时保留「双基座 + 教师合并 + 学生合并」全副本。推荐流程:
#mermaid-svg-5qQVAl4YQeA4uXOd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5qQVAl4YQeA4uXOd .error-icon{fill:#552222;}#mermaid-svg-5qQVAl4YQeA4uXOd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5qQVAl4YQeA4uXOd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5qQVAl4YQeA4uXOd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5qQVAl4YQeA4uXOd .marker.cross{stroke:#333333;}#mermaid-svg-5qQVAl4YQeA4uXOd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5qQVAl4YQeA4uXOd p{margin:0;}#mermaid-svg-5qQVAl4YQeA4uXOd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd .cluster-label text{fill:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd .cluster-label span{color:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd .cluster-label span p{background-color:transparent;}#mermaid-svg-5qQVAl4YQeA4uXOd .label text,#mermaid-svg-5qQVAl4YQeA4uXOd span{fill:#333;color:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd .node rect,#mermaid-svg-5qQVAl4YQeA4uXOd .node circle,#mermaid-svg-5qQVAl4YQeA4uXOd .node ellipse,#mermaid-svg-5qQVAl4YQeA4uXOd .node polygon,#mermaid-svg-5qQVAl4YQeA4uXOd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5qQVAl4YQeA4uXOd .rough-node .label text,#mermaid-svg-5qQVAl4YQeA4uXOd .node .label text,#mermaid-svg-5qQVAl4YQeA4uXOd .image-shape .label,#mermaid-svg-5qQVAl4YQeA4uXOd .icon-shape .label{text-anchor:middle;}#mermaid-svg-5qQVAl4YQeA4uXOd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5qQVAl4YQeA4uXOd .rough-node .label,#mermaid-svg-5qQVAl4YQeA4uXOd .node .label,#mermaid-svg-5qQVAl4YQeA4uXOd .image-shape .label,#mermaid-svg-5qQVAl4YQeA4uXOd .icon-shape .label{text-align:center;}#mermaid-svg-5qQVAl4YQeA4uXOd .node.clickable{cursor:pointer;}#mermaid-svg-5qQVAl4YQeA4uXOd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5qQVAl4YQeA4uXOd .arrowheadPath{fill:#333333;}#mermaid-svg-5qQVAl4YQeA4uXOd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5qQVAl4YQeA4uXOd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5qQVAl4YQeA4uXOd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5qQVAl4YQeA4uXOd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5qQVAl4YQeA4uXOd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5qQVAl4YQeA4uXOd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5qQVAl4YQeA4uXOd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5qQVAl4YQeA4uXOd .cluster text{fill:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd .cluster span{color:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5qQVAl4YQeA4uXOd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5qQVAl4YQeA4uXOd rect.text{fill:none;stroke-width:0;}#mermaid-svg-5qQVAl4YQeA4uXOd .icon-shape,#mermaid-svg-5qQVAl4YQeA4uXOd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5qQVAl4YQeA4uXOd .icon-shape p,#mermaid-svg-5qQVAl4YQeA4uXOd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5qQVAl4YQeA4uXOd .icon-shape .label rect,#mermaid-svg-5qQVAl4YQeA4uXOd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5qQVAl4YQeA4uXOd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5qQVAl4YQeA4uXOd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5qQVAl4YQeA4uXOd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Step1 教师LoRA
Step2 合并教师
Step3 蒸馏
删除 merged-teacher 释放7.6GB
Step4 合并学生

Step 3 磁盘不足时的备选: 不合并教师,YAML 改用:

yaml 复制代码
ref_model: <TEACHER_PATH>
ref_model_adapters: saves/qwen3-4b/lora/teacher-sft

9.3 冒烟训练指标

步骤 配置 耗时 train_loss 备注
4.4 数据加载 max_samples=5, max_steps=1 1.1s 2.11 本地 JSON 加载正常
Step 1 教师 SFT 50 samples, 1 epoch 18.3s 2.54 13 steps
Step 2 教师合并 CPU export ~35s --- 产出 ~7.6GB(冒烟后已删)
Step 3 蒸馏 50 samples, 1 epoch, ASFT 16.7s 0.94 日志:Created reference model from saves/qwen3-4b/merged-teacher
Step 4 学生合并 CPU export ~16s --- 产出 ~3.4GB

9.4 推理对比(同一条验证 prompt)

Prompt: 保持健康的三个提示。

模型 回答特征(摘要)
基座 Qwen3-1.7B 输出 `` 思维链,未直接给出三点列表
教师 Qwen3-4B+LoRA 直接输出结构化三点:均衡饮食 / 规律运动 / 充足睡眠,与训练数据风格一致
蒸馏学生 merged 冒烟 1 epoch 后仍偏 Thinking 风格,未明显接近教师(需正式 30 epoch)

结论: 四步链路已跑通;白盒 ASFT 蒸馏工程链路正确(ref_model 加载、loss 收敛)。效果层面 需正式规模训练;另建议评估将学生换为 Instruct 版本或在 Thinking 模型上使用 template: qwen3 而非 qwen3_nothink

9.5 实测产物清单

复制代码
Distill2/
├── validation_prompt.txt
├── logs_step1_teacher.log
├── logs_smoke_data_load.log
├── logs_step2_merge_teacher.log
├── logs_step3_distill.log
├── logs_step4_merge_student.log
└── LLaMA-Factory/
    ├── data/alpaca_gpt4_zh.json          # 本地数据集
    ├── saves/qwen3-4b/lora/teacher-sft/  # 教师 LoRA
    ├── saves/qwen3-1.7b/lora/distill/      # 学生 LoRA
    └── saves/qwen3-1.7b/merged-student/    # 最终可部署模型

参考文档:

相关推荐
阿成学长_Cain1 小时前
Linux grpck命令超全详解|校验组文件完整性、修复/etc/group错误实战
linux·运维·服务器·网络
2401_868534781 小时前
案例介绍-小型网络规划及搭
python·计算机网络
Token炼金师1 小时前
工程基础设施层:MLOps闭环断裂让模型上线即裸奔
人工智能·深度学习·llm
ONE_SIX_MIX1 小时前
lightweight-charts-onesixth v2.8.1 → v3.1.1 更新总览
java·前端·python
YUS云生1 小时前
Python学习笔记·第29天:Git进阶——分支操作与合并冲突
笔记·python·学习
小雨青年1 小时前
【HarmonyOS 7开发者前瞻】06 HarmonyOS 7 AI 能力接入前,先用业务场景判断优先级
人工智能·华为·harmonyos
杖雍皓1 小时前
没有服务器如何构建现代 Web 应用:平台选型与组合策略
运维·服务器·前端·react.js·github·netlify·vercel
指尖的爷1 小时前
Ubuntu 24.04 彻底关闭自动更新(桌面+服务器通用)
服务器·数据库·ubuntu
格子生意经1 小时前
GEO系统多引擎自适应算法实战解析
大数据·人工智能