0基础也能学会的DeepSeek 蒸馏实战

本文来自九天老师的公开课,由赋范空间运营进行整理编辑,如果你有任何建议欢迎评论告知哦~

作为技术人,看到的肯定不止于DeepSeek爆火,而是模型蒸馏。

其实很多业内的技术人甚至觉得,模型蒸馏这部分技术实践,才是整个R1模型技术报告中最具含金量的部分。

深度求索团队以R1模型作为教师模型,将其推理能力通过模型蒸馏的方法,赋予Qwen 1.5B、Qwen 7B、Llama 8B等一众小尺寸模型。

图片

最终模型蒸馏效果非常炸裂,具体蒸馏模型性能如图所示。

图片

经过了DeepSeek R1模型蒸馏,一个1.5B小尺寸的模型甚至能达到GPT4o的推理能力水平。

也就是说仅需4G的显存就可以让你在本地拥有GPT4o的编程能力,而一个32B的模型就能达到o1 mini性能级别。

图片

要知道,传统的高性能模型,往往模型参数量也很大,需要大量的算力才能支撑运行。

比如DeepSeek R1模型,全精度运行至少需要1000G的显存,也就是需要42块4090或者14块A100才能运行,光是硬件成本就高达一百多万。

而R1模型蒸馏技术的诞生,大模型赋能小尺寸模型成为了可能,可以说是真正拉开了全民使用推理模型的新时代。

并且,DeepSeek R1模型的蒸馏过程也非常简单,直接使用R1训练过程中,第三步的80万条精选数据集,对其他小尺寸模型进行SFT有监督微调即可。

图片

可以说,这又是一项过程简单优雅,但实际上效果非常炸裂的技术。

下面正式开始。

同样的,课件、练习用数据、模型权重等练习使用物料已放进大模型技术社区,扫码即可无偿领取。

图片

一、模型蒸馏环境部署

注:本次实验仍然采用Ubuntu操作系统,基本配置如下:

图片

需要注意的是,本次公开课以Qwen 1.5-instruct模型为例进行蒸馏,从而能省略冷启动SFT过程。

并且   由于Qwen系列模型本身性能较强,因此只执行后训练的SFT阶段,省略RL阶段。如此能够更高效的完成 蒸馏过程,但由于并不是从Base模型开始蒸馏,只能一定程度提升模型推理能力。

这个简化的推理流程  仅作为公开课快速入门了解模型蒸馏场景使用。

  • 创建虚拟环境

conda create --name o1 python=3.11
conda init
source ~/.bashrc conda activate R1

图片

  • 创建Jupyter Kerne

conda install jupyterlab conda install ipykernel
python -m ipykernel install --user --name R1 --display-name "Python (R1)"
  • 安装wandb

在大规模模型训练中,我们往往需要监控和分析大量的训练数据,而WandB可以帮助我们实现这一 目标。它提供了以下几个重要的功能:

  • 实时可视化:WandB可以实时展示训练过程中关键指标的变化,如损失函数、学习率、训练时间等。通 过这些可视化数据,我们能够直观地了解模型的训练进展,快速发现训练中的异常或瓶颈。

  • 自动记录与日志管理:WandB会自动记录每次实验的参数、代码、输出结果,确保实验结果的可追溯性。无论是超参数的设置,还是模型的架构调整,  WandB都能够帮助我们完整保留实验记录,方便后期 对比与调优。

  • 支持中断与恢复训练:在长时间的预训练任务中,系统中断或需要暂停是常见的情况。通过WandB的 checkpoint功能,我们可以随时恢复训练,从上次中断的地方继续进行,避免数据和时间的浪费。

  • 多实验对比:当我们尝试不同的模型配置或超参数时, WandB允许我们在多个实验之间轻松进行对比分 析,帮助我们选择最优的模型配置。

  • 团队协作:WandB还支持团队协作,多个成员可以共同查看实验结果,协同调试模型。这对研究和项目 开发中团队的合作非常有帮助。

注册wandb:https://wandb.ai/site

安装wandb:在命令行中输入如下代码安装wandb:

