【AI大模型】大模型知识蒸馏实战:提升BGE-m3性能10%的技术解析,收藏这一篇就够了!!
技术专精,深度解析
BGE-m3是开源社区下载量最高的向量模型之一,在RAG(检索增强生成,Retrieval-Augmented Generation)中用于文档检索。通常,模型微调的一大难点在于需构建高质量数据集:若合成数据或人工标注精度不足,过于绝对的监督信号会放大这种偏差,进而导致模型过拟合(overfitting)与灾难性遗忘(catastrophic forgetting)。而借助更强大的教师模型生成软标签(soft label)进行知识蒸馏,可提供更精细的监督信号,从而缓解上述问题。当你面临数据质量有限的情况时,这种方法值得一试。

近期,阿里云发布了Qwen3-Embedding系列SOTA(state-of-the-art,当前最优)向量模型。本文以该系列中性能最强的Qwen3-Embedding-8B(教师模型)为基础,将其知识蒸馏至参数规模为0.6B的BGE-m3(学生模型)中。实验结果表明,通过该方法,学生模型在scidocs-reranking数据集上的MAP@10指标提升幅度达10.20%,且在领域外数据集上的性能下降幅度低于2.5%。本项目代码已开源至GitHub:ttps://github.com/kanhaoning/RAG-Optimization-Practices
一、核心工具与方法
1.1 核心工具
| 类别 | 具体信息 |
|---|---|
| 教师模型 | Qwen/Qwen3-Embedding-8B (80亿参数) |
| 学生模型 | BAAI/bge-m3 (6亿参数) |
| 训练/评测框架 | sentence-transformers |
| 数据集 | MTEB/scidocs-reranking 、MTEB/Stackoverflowdupquestions-reranking |
| 推理加速框架 | vLLM |

1.2 训练方法:基于KL散度的知识蒸馏
本次实践采用sentence-transformers库中更适用于排序蒸馏任务的DistillKLDivLoss(KL散度蒸馏损失函数)。
该方法的核心思想是:让学生模型学习教师模型计算得出的“查询-文档相似度完整概率分布”,从而更精细地传递教师模型的“排序偏好”。
其损失函数为教师模型概率分布与学生模型概率分布之间的KL散度(Kullback-Leibler Divergence)。
具体步骤如下:
- • 对于单个查询
Q与一组文档{P1, P2, ..., Pn}(含1个正样本与多个负样本),分别通过教师模型与学生模型计算二者间的相似度分数。 - • 利用带温度系数(temperature)的
Softmax函数,将相似度分数转换为概率分布。温度可平滑概率分布,降低教师模型判断的“绝对性”,从而为学生模型提供更丰富的学习信号。 - • 计算两个概率分布的KL散度作为损失值。此处乘以是为了在Softmax函数平滑概率分布时补偿梯度,确保梯度稳定性。

在源码实现中,为避免数值下溢出,通过更稳定的log_softmax函数计算。
各符号含义说明:
- • :查询(Query)。
- • :一组候选文档,包含1个正样本(Positive)与多个负样本(Negative)。
- • 、:分别为教师(teacher)模型与学生(student)模型计算的相似度分数。
- • :温度系数(temperature),用于软化概率分布。
- • :表示KL散度(Kullback-Leibler Divergence)。
二、环境准备

首先,请确保安装所有必要的库。本次实验使用的主要库及其版本如下:
Package Version
----------------------- ------------------------
torch 2.6.0
sentence-transformers 5.0.0
transformers 4.53.1
vllm 0.8.4
若尚未安装,可通过pip命令安装:
pip install torch sentence-transformers==5.0.0 transformers==4.53.1 vllm==0.8.4
# modelscope 用于便捷下载国内模型
pip install modelscope
三、复现步骤

