中文 | English
利用 Qwen3-VL-32B 大模型的推理能力,通过知识蒸馏构建增强数据集,对 Qwen3-VL-2B 小模型进行 QLoRA 微调,使其在单卡可部署的条件下获得接近大模型的图表数值推理能力。
ChartQA/
├── sft/ # 监督微调训练
│ ├── __init__.py
│ ├── config.py # 超参数配置(dataclass 体系)
│ ├── model.py # 模型加载与 LoRA 适配
│ ├── data_loader.py # 数据集加载与预处理
│ ├── collator.py # 数据整理与标签掩码
│ ├── callbacks.py # 训练回调(监控、早停)
│ ├── trainer.py # 训练器设置
│ └── train.py # SFT 训练入口
│
├── ChartQADataset/ # ChartQA 数据集
│ ├── train/ # 训练集
│ ├── val/ # 验证集
│ └── test/ # 测试集
│
├── test_model.py # 评估脚本(六项指标)
├── requirements.txt # Python 依赖
├── README.md # 本文档
└── LICENSE # MIT License
pip install -r requirements.txt| 维度 | Qwen3-VL-32B-Thinking | Qwen3-VL-8B-Thinking | Qwen3-VL-2B-Thinking | 差距 |
|---|---|---|---|---|
| FP16 显存需求(仅权重) | ~64 GB | ~16 GB | ~4 GB | 16 倍(32B vs 2B) |
| 最低部署硬件 | 多张 A100 / H100 | 单张 5090 32GB | 单张 RTX 4060 8GB | 硬件成本相差 4-30 倍 |
| 单条推理延迟 | ~2-5 秒 | ~0.8-1.5 秒 | ~0.3-0.8 秒 | 3-6 倍 |
矛盾一:部署成本 vs 推理能力
→ 32B 效果好但太贵,2B 便宜但数值推理能力显著不足
矛盾二:数据标注 vs 标注成本
→ 要让 2B 学会推理链,需要 (问题, 推理链, 答案) 三元组标注,
但人工编写上千条结构化推理链的成本不可接受
矛盾三:端到端 SFT vs 推理能力
→ 如果只用 (问题, 答案) 二元组做 SFT,小模型会"死记硬背"——
看到 "2019" 就猜最大数值,看到柱状图就输出最高柱子对应的值,
而不会真正地定位坐标轴、读取数值、做计算
解决方案:用 32B 大模型的推理产出为 2B 小模型生成训练标注,让小模型学会"像大模型一样逐步思考图表问题",在单卡可部署的模型尺寸下获得接近大模型的数值推理准确率。
原始 ChartQA 数据集仅包含 (image, question, label) 三字段,没有推理链标注:
{
"image": "multi_col_20134.png",
"question": "What is the estimated cyber security market size of the defense and intelligence sector in 2017?",
"label": "250"
}使用 Qwen3-VL-32B-Thinking 作为教师模型,在 ChartQA 数据集上逐条推理,自动生成高质量推理链。 输入教师模型的 prompt 设计如下:
You are a helpful assistant capable of visual reasoning for answering questions about charts.
Given a chart image and a question, you will first analyze the chart step by step, then provide the final answer in a JSON format:
{answer: "your_answer"}
Make sure to include a detailed reasoning process before the final answer.
Here is the chart image: {image_path}
Question: {question}
教师模型输出格式为:
<think>推理过程</think>
<answer>答案</answer>
示例:
输入:
"""
You are a helpful assistant capable of visual reasoning for answering questions about charts.
Given a chart image and a question, you will first analyze the chart step by step, then provide the final answer in a JSON format:
{answer: "your_answer"}
Make sure to include a detailed reasoning process before the final answer.
Here is the chart image: multi_col_20134.png
Question: What is the estimated cyber security market size of the defense and intelligence sector in 2017?
"""<think>Got it, let's look at the bar chart. The question is about the defense and intelligence sector's cyber security market size in 2017. The chart has two segments for each year: blue is "Other Public Sector" and black is "Defence and Intelligence".
For 2017, the black segment (defence and intelligence) shows a value. Let me check the numbers. The black part for 2017 is labeled as 250 million GBP. Let me confirm. The y-axis is value in million GBP. The black bar in 2017 reaches up to 250. Yes, the label on top of the black segment for 2017 is 250.</think>
<answer>250</answer>
将蒸馏得到的数据转换为以下格式, 适配 SFT 训练代码:
{
"image": "multi_col_20134.png",
"question": " What is the estimated cyber security market size of the defense and intelligence sector in 2017?",
"think": "Got it, let's look at the bar chart. The question is about the defense and intelligence sector's cyber security market size in 2017. The chart has two segments for each year: blue is \"Other Public Sector\" and black is \"Defence and Intelligence\".\nFor 2017, the black segment (defence and intelligence) shows a value. Let me check the numbers. The black part for 2017 is labeled as 250 million GBP. Let me confirm. The y-axis is value in million GBP. The black bar in 2017 reaches up to 250. Yes, the label on top of the black segment for 2017 is 250.",
"answer": "250",
"label": "250"
}关键设计:
think字段:教师模型生成的逐步推理链,作为监督信号教会模型"先分析图表结构 → 定位数据 → 计算 → 再给出答案"answer字段:教师模型的输出答案(训练中不直接使用)label字段:原始数据集的真实标签,训练时模型的目标答案使用真实标签而非教师模型输出,确保推理链是参考、答案是标准的双重监督信号
ChartQADataset/
├── train/
│ ├── train_augmented.json # 蒸馏原始输出(含 <think> 标签)
│ ├── train_converted.json # 转换后的训练数据
│ └── png/ # 图表图片
├── val/
│ ├── val_augmented.json
│ ├── val_converted.json
│ └── png/
└── test/
├── test_augmented.json
└── png/
- 基座模型:Qwen3-VL-2B-Thinking(具备 CoT 推理架构的视觉语言模型)
- 微调方式:QLoRA(Quantized Low-Rank Adaptation)
- 可训练参数:1%(仅训练 attention 层的投影矩阵)
LoRA 通过低秩分解的方式向预训练模型的权重矩阵中注入可训练的秩分解矩阵,冻结原始模型参数,仅训练低秩适配器:
W = W₀ + BA
其中 W₀ 是冻结的预训练权重,B 和 A 是可训练的低秩矩阵(r << d)。
QLoRA 进一步将基座模型量化为 4-bit,在保持精度的同时大幅降低显存占用。
| 参数 | 值 | 说明 |
|---|---|---|
r (秩) |
16 | 低秩矩阵的秩,控制可训练参数量 |
lora_alpha |
32 | 缩放系数,通常设为 2r |
target_modules |
q_proj, k_proj, v_proj, o_proj |
注意力层的 4 个投影矩阵 |
lora_dropout |
0.05 | 防止过拟合 |
bias |
none |
不训练偏置项 |
task_type |
CAUSAL_LM |
因果语言建模任务 |
| 参数 | 值 |
|---|---|
| 学习率 | 2e-5 |
| 批次大小 | 2(每设备) |
| 梯度累积 | 8 步 |
| 有效批次大小 | 16 |
| 最大序列长度 | 1024 |
| 精度 | BF16 |
| 优化器 | adamw_torch |
| NEFTune noise alpha | 5.0(增加输入鲁棒性) |
| Early Stopping patience | 3 |
原始 JSON → 加载数据 → 构建对话 → 应用模板 → 处理器编码 → 标签掩码 → 训练批次
- 加载数据:从
train_converted.json读取 5 字段格式数据 - 构建对话:将
(system_prompt, question, think, label)组合为三轮对话 - 应用模板:使用
apply_chat_template将对话转为完整的文本序列 - 处理器编码:图像通过视觉编码器,文本通过 tokenizer
- 标签掩码:通过
_mask_labels将<think>之前的部分掩码为-100,仅训练模型生成推理链和答案 - 训练批次:动态填充到批次最大长度
训练样本的标签被格式化为统一模板:
{think_text} {answer: "label"}
系统 Prompt 明确要求模型"逐步推理后,以 {answer: 'your_answer'} 的 JSON 格式输出最终答案"。
python -m sft.train| 指标 | 说明 |
|---|---|
| Exact Match | 预测答案与标准答案归一化后完全匹配 |
| Numeric Accuracy | 数值答案的容差比较(相对误差 < 0.1%) |
| Token F1 | 预测与答案的 token 级别 F1 分数 |
| 格式合规率 | 输出中包含 {answer: '...'} JSON 格式的比例 |
| 答案提取成功率 | 能从模型长回复中成功提取 JSON 答案的比例 |
| 平均回复长度 | 模型输出的平均 token 数 |
python test_model.py结果保存为 JSON 文件,便于横向对比不同模型版本。
本项目的核心对比是经过知识蒸馏 + QLoRA 微调后的 2B 模型与原始未微调的 8B 基座模型之间的性能比较:
| 指标 | Qwen3-VL-2B(蒸馏 + QLoRA SFT) | Qwen3-VL-8B-Thinking(基座) | 说明 |
|---|---|---|---|
| Exact Match | 90.1%(64/71) | 90.1%(64/71) | 两者持平 |
| Numeric Accuracy | 93.0%(53/57) | 93.0%(53/57) | 数值推理能力相当 |
| 格式合规率 | 100%(71/71) | 100%(71/71) | 均能稳定输出 JSON 格式 |
| 答案提取成功率 | 100%(71/71) | 98.6%(70/71) | 2B 格式更稳定 |
| Token F1(均值) | 0.901 | 0.901 | 答案 token 重叠度相同 |
关键发现:
- 蒸馏 + QLoRA 微调后的 2B 模型在 Exact Match 上与原始 8B 模型持平(90.1% vs 90.1%)
- 数值推理准确率完全一致(93.0% vs 93.0%),Token F1 也完全相同(0.901)
- 但 2B 模型的显存需求仅为 8B 的 1/4,部署成本降低一个数量级
- 2B 模型的推理延迟比 8B 低 2-3 倍,更适合高并发场景
- 性价比优势显著:用 1/4 的显存、1/3 的推理时间,获得了与 8B 基座模型相同的推理准确率