pip install wandb

图片

然后即可登录wandb,在命令行页面输入:

wandb login

并根据提示输入API-KEY:

图片

即可在当前电脑上保存wandb账号信息,之后即可直接在wandb home主页上看到训练过程。

注,登录信息会一直保留在当前服务器上,除非重置系统,否则不用重新登录。  wandb显示信息类似如下:

图片

创建主目录:

cd /root/autodl-tmp
mkdir ./DeepSeek-R1-Distill

下载原始模型: Qwen2.5-1.5B-Instruct

模型魔搭社区官网: https://www.modelscope.cn/models/Qwen/Qwen2.5-1.5B-Instruct/

图片

具体模型下载过程如下:

pip install modelscope

cd ./DeepSeek-R1-Distill
mkdir ./Qwen2.5-1.5B-Instruct
modelscope download --model Qwen/Qwen2.5-1.5B-Instruct --local_dir ./Qwen2.5- 1.5B-Instruct

图片

然后即可在Jupyter中尝试进行调用:

from modelscope import AutoModelForCausalLM, AutoTokenizer
path1 = "/root/autodl-tmp/DeepSeek-R1-Distill/Qwen2.5-1.5B-Instruct" prompt = "请证明根号2是无理数。 "
# 输入模型下载地址
model_name = path1

# 实例化预训练模型
model = AutoModelForCausalLM.from_pretrained( model_name,
torch_dtype="auto",
device_map="auto",
low_cpu_mem_usage=True
)

tokenizer = AutoTokenizer.from_pretrained(model_name)

# 创建消息
# prompt = "你好,好久不见,请介绍下你自己。 "
messages = [
{"role": "system", "content": "你是一名助人为乐的助手。 "},
{"role": "user", "content": prompt} ]
# 分词
text = tokenizer.apply_chat_template( messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)

# 创建回复
generated_ids = model.generate( **model_inputs,
max_new_tokens=512 )
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]

response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

print(response)
  • 下载安装Llama-Factory

在SFT阶段,我们考虑直接使用Llama-Factory进行全量指令微调,因此这里需要提前安装Llama- Factory。

cd /root/autodl-tmp/DeepSeek-R1-Distill
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git

然后安装相关依赖

cd LLaMA-Factory
pip install -e ".[torch,metrics]"

二、模型蒸馏数据集准备

这里我们先介绍可以用于模型蒸馏的数据集基本情况,最终我们将提供一个经过数据清洗后可直接 用于模型蒸馏的数据集。 https://huggingface.co/

图片

1.主流推理数据集介绍

1. NUMINA COT数据集: https://huggingface.co/datasets/AI-MO/NuminaMath-CoT

图片

NuminaMath CoT 数据集是一个包含大约86万个数学问题和解决方案的集合,所有解决方案都采用了

“Chain of Thought”( CoT)推理方式。该数据集广泛涵盖了从中国高中数学练习到美国及国际数学奥林  匹克竞赛问题的各种数学题目。数据主要来源于在线考试试卷的PDF文件和数学讨论论坛,经过多个处理 步骤整理而成。

  • 数据集核心特性:

大规模数学数据集: NuminaMath CoT 包含约860,000个数学问题,覆盖了不同难度和领域的数学 题目。这些题目适合用于训练和评估能够进行逻辑推理和解题过程建模的机器学习模型。

链式思维推理(CoT)格式:每个数学问题的解决方案都被格式化为链式思维(Chain of Thought ,CoT)推理过程。这意味着每个问题的解答不仅仅给出最终答案,而是展示了解题的完 整思路和推理过程,便于模型学习推理的逻辑。

  3. 数据来源

  • aops_forum:来自美国数学奥林匹克论坛的样本(30,201个)。
  • amc_aime:来自美国数学竞赛(AMC)和AIME的样本(4,072个)。
  • cn_k12:来自中国K12教育阶段的数学题目(276,591个)。
  • gsm8k:GSM8K数据集的样本(7,345个)。
  • math:通用数学问题样本(7,478个)。
  • olympiads:来自各类数学奥林匹克竞赛的题目(150,581个)。
  • orca_math :ORCA数学竞赛题目样本(153,334个)。
  • synthetic_amc :合成的AMC样本(62,111个)。
  • synthetic_math:合成的数学问题样本(167,895个)。

  4. 处理流程

  • OCR:从原始PDF文档中提取数学题目。
  • 分割:将数据分为问题-答案对。
  • 翻译:将数据翻译成英文。
  • 重新对齐:调整数据格式以生成CoT推理的格式。
  • 最终答案格式化:整理每个问题的最终答案。