整个流程分为四步:生成教师分数→构建训练数据→训练学生模型→性能评测。所有步骤均已封装为脚本,只需按顺序执行即可。
步骤1:下载模型与数据集
首先,需准备好教师模型、学生模型及相关数据集。
- 下载BGE-m3(学生模型)
from modelscope import snapshot_download
model_dir = snapshot_download('BAAI/bge-m3', cache_dir='/path/to/your/models')
- 下载Qwen3-Embedding-8B(教师模型)
from modelscope import snapshot_download
model_dir = snapshot_download('Qwen/Qwen3-Embedding-8B', cache_dir='/path/to/your/models')
- 下载Scidocs数据集
注意:直接拉取该数据集可能报错,建议手动下载:
访问MTEB/scidocs-reranking页面,手动下载validation.jsonl.gz与test.jsonl.gz(两个文件均为3.5MB),并将其保存至路径Embedding-Distillation/dataset_scidocs,随后执行以下代码解压:
gunzip validation.jsonl.gz
gunzip test.jsonl.gz
解压后,Embedding-Distillation/dataset_scidocs目录下应包含validation.jsonl与test.jsonl两个文件。为降低复现成本,本次实验以validation.jsonl作为训练集,test.jsonl作为领域内测试集。
-
- 下载Stackoverflowdupquestions数据集
访问MTEB/stackoverflowdupquestions-reranking页面,手动下载test.jsonl.gz(1.35MB),保存至路径Embedding-Distillation/dataset_stackoverflowdupquestions,然后执行以下代码解压:
- 下载Stackoverflowdupquestions数据集
gunzip test.jsonl.gz
解压后,Embedding-Distillation/dataset_stackoverflowdupquestions目录下应包含test.jsonl文件。为测试模型是否发生灾难性遗忘,本次实验以该文件作为领域外测试集。
步骤2:生成蒸馏数据集
本步骤的目标是利用性能更强的教师模型Qwen3-Embedding-8B,为数据集中的每个(query, passage)对计算相似度分数。由于数据集规模较大(训练集含约8.8万个文档片段),直接使用transformers库计算会非常耗时。为大幅提升效率,本次采用vLLM框架进行推理加速。
执行脚本:
bash generate_distillation_data.sh
该脚本会调用generate_distillation_data.py。运行前,请修改脚本中的--teacher_model_path参数,使其指向你已下载的Qwen3-Embedding-8B模型路径。
实现思路
generate_distillation_data.py的逻辑清晰高效,可拆解为以下四步:
- 读取与展开数据
脚本首先读取原始validation.jsonl文件,该文件每一行包含1个query、1个positive列表(正样本文档)与1个negative列表(负样本文档)。为给DistillKLDivLoss准备输入数据,脚本使用itertools.product(笛卡尔积)将正样本与负样本文档两两组合,生成大量(query, positive_doc, negative_doc)三元组。
# 关键代码片段1:使用笛卡尔积生成三元组
from itertools import product
for pos_item, neg_item in product(positives, negatives):
unique_texts.add(pos_item)
unique_texts.add(neg_item)
triplets.append({'query': query, 'positive': pos_item, 'negative': neg_item})
- 批量向量化
为最大化效率,脚本会收集所有不重复的文本(包括所有查询、正样本与负样本),然后通过vLLM的model.embed()方法一次性将其全部转换为向量。需注意:Qwen3-Embedding官方代码会为查询添加任务指令(如“Given a web search query, retrieve relevant passages that answer the query”),但实测表明该操作会降低蒸馏效果,因此本次实验未使用该指令。
# 关键代码片段2:使用vLLM进行高效批量编码
input_texts = list(unique_texts)
outputs = model.embed(input_texts)
all_embeddings = [torch.tensor(o.outputs.embedding) for o in outputs]
- 计算教师分数
获取所有文本的向量后,脚本为每个三元组计算教师模型给出的余弦相似度分数。对于标准化向量,余弦相似度可通过更简便的内积运算等效实现。
# 关键代码片段3:计算(query, pos)与(query, neg)的相似度
emb_q = text_to_embedding.get(q_text)
emb_p = text_to_embedding.get(p_text)
emb_n = text_to_embedding.get(n_text)
sim_pos = similarity(emb_q, emb_p)
sim_neg = similarity(emb_q, emb_n)
- 生成蒸馏文件
最后,脚本将每个三元组及其对应的两个相似度分数封装为新的JSON对象,写入输出文件。该格式恰好满足DistillKLDivLoss的输入要求。
# 关键代码片段4:构建最终的输出记录
record = {
"query": q_text,
"positive": p_text,
"negative": n_text,
"label": [sim_pos, sim_neg] # “软标签”
}
f_out.write(json.dumps(record, ensure_ascii=False) + '\n')
注意:此处每个样本仅包含(query, positive, negative)三元组,将公式中的候选文档集合{P_i}简化为{positive, negative}两个文档。教师模型生成的label即[M_t(Q, P_positive), M_t(Q, P_negative)]。实际实践中无需局限于“单个负样本”的格式——sentence-transformers实现的DistillKLDivLoss同样支持单个样本含多个负样本的情况,例如格式{"query": "q_text", "positive": "p_text", "negative1": "n_text1", "negative2": "n_text2", "label": [0.6, 0.3, 0.1]},但这种格式会增加超参数调优的难度。
最终,在Embedding-Distillation/dataset_scidocs路径下会生成供模型训练的jsonl文件validation_kldiv_distill.jsonl,以下为一个样本示例:
{"query": "Beauty eMakeup: A Deep Makeup Transfer System", "positive": "Learning Hierarchical Features for Scene Labeling", "negative": "Registration with the Point Cloud Library: A Modular Framework for Aligning in 3-D", "label": [0.6058026552200317, 0.5828931331634521]}
步骤3:训练学生模型
接下来开始训练学生模型BAAI/bge-m3。
执行脚本:
bash train.sh
该命令会执行train.py脚本。运行前,请务必检查并修改train.sh中的以下关键路径与参数:
- •
--student_model_name_or_path:将your_path_to/bge-m3修改为你已下载的bge-m3模型路径。 - •
--train_dataset_path:确认该路径指向步骤2生成的validation_kldiv_distill.jsonl文件。 - •
--output_dir:指定用于保存训练模型检查点(checkpoint)的目录。
该脚本基于sentence-transformers库实现,核心逻辑分为以下几步:
实现思路
- 加载学生模型和数据集
脚本首先加载预训练的学生模型bge-m3(该模型为SentenceTransformer双编码器模型,可将文本高效映射至向量空间),随后加载步骤2生成的.jsonl格式蒸馏数据集。
# 文件:train.py
# 1. 加载学生模型
student_model = SentenceTransformer(model_args.student_model_name_or_path)
# 2. 加载蒸馏数据集
# 每条样本包含 query、positive、negative 和 label 字段
train_dataset = load_dataset("json", data_files=model_args.train_dataset_path)["train"]
- 定义
DistillKLDivLoss损失函数
该损失函数的实现细节如下:
- • 接收参数:学生模型
model与温度系数temperature。 - • 训练过程:利用学生模型计算
(query, positive)与(query, negative)的相似度分数;将学生模型分数与数据集中教师模型提供的label(即[teacher_pos_score, teacher_neg_score])均通过Softmax函数转换为概率分布;计算两个概率分布的KL散度,并将其作为损失值进行反向传播,引导学生模型模仿教师模型的打分分布。
使用代码如下:
# 文件:train.py
from sentence_transformers import losses
# 定义KL散度蒸馏损失
train_loss = losses.DistillKLDivLoss(
model=student_model,
temperature=model_args.temperature # 温度参数,默认值为2.0
)
- 初始化并运行
SentenceTransformerTrainer
最后,将学生模型、训练参数、蒸馏数据集与损失函数等组件传入SentenceTransformerTrainer。该Trainer已封装批量处理、梯度累积、学习率调度、日志记录与模型保存等训练细节。
# 文件:train.py
from sentence_transformers.trainer import SentenceTransformerTrainer
trainer = SentenceTransformerTrainer(
model=student_model,
args=training_args,
train_dataset=train_dataset,
loss=train_loss,
)
# 启动训练
trainer.train()
关键参数说明
--per_device_train_batch_size与--gradient_accumulation_steps:这两个参数共同决定有效批处理大小(例如16 * 32 = 512),是重要的超参数,需根据GPU显存大小与实验效果调整。--learning_rate:学习率,决定模型参数更新的步长。--bf16:启用bfloat16混合精度训练,相比fp16能提升训练的数值稳定性,但在计算能力(Compute Capability)低于8.0的旧款GPU(如V100、2080Ti等)上可能不支持。
训练启动后,可通过日志实时监控训练进度。训练完成后,最终模型与检查点将保存至--output_dir指定的目录,用于下一步性能评测。
步骤4:性能评测
训练完成后,需验证以下两个核心问题:
- 学生模型在领域内(
scidocs数据集)的性能提升幅度如何? - 学生模型在领域外(如
stackoverflowdupquestions数据集)的性能是否大幅下降?
本次实验将分别使用蒸馏前后的bge-m3模型,通过sentence-transformers库实现的RerankingEvaluator(重排序评估器),对领域内与领域外两个测试集进行快速评测。
执行脚本:
bash evaluation.sh
该命令会调用evaluation.py脚本执行完整评测流程。运行前,请务必修改evaluation.sh中的模型路径:
--model_before:保持为原始BAAI/bge-m3模型的路径。--model_after:修改为步骤3训练生成的检查点路径(例如output/checkpoint-1000)。--in_domain_dataset:确认指向dataset_scidocs/test.jsonl。--out_domain_dataset:确认指向dataset_stackoverflowdupquestions/test.jsonl。
四、结果

