你好,我是邢云阳。

上节课,我带领你借助开源大模型微调工具 LLama-Factory 对 DeepSeek-R1-Distill-Qwen-7B 进行了微调,实现了新闻分类器的效果。通过这样一个挺有意思的小案例,想必你也感受到了微调的魅力。这节课我们就把目光投向另一个大模型里常用的技术——蒸馏。

什么是蒸馏

那在春节前后呢,另一个大模型术语——蒸馏也是火起来了,不管知不知道啥叫蒸馏,反正都听说过。我在课程的[第一讲]曾用一个《射雕英雄传》的例子简单讲解过啥叫微调,今天我们就更加简单粗暴地讲解一下。

其实蒸馏呢,本质上也是微调的一种类型。传统微调是为了让大模型获取一些私域知识,比如股票、医疗等等,这是让大模型的知识面增加了,但没有改变大模型的能力。而蒸馏不一样,蒸馏不光教知识,还要教能力。所谓授之以鱼,不如授之以渔,蒸馏就是要让被训练的模型能够学会教师模型的能力。

我们知道传统的一些快速响应模型,比如 qwen2.5、llama3 等等模型是不带思维链的。但 DeepSeek-R1 模型带有思维链,而且思考能力很强。因此对 DeepSeek-R1 蒸馏的意义就是要让 qwen2.5 等模型也学会思维链,就是这么简单。

那接下来,我们看一下蒸馏一个自己的小模型,应该怎么做。

蒸馏的流程

首先,我们知道,只要涉及到微调,就少不了数据集,因此需要先从数据集着手。我在这画了一张简单的图来说明如何生成数据集。

首先,我们需要准备好一份传统的数据集,比如一些新闻标题的数据。

1
2
3
CF生存特训:落地“加特林”,还剩一滴血,千钧一发,队友来救!
崔海涛篆刻艺术展将于512日在青岛举行
球员生涯还剩一个月,吴伟超回忆申花邀请:曾以为是个玩笑

之后我们需要将这些数据喂给满血版的 DeepSeek-R1:671B 模型,让 DeepSeek-R1:671B 为我们输出带有思考过程和结果的回答,这便是我们的教学数据。那 DeepSeek-R1:671B 输出的回答的实际格式是什么样的呢?我们在之前的模型部署课程上,曾经用 curl 命令对 DeepSeek-R1 模型进行过提问,模型给出的回复格式是:

1
2
3
4
{"id":"chat-7b3532b3c7e3481b86104f17f744f26c","object":"chat.completion","created":1740925630,"model":"deepseek-r1","choices":[{"index":0,"message":{"role":"assistant","
content":"<think>我 是 DeepSeek-R1, 一 个 由 深 度 求 索 公 司 开 发 的 智 能 助 手 , 我 擅 长 通 过 思 考 来 帮 您 解 答 复 杂 的 数 学 , 代 码 和 逻 辑 推 理 等 理 工 类 问 题 。 \n</think>\n\n我 是 DeepSeek-R1, 一 个 由 深 度 求
索 公 司 开 发 的 智 能 助 手 , 我 擅 长 通 过 思 考 来 帮 您 解 答 复 杂 的 数 学 , 代 码 和 逻 辑 推 理 等 理 工 类 问 题 。 ","tool_calls":[]},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usa
ge":{"prompt_tokens":9,"total_tokens":108,"completion_tokens":99},"prompt_logprobs":null}

也就是说是如下形式:

1
<think>思考过程 \n</think>\n\n结果

当我们拿这些教学数据再去微调小模型时,就可以让小模型学会 DeepSeek-R1:671B 同款的输出回答的模式,这种微调方式叫做监督微调。

到此,蒸馏的流程就讲完了,整个过程其实非常简单,一点也不神秘,无非就是教学数据的生成与传统微调的教学数据相比,增加了思考过程。

那讲完了理论,接下来我们就开始实践。我们以 qwen2.5-7B 模型为例,蒸馏出一个我们自己的 DeepSeek-R1-Distill-Qwen2.5-7B 模型。

如何生成教学数据

首先从生成教学数据开始。

前面我们已经知道想要,生成用于蒸馏小模型的教学数据,需要将原始数据喂给 DeepSeek-R1大模型,从而生成带有高格调思考过程的问答对。

因此教学数据的模型,本质上还是 prompt 工程的范畴,需要我们根据实际业务情况编写合适的 prompt,这个每一种业务都不一样,无法形成一个标准的模板,但我们可以用新闻分类器的例子演示一下思路。

由于 DS 官方的服务器最近不是特别稳定,我依然使用的阿里云百炼提供的满血版 DeepSeek-R1 671B服务。我准备的原始数据集的样式如下:

1
2
3
新闻分类:《美国队长4》被调侃为《关云长4:周仓传》
新闻分类:特朗普与泽连斯基在白宫举行会谈时爆发激烈争吵
....

之后我的提示词这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
system = """
你是一个新闻分类器,擅长根据新闻标题识别新闻的类型,新闻种类包括:政治、经济、科技、娱乐、体育、教育、健康、国际、国内、社会。用户会在需要进行分类的新闻标题前加入"新闻分类:"字样,你需要给出该新闻的种类。要求包含思考过程和最终答案。


#要求格式:
<think>
思考过程(分步骤解释如何从给定信息中推导出答案)
</think>


答案(政治、经济、科技、娱乐、体育、教育、健康、国际、国内、社会中的某一种)


#示例1:
human: 新闻分类:给力!中国两次出手,美到手的订单黄了,该国从此只认中国制造!
gpt:
<think>
首先,我需要分析给出的新闻标题:“给力!中国两次出手,美到手的订单黄了,该国从此只认中国制造!”
接下来,根据标题内容进行分类。标题中提到了中国两次行动导致美国订单出现问题,并且其他国家开始依赖中国制造,说明这涉及国家之间的经济合作和社会影响。
结合新闻种类,考虑到涉及国际贸易和经济合作,最合适的分类是“经济”。所以,这条新闻应该归类到“经济”类别中。
</think>


经济
"""

这份提示词首先描述了需求,规定了新闻的分类有哪些种,还告诉了大模型当用户输入什么格式的内容时,大模型需要进行分类。之后的要求格式的样式,大家可以当作模板,然后根据自己的实际业务修改答案部分的描述。

比较难的部分在于示例,这块就是我给很多同学回复留言时说的,要懂业务,如果不懂业务,提示词都写不出来。这是因为我们需要写一个 think 的例子,例子要逼真,符合 DS-R1 的口吻,这样才能得到好的效果。

之后就是常规的向大模型提问,以及反馈答案的代码了。我们就以“新闻分类:《美国队长4》被调侃为《关云长4:周仓传》”为例,进行测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
completion = client.chat.completions.create(
    model="deepseek-r1",
    messages=[
        {'role': 'system', 'content': system},
        {'role': 'user', 'content': '新闻分类:《美国队长4》被调侃为《关云长4:周仓传》'},
    ]
)


# 通过reasoning_content字段打印思考过程
print("<think>")
print(completion.choices[0].message.reasoning_content)
print("</think>")


# 通过content字段打印最终答案
print(completion.choices[0].message.content)


输出为:

1
2
3
4
5
6
7
8
9
10
11
12
<think>
首先,我需要分析用户提供的新闻标题:“《美国队长4》被调侃为《关云长4:周仓传》”。标题中提到了《美国队长4》,这是一部著名的超级英雄电影,属于娱乐产业的内容。此外,标题提到该电影被调侃为《关云长4:周仓传》,后者可能涉及对中国传统故事或影视作品的戏仿,这种调侃通常出现在娱乐新闻
中,用于吸引观众注意或制造话题。


接下来,考虑新闻分类的选项:政治、经济、科技、娱乐、体育、教育、健康、国际、国内、社会。这里的关键词是电影名称和调侃,明显与影视娱乐相关,没有涉及其他如经济、政治或科技的元素。因此,最合适的分类应为“娱乐”。
</think>




娱乐

我们就生成了第一条教学数据,我们只需要再将这条教学数据包装成问答对的形式即可。格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
    {
        "conversations": [
            {
                "from": "human",
                "value": "新闻分类:《美国队长4》被调侃为《关云长4:周仓传》"
            },
            {
                "from": "gpt",
                "value": "<think>\n首先,我需要分析用户提供的新闻标题:“《美国队长4》被调侃为《关云长4:周仓传》”。标题中提到了《美国队长4》,这是一部著名的超级英雄电影,属于娱乐产业的内容。此外,标题提到该电影被调侃为《关云长4:周仓传》,后者可能涉及对中国传统故事或影视作品的戏仿,这种调侃通常出现在娱乐新闻中,用于吸引观众注意或制造话题。\n\n接下来,考虑新闻分类的选项:政治、经济、科技、娱乐、体育、教育、健康、国际、国内、社会。这里的关键词是电影名称和调侃,明显与影视娱乐相关,没有涉及其他如经济、政治或科技的元素。因此,最合适的分类应为“娱乐”\n</think>\n\n娱乐"
            }
        ]
    }
]

接下来的事情就是苦力活了,你可以写一个循环执行的程序,有多少条原始数据就执行多少次以上步骤。所以这个过程是很慢的,建议最好多开几个账号并行执行。

微调与测试

由于上节课,我们使用的新闻分类器的数据是带有以上格式的,因此我们可以直接拿过来做教学数据,对 Qwen2.5-7B 进行微调。微调工具还是使用 LLama-Factory,参数与上节课一模一样。

微调之后,我们使用 Chat 功能测试一下,首先测试原版的 Qwen2.5-7B 的效果。

可以看到完全没有思考过程,也没有进行分类。

接着测试微调后的 Qwen2.5-7B。

可以看到有思考过程,也有结果。到此我们就成功蒸馏出了一个自己的 DeepSeek-R1-Distill-Qwen2.5-7B 模型。

总结

今天我们通过新闻分类器的案例,系统梳理了模型蒸馏的全流程。很多同学可能没有想到,在蒸馏过程中编写prompt同样是关键环节。这也印证了我常强调的观点——完成高质量的prompt设计,就意味着完成了50%-70%的模型开发工作。

至此,这一章内容即将告一段落。我们完整探讨了大模型落地的核心路径——从不同部署方案的选择,到微调与蒸馏的技术实践,形成了如下图模型开发的全流程知识体系。

最后,我梳理了一个表格,为大家整理了一下模型部署方案的对比,方便大家学习理解。

这一章的内容是最近的一个热点,但对于很多公司里目前没搞私有化部署的同学来说,可能暂时只能做到了解是怎么回事,但没法实操。不过我相信随着模型蒸馏技术的发展,各细分行业都用上普惠小模型的时代不远了,到时候就是大家在公司内展现能力的时候。

思考题

这节课我们微调 Qwen2.5-7B 模型和上节课微调 DeepSeek-R1-Ditill-Qwen-7B模型,都用了同一份数据集,和同样的微调参数,为什么我们能这么做呢?微调这两个模型的意义分别是什么呢?

欢迎你在留言区展示你的思考结果,我们一起探讨。如果你觉得这节课的内容对你有帮助的话,也欢迎你分享给其他朋友,我们下节课再见!