这条数据是一个数学问题及其解答,采用了"Chain of Thought"( CoT,链式思维)格式,逐步展示了解 题过程。它包含了一个数学问题,并通过多个步骤展示了如何推理和求解问题。

  • 单条数据集解释:

1. 问题描述(problem)

Consider the terms of an arithmetic sequence: $-\frac{1}{3}, y+2, 4y, \ldots$. Solve for $y$.

这个问题给出了一个算术数列的前几项: $-\frac{1}{3}$、 $y+2$ 和 $4y$,要求求解 $y$ 的值。

2. 解题思路(solution)

  • 设定等式

    :题目中提到,算术数列的相邻项之间的差值是相等的。根据这个性质,我们可以设 置等式来解这个问题。首先我们有:

(y + 2) - \left(-\frac{1}{3}\right) = 4y - (y + 2)

这表示数列的第二项与第一项之差等于第三项与第二项之差。

  • 简化方程

    :接下来我们简化并求解这个方程:

y + 2 + \frac{1}{3} = 4y - y - 2

这一步通过展开等式的右边和左边,开始化简。

继续简化:

y + \frac{7}{3} = 3y - 2

    再次简化,合并同类项。

    • 求解$y$
    \frac{7}{3} + 2 = 3y - y

    再继续化简,得到:

    \frac{13}{3} = 2y

    最后,解出 $y$:

    y = \frac{13}{6}

    3. 最终答案: 通过以上的推理过程,我们得到了 $y = \frac{13}{6}$ ,这是问题的解答。 结构总结:

    • source:问题的来源或类型,标记为“synthetic_math”,说明这是一个合成的数学问题。
    • problem:数学问题的描述,要求解算术数列中的未知数 $y$。
    • solution :详细的解答过程,通过逐步的推理和简化来求解问题,最后得出答案。
    • messages:消息格式,包含了多轮用户输入和系统输出,模拟了一个互动式解题过程。

    此外这个数据中, messages 是一个包含多条信息的列表,主要由两部分组成:用户( user )输入的消 息和系统(assistant)输出的消息。我们可以从中分辨出每一条消息的来源和内容。

    messages 的构成:

    [
    { "content": "Consider the terms of an arithmetic sequence: $-\\frac{1}{3}, y+2, 4y, \\ldots$. Solve for $y$.", "role": "user" },
    { "content": "For an arithmetic sequence, the difference between consecutive
    terms must be equal. Therefore, we can set up the following equations based on
    the sequence given:\n\\[ (y + 2) - \\left(-\\frac{1}{3}\\right) = 4y - (y+2)
    \\]\n\nSimplify and solve these equations:\n\\[ y + 2 + \\frac{1}{3} = 4y - y - 2 \\]\n\\[ y + \\frac{7}{3} = 3y - 2 \\]\n\\[ \\frac{7}{3} + 2 = 3y - y \\]\n\\[
    \\frac{13}{3} = 2y \\]\n\\[ y = \\frac{13}{6} \\]\n\nThus, the value of $y$ that satisfies the given arithmetic sequence is $\\boxed{\\frac{13}{6}}$", "role":
    "assistant" } ]

    消息解释:

    • 第一条消息(用户消息):

    { "content": "Consider the terms of an arithmetic sequence: $-\\frac{1}{3}, y+2, 4y, \\ldots$. Solve for $y$.", "role": "user" }
    1. 这是用户提出的问题,要求解算术数列中的未知数 $y$。

    2. role: "user" 表明这是用户的输入。

    • 第二条消息(系统回答):

    { "content": "For an arithmetic sequence, the difference between consecutive terms must be equal. Therefore, we can set up the following equations based on the sequence given:\n\\[ (y + 2) - \\left(-\\frac{1}{3}\\right) = 4y -
    (y+2) \\]\n\nSimplify and solve these equations:\n\\[ y + 2 + \\frac{1}{3} = 4y - y - 2 \\]\n\\[ y + \\frac{7}{3} = 3y - 2 \\]\n\\[ \\frac{7}{3} + 2 = 3y - y \\]\n\\[ \\frac{13}{3} = 2y \\]\n\\[ y = \\frac{13}{6} \\]\n\nThus, the value of $y$ that satisfies the given arithmetic sequence is
    $\\boxed{\\frac{13}{6}}$", "role": "assistant" }
    1. 这是系统的回复,展示了如何从问题中推理出解答的步骤,逐步通过方程求解出 $y = \frac{13}{6}$。

    2. role: "assistant" 表明这是系统的输出(即模型的回答)。

    2. APPs:https://huggingface.co/datasets/codeparrot/apps

    图片

    • APPSDataset数据集介绍

    APPS (Automated Programming Problem Solving) 是一个用于编程任务的基准数据集,包含了10,000 个问题,旨在评估语言模型生成代码的能力,特别是从自然语言描述中生成代码的能力。它为基于自然  语言的代码生成、自动编程和相关任务的研究提供了一个标准化的测试平台。

    • 主要特点
      • 编程问题:数据集中的每个问题都包含一个用英语表述的编程问题,并且有一组 Python语言的解决方案。问题涵盖从初学者到竞赛级别的各种难度。
      • 代码生成:该数据集的核心目标是评估语言模型是否能够根据问题描述生成正确的 Python 代 码解决方案。
      • 数据集包含:每个问题除了文本描述外,还包括测试用例、难度级别、问题来源(如 Codeforces 等)和部分 starter 代码。

    • 数据集结构
    from datasets import 
    load_dataset load_dataset("codeparrot/apps")
      • 数据结构:该数据集包含 train 和 test  两个部分,每部分包含5000个样本。

      图片

      字段说明

        • problem_id : 问题ID。
        • question : 问题描述,通常是用英语写的编程问题。
        • solutions: 多个Python解决方案,通常是问题的不同解法。
        • input_output:包含输入输出样本的字典,可能还包括函数名( fn_name )。
        • difficulty: 问题的难度级别,可能包括  introductory(入门)、  interview (面试)和 competition (竞赛)等类别。
        • url: 问题的来源 URL,通常是在线编程平台(如 Codeforces 等)。    
        • starter_code : 可能提供的起始代码,用于帮助编写完整的解决方案。

      使用以下代码加载并处理训练集中的数据:

      from datasets import load_dataset 
      import json
      
      ds = load_dataset("codeparrot/apps", split="train") 
      sample = next(iter(ds))
      # 解析非空的 solutions 和 input_output 字段
      sample["solutions"] = json.loads(sample["solutions"])
      sample["input_output"] = json.loads(sample["input_output"]) 
      print(sample)

      输出示例

      {
      'problem_id': 0,
      'question': 'Polycarp has $n$ different binary words. A word called binary if it contains only characters \'0\' and \'1\'. For example...',
      'solutions': ["for _ in range(int(input())):\n n = int(input())\n mass =
      []\n zo = 0\n oz = 0\n zz = 0\n oo = 0\n...", ...],
      'input_output': {'inputs':
      ['4\n4\n0001\n1000\n0011\n0111\n3\n010\n101\n0\n2\n00000\n00001\n4\n01\n001\n0001 \n00001\n'], 'outputs': ['1\n3 \n-1\n0\n\n2\n1 2 \n']},
      'difficulty': 'interview',
      'url': 'https://codeforces.com/problemset/problem/1259/D',
      'starter_code': '' 
      }
      • 数据筛选

      你可以根据问题的难度筛选数据集。例如,如果你只想加载 competition 难度级别的问题:

      ds = load_dataset("codeparrot/apps", split="train", 
      difficulties=["competition"]) print(next(iter(ds))["question"])

      输出示例

      Codefortia is a small island country located somewhere in the West Pacific. It consists of $n$ settlements connected by
      ...
      For each settlement $p = 1, 2, \dots, n$, can you tell what is the minimum time
      required to travel between the king's residence and the parliament house (located in settlement $p$) after some roads are abandoned?
      ...
      • 数据集统计

      。 问题数量: 10,000个编程问题。

      。 测试用例数量: 131,777个测试用例

      。 问题的平均长度: 约 293.2 字。

      每个问题至少有一个测试用例,除了训练集中的195个样本,每个测试分割的平均测试用例数:  21.2。大部分问题都提供了完整的解决方案,测试集有1235个问题缺少解决方案。

      下面是这个数据集中的一条示例数据:

      • problem_id: 0

      唯一标识符为 0。

      • question:

      图片

      这个问题描述了一个关于二进制词汇的游戏,问题需要通过给定的二进制词汇顺序或反转它们,使 得最终的词汇集合能够符合游戏的规则。

      • solutions:

      图片

      图片

      该代码段为 Python 编写,解决了上述问题。它通过对输入的二进制词汇进行分类(比如根据首尾字符),并通过计算如何反转最少的词汇来满足题目要求。

      输入包括四个测试用例,每个测试用例有一组二进制字符串。输出给出了每个测试用例需要反转的 词汇索引或在无法满足条件时输出 -1。

      • difficulty
        • "interview":表示这个问题属于面试难度,通常适合用来测试候选人在面对编程挑战时的能力。

      • url
        • Codeforces1259/D:问题的来源链接,可以通过这个链接访问该问题的详细信息。

      • starter_code
        • 空字符串 "" ,意味着该问题没有提供任何初始代码,只提供了问题描述和测试用例。

      3. TACO数据集: https://huggingface.co/datasets/BAAI/TACO

      图片

      TACO(Text to Code)是一个用于评估语言模型从自然语言描述生成代码能力的基准数据集。它包含了 26,443个编程问题,配有Python代码解决方案,适用于代码生成、自然语言理解和问题求解等任务。

      • TACO 数据集的主要特点:

        • 问题与解决方案:每个样本包含一个英文编程问题描述、 Python代码解决方案、测试用例

          (输入/输出)以及相关的元数据(如难度、标签和所需技能类型)。

      • 语言:问题描述使用英文,解决方案使用Python
        • 数据集结构 :数据集分为两部分
        • 测试集:包含1,000个样本
      • 元数据每个问题还包含其他信息,如:
        • 标签(例如:数据结构、算法)

        • 所需技能类型(例如:动态规划、贪心算法)

        • 解决问题的时间限制和内存限制

        • 辅助空间和时间复杂度(如果有的话)

        • 难度(EASY、 MEDIUM、 HARD等)

      • 数据集字段:

        • question :问题描述,采用英文写成。
        • solutions: Python解决方案的列表(地面真实答案)。
        • input_output:包含测试用例输入和输出的JSON字符串。
        • difficulty:问题的难度等级(如: EASY、 MEDIUM、 HARD)。
        • raw_tags:问题主题的原始标签(如:数据结构、贪心算法)。
        • tags:注释的算法或技术,描述解决该问题所需的算法。
        • skill_types:解决问题所需的编程技能类型(如:动态规划、贪心算法)。
        • source:问题的来源(如: Codeforces、 CodeChef)。
        • url:问题所在平台的URL。
        • starter_code:问题的起始代码,通常用于提示。
        • time_limit:解决问题的时间限制。
        • memory_limit:解决问题的内存限制。
        • ExpectedTimeComplexity:预期的时间复杂度。
        • ExpectedAuxiliarySpace:预期的辅助空间。

      可以使用以下代码加载数据集:

      from datasets import load_dataset import json
      # 加载训练数据
      ds = load_dataset("BAAI/TACO", split="train") sample = next(iter(ds))
      
      # 解析特征
      sample["solutions"] = json.loads(sample["solutions"])
      sample["input_output"] = json.loads(sample["input_output"]) sample["raw_tags"] = eval(sample["raw_tags"])
      sample["tags"] = eval(sample["tags"])
      sample["skill_types"] = eval(sample["skill_types"]) 
      
      print(sample)

      示例输出:

      {
      "question": "You have a deck of $n$ cards, and you'd like to reorder it to a new one...",
      "solutions": [
      "import heapq\nfrom math import sqrt\n...", "t = int(input())\nfor _ in range(t):\n...",
      "import sys\n\ndef get_ints():\n...", "def solve():\n..."
      ],
      "starter_code": "", "input_output": {
      "inputs": ["4\n4\n1 2 3 4\n5\n1 5 2 4 3\n..."],
      "outputs": ["4 3 2 1\n5 2 4 3 1\n6 1 5 3 4 2\n1\n"] },
      "difficulty": "EASY",
      "raw_tags": ["data structures", "greedy", "math"],
      "tags": ["Data structures", "Mathematics", "Greedy algorithms"],
      "skill_types": ["Data structures", "Greedy algorithms"],
      "url": "https://codeforces.com/problemset/problem/1492/B", "time_limit": "1 second",
      "date": "2021-02-23",
      "memory_limit": "512 megabytes", "Expected Time Complexity": null
      }

      4. long_form_thought_data_5k数据集:

      https://huggingface.co/datasets/RUC-AIBOX/long_form_thought_data_5k

      图片

      这个数据集名为 RUC-AIBOX/long_form_thought_data_5k,它存储了 JSONL(JSONLines) 格式的数据,每一行都是一个包含多个键值对的字典。下面是数据集的主要结构和内容:

      1. question

      • 这是模型所要解答的问题。问题可以是来自不同领域的各种类型,如数学、物理、化学等

      2.combined_text

      • 该字段包含了模型的长篇思维过程和最终解决方案,分为两个部分:

        • thought:模型的长时间思考过程。这部分通常包含模型对问题的分析、推理过程,可 能会涉及到中间步骤、假设、推理的推导等。
        • solution :模型给出的最终解决方案,这部分是针对问题的最终答案。

      在 combined_text 字段中, <|begin_of_thought|> 和 <|end_of_thought|> 用来标记  思维过程的开始和结束,而 "<|begin_of_solution|>" 和 "<|end_of_solution|>" 用来 标记解决方案的开始和结束。

      3. domain

      • 该字段指示问题的领域,包含以下类别:

        • math(数学)
        • physics(物理)
        • chemistry(化学)
        • biology(生物学)
        • code(编程)
        • puzzle(谜题)

      每个问题都会被标记为一个特定的领域,以帮助分类和理解问题的性质。 示例数据

      假设数据集中有这样一条记录:

      {
      "question": "How do you solve this equation?", "combined_text":
      "<|begin_of_thought|>\n\nlong-form
      thought\n\n<|end_of_thought|>\n\n<|begin_of_solution|>solution<|end_of_solution|>
      "
      ,
      "domain": "math" 
      }

      其中:

      • question : "How do you solve this equation?" 这是模型需要解答的数学问题。
      • combined_text:

        • thought: 用 <|begin_of_thought|> 和 <|end_of_thought|> 标记的部分,通常包含模型 对问题的思考过程。例如,模型可能会描述如何将方程式进行变形或如何选择适当的解法。
        • solution: 用 <|begin_of_solution|> 和 <|end_of_solution|> 标记的部分,这里会给出问题的最终解答,可能是方程的解,或者是其他形式的答案。
      • domain

        "math": 这表明问题属于数学领域。

      2.数据清洗过程

      步骤1:数据推理

      使用DeepSeek R1模型推理多个数据集的结果,即输入问题,输出思维链和模型推理结果

      图片

      步骤2:格式化响应

      获取训练数据列表文件后,将它们转换为统一的格式(注意:这一步使用DeepSeekV3进行重写,输出 较长,处理数据大约需要花费20-30元)。

      步骤3:对格式化后的数据进行拒绝采样

      采用DeepSeekV3对比R1模型输出结果和答案之间差距,挑选回答正确的进行进行全量指令微调,回答 错误的内容则再次提示创建思维链,并带入到后续强化学习训练阶段。

      为什么不采用完整的数据集进行全量指令微调?实际上是因为教师模型输出的结果更容易被学习。

      3.数据集下载与准备

      在课件网盘中下载数据集: Distill_data_ 17k-train.arrow

      图片

      然后上传至主目录下的dataset文件夹内:

      图片

      然后还需要在LLama-Factory中注册自定义数据集,找到dataset_info .json:

      图片

      在最后面加上:

      图片

      4.模型蒸馏过程

      • 上传微调脚本

      脚本内容如下:

      图片

      同样可以先在课件网盘中下载:

      图片

      然后上传至exampl/train_full文件夹中即可:

      图片

      • 执行微调

      最后即可使用Llama-Factory full脚本进行模型蒸馏,即进行全量指令微调:

      cd /root/autodl-tmp/DeepSeek-R1-Distill/LLaMA-Factory
      FORCE_TORCHRUN=1 NNODES=1 NODE_RANK=0 MASTER_PORT=29501 llamafactory-cli train examples/train_full/qwen2_full_sft.yaml

      总共约需要运行10个小时左右:

      图片

      最终训练结果保存如下:

      图片

      模型权重也可直接在课件网盘中下载:

      图片

      四、调用测试

      # 测试问题
      prompt = """
      写一个 Bash 脚本,将格式为 '[1,2],[3,4],[5,6]' 的字符串表示的矩阵转置,并以相同格式输出
      """
      • 普通模型

        回答结果如下

      你可以使用以下 Bash 脚本来实现这个功能:
      
      ```bash
      #!/bin/bash
      
      # 定义输入和输出变量
      input="['[1,2]', '[3,4]', '[5,6]']"
      output=$(echo $input | sed 's/[\[]/\[/g' | sed 's/[)]//g')
      • 蒸馏模型

      from modelscope import AutoModelForCausalLM, AutoTokenizer
      # 普通模型
      path1 = "/root/autodl-tmp/DeepSeek-R1-Distill/Qwen2.5-1.5B-Instruct"
      # 输入模型下载地址
      model_name = path1
      
      # 实例化预训练模型
      model = AutoModelForCausalLM.from_pretrained( model_name,
      torch_dtype="auto",
      device_map="auto",
      low_cpu_mem_usage=True
      )
      
      tokenizer = AutoTokenizer.from_pretrained(model_name)
      
      # 创建消息
      # prompt = "你好,好久不见,请介绍下你自己。 "
      messages = [
      {"role": "system", "content": "你是一名助人为乐的助手。 "}, {"role": "user", "content": prompt}
      ]
      
      # 分词
      text = tokenizer.apply_chat_template( messages,
      tokenize=False,
      add_generation_prompt=True
      )
      model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
      
      # 创建回复
      generated_ids = model.generate( **model_inputs,
      max_new_tokens=512 )
      generated_ids = [
      output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
      ]
      
      response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
      
      print(response)

      回复结果如下:

      你可以使用以下 Bash 脚本来实现这个功能:
      
      ```bash
      #!/bin/bash
      
      # 定义输入和输出变量
      input="['[1,2]', '[3,4]', '[5,6]']"
      output=$(echo $input | sed 's/[\[]/\[/g' | sed 's/[)]//g')

      蒸馏模型

      图片

      回答结果如下

      要编写一个 Bash 脚本来处理这样的任务,我们需要按照以下步骤操作:
      
      1. 解析输入字符串,提取出每一行。
      2. 将这些行转换为各自的整数列表。
      3. 对于每个列,计算其元素的平均值或某种其他操作(在这里,我们只是简单地取每个子列表中的元素 并将其转置)。
      4. 将这些新的子列表组合成一个新的二维字符串。
      
      假设输入是 '[1,2],[3,4],[5,6]', 我们需要将其转置,得到 '1 3 5' 和 '2 4 6',然后以空 格分隔,形成最终的字符串。
      ### 解决方案
      
      ```bash
      #!/bin/bash
      
      # 定义函数来解析和转置矩阵
      transpose_matrix() { # 检查输入是否有效
      if [[ $1 =~ ^\[(.*)\]$ ]]; then# 提取矩阵内的字符串
      IFS=','read -r matrix_str <<< "$1"
      
      # 初始化结果变量 
      result=""
      
      # 遍历每一行
      for row in$matrix_str; do# 
      计算当前行的长度
      len=${#row}
      
      # 如果是第一个行,直接添加到结果中 if [ $len -eq 0 ]; then
      continue
      fi
      ### DeepSeek 模型蒸馏实战教程 #### 背景介绍 DeepSeek模型的部署可以通过阿里云PAI Model Gallery实现零代码的一键部署,这种方式极大地简化了模型开发流程并提升了效率[^1]。然而,在某些情况下,为了优化性能或适应特定硬件环境,可能需要对预训练的大规模模型进行知识蒸馏。 #### 知识蒸馏概述 知识蒸馏是一种将大型复杂网络(教师模型)的知识迁移到较小更高效的网络(学生模型)中的技术。这种方法不仅能够保持较高的准确性,还能显著减少计算资源消耗和加速推理过程。对于像DeepSeek这样的大规模预训练语言模型来说,将其压缩成更适合边缘设备或其他受限环境中运行的小型版本是非常有价值的。 #### 实战教程:从DeepSeek-R1到Qwen2的知识蒸馏 ##### 准备工作 - 安装必要的库文件: ```bash pip install transformers datasets torch sentence-transformers ``` ##### 加载教师模型 (DeepSeek-R1) ```python from transformers import AutoModelForSequenceClassification, AutoTokenizer teacher_model_name = "deepseek-r1" tokenizer = AutoTokenizer.from_pretrained(teacher_model_name) teacher_model = AutoModelForSequenceClassification.from_pretrained(teacher_model_name) ``` ##### 配置学生模型架构 (基于Qwen2) 这里假设已经有一个预先定义好的较小型的学生模型结构`qwen2_config.json`以及初始化权重路径。 ```python student_model_path = "./path_to_qwen2/" student_tokenizer = AutoTokenizer.from_pretrained(student_model_path) student_model = AutoModelForSequenceClassification.from_pretrained(student_model_path) ``` ##### 数据准备 使用Hugging Face `datasets`加载一个适合的任务数据集作为训练样本。 ```python from datasets import load_dataset dataset = load_dataset('glue', 'mrpc') # MRPC是一个简单的文本匹配任务的数据集 train_data = dataset['train'] eval_data = dataset['validation'] ``` ##### 训练配置与损失函数设计 引入温度参数T来控制软标签分布平滑度;交叉熵损失用于衡量预测概率分布之间的差异。 ```python import torch.nn.functional as F temperature = 2.0 def distillation_loss(y_pred_student, y_true_teacher, temperature=temperature): soft_targets = F.softmax(y_true_teacher / temperature, dim=-1) student_outputs = F.log_softmax(y_pred_student / temperature, dim=-1) loss_kd = F.kl_div(student_outputs, soft_targets, reduction='batchmean') return loss_kd * (temperature ** 2) optimizer = ... # 自行选择合适的优化器 scheduler = ... # 可选的学习率调度策略 ``` ##### 开始训练循环 结合常规监督学习目标一起最小化总损失。 ```python for epoch in range(num_epochs): for batch in train_loader: inputs = tokenizer(batch["sentence1"], batch["sentence2"], padding=True, truncation=True, return_tensors="pt").to(device) with torch.no_grad(): teacher_logits = teacher_model(**inputs).logits optimizer.zero_grad() outputs = student_model(**inputs) kd_loss = distillation_loss(outputs.logits, teacher_logits.detach()) kd_loss.backward() optimizer.step() scheduler.step() if scheduler is not None else None eval_results = evaluate(eval_dataloader) # 对验证集评估 ``` 以上就是如何利用Python脚本完成从DeepSeek-R1向Qwen2实施知识蒸馏的一个基本框架示例[^2]。
      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值