待evaluation.py脚本运行完毕后,将生成如下评测结果表格:
| 指标 | 蒸馏前 | 蒸馏后 | 绝对变化 | 相对变化(%) |
|---|---|---|---|---|
| 领域内 (scidocs) | ||||
| map | 0.7744 | 0.8534 | +0.0790 | +10.20 |
| mrr@10 | 0.9321 | 0.9554 | +0.0233 | +2.50 |
| ndcg@10 | 0.8296 | 0.8973 | +0.0676 | +8.15 |
| 领域外 (stackoverflow) | ||||
| map | 0.5168 | 0.5040 | -0.0129 | -2.49 |
| mrr@10 | 0.5240 | 0.5116 | -0.0124 | -2.37 |
| ndcg@10 | 0.5904 | 0.5774 | -0.0129 | -2.19 |
(注:受训练随机性、超参数设置等因素影响,你的实测数值可能存在微小差异,但整体趋势保持一致。)
从结果中可得出以下两个核心结论:
- 领域内性能显著提升:在目标任务
scidocs数据集上,三个关键指标(MAP、MRR@10、NDCG@10)均实现明显增长,其中MAP指标提升10.20%。这证明知识蒸馏有效——学生模型成功从教师模型Qwen3-Embedding-8B中学习到更精细的排序知识,使其在专业领域的文档排序能力显著增强。 - 通用能力基本保持:在领域外
stackoverflowdupquestions数据集上,模型性能仅出现小幅下降(MAP指标下降2.49%),未发生灾难性遗忘。这表明学生模型在提升特定领域能力的同时,基本保留了原有的通用检索能力。
实测表明,相比硬标签(hard label)损失函数(如MultipleNegativesRankingLoss、TripletLoss),使用软标签的DistillKLDivLoss在“保留模型通用能力”与“提升泛化能力”方面整体更具优势,但也存在失效场景(例如教师模型在某数据集上表现不佳时)。实际应用中,需结合数据量、数据质量及教师模型性能,综合选择合适的方法。
最后
为什么要学AI大模型
当下,⼈⼯智能市场迎来了爆发期,并逐渐进⼊以⼈⼯通⽤智能(AGI)为主导的新时代。企业纷纷官宣“ AI+ ”战略,为新兴技术⼈才创造丰富的就业机会,⼈才缺⼝将达 400 万!
DeepSeek问世以来,生成式AI和大模型技术爆发式增长,让很多岗位重新成了炙手可热的新星,岗位薪资远超很多后端岗位,在程序员中稳居前列。

与此同时AI与各行各业深度融合,飞速发展,成为炙手可热的新风口,企业非常需要了解AI、懂AI、会用AI的员工,纷纷开出高薪招聘AI大模型相关岗位。
最近很多程序员朋友都已经学习或者准备学习 AI 大模型,后台也经常会有小伙伴咨询学习路线和学习资料,我特别拜托北京清华大学学士和美国加州理工学院博士学位的鲁为民老师给大家这里给大家准备了一份涵盖了AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频 全系列的学习资料,这些学习资料不仅深入浅出,而且非常实用,让大家系统而高效地掌握AI大模型的各个知识点。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
AI大模型系统学习路线
在面对AI大模型开发领域的复杂与深入,精准学习显得尤为重要。一份系统的技术路线图,不仅能够帮助开发者清晰地了解从入门到精通所需掌握的知识点,还能提供一条高效、有序的学习路径。

但知道是一回事,做又是另一回事,初学者最常遇到的问题主要是理论知识缺乏、资源和工具的限制、模型理解和调试的复杂性,在这基础上,找到高质量的学习资源,不浪费时间、不走弯路,又是重中之重。
AI大模型入门到实战的视频教程+项目包
看视频学习是一种高效、直观、灵活且富有吸引力的学习方式,可以更直观地展示过程,能有效提升学习兴趣和理解力,是现在获取知识的重要途径

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
海量AI大模型必读的经典书籍(PDF)
阅读AI大模型经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习AI大模型开发的读者来说,阅读经典书籍是非常有必要的。
600+AI大模型报告(实时更新)
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
AI大模型面试真题+答案解析
我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

更多推荐


所有评论(0)