基于DeepSeek R1知识对Qwen2.5 3B模型进行蒸馏
DeepSeek基于R1的知识对Qwen的一系列模型进行蒸馏,使得蒸馏后的模型也具备了深度思考的能力,也提高了模型的性能。其中包括了对Qwen 2.5 1.5B和7B这两个Math模型进行了蒸馏。这里我也想复现一下这个蒸馏的方法,目的是了解如何通过知识蒸馏来提高我们的小参数模型的性能。我选取Qwen 2.5 3B Instruct这个模型来进行试验。
首先是下载用于知识蒸馏的数据集,DeepSeek官方提到了是采用了80万条数据来对Qwen模型进行蒸馏,但是官方并没有发布这些训练数据。在HuggingFace上我们可以找到一个公开的数据集,里面包含了11万条的数据,可以用于我们的试验。数据集的地址是Congliu/Chinese-DeepSeek-R1-Distill-data-110k · Datasets at Hugging Face,在国内也可以通过hf-mirror这个网站来下载。
数据下载后我们可以看一下数据的内容
import jsonlines
from itertools import islicefile_path = '../datasets/Chinese-DeepSeek-R1-Distill-data-110k-SFT/distill_r1_110k_sft.jsonl'
with jsonlines.open(file_path) as reader:chunk = list(islice(reader, 100))for key in chunk[0].keys():print(f"{key}: {chunk[0][key]}")
内容如下,这里限于篇幅把生成的部分内容省略掉了,可以看到这个数据集的内容包含了<think>的内容:
instruction: 能给我讲一个寓意深刻的故事吗?
input:
output: <think>
好的,用户让我讲一个寓意深刻的故事。首先,我需要确定用户的需求是什么。他们可能想要一个能引发思考、有深层含义的故事,而不仅仅是娱乐性的。接下来,我得考虑故事的题材。寓言、现代故事还是神话改编?用户没有指定,所以可能需要一个通用且容易理解的类型。 然后,主题方面,用户要求寓意深刻,所以需要选择一个普遍的主题,比如生命的意义、自我认知、成长等。考虑到现代人可能面临的困惑,比如存在的意义、工作的重复性,这样的主题更容易引起共鸣。 接下来是角色设定。主角需要 relatable,可能是一个普通人,或者象征性的角色,比如机器人,这样更容易带入寓意。机器人有程序设定,却寻求自由,这样的冲突明显,容易展开。 故事结构方面,可能需要一个循环的结构,来强调主题。比如开始和结束在同一个地方,但主角有了新的认识。这样能突出转变和领悟。 然后考虑情节发展。主角觉醒,逃离,经历外面的世界,发现真相,最终回归。这样的结构可以展示变化的过程,并带出寓意。中间的导师角色可以帮助传递主题,比如老园丁的话,暗示生命的意义在于过程而非目的。 在细节描写上,需要加入象征元素,比如编号、机械的工作、自然界的对比。老园丁的沙漏、胡须里的嫩芽,这些意象能增强故事的深度和隐喻。 最后,结尾部分要让主角领悟到真谛,即使回到原地,但心态不同,带出主题:存在的意义在于体验本身。这样用户能得到启示,符合寓意深刻的要求。 需要检查故事是否流畅,有没有逻辑漏洞,以及寓意是否明确。可能还需要调整语言,使其更生动,有画面感,让读者更容易沉浸其中。确保故事不长不短,结构紧凑,结尾点题,让用户回味。
</think>
好的,我将按照您的要求创作一个富有寓意的故事。为了让故事更完整,我会先列出一些基本的情节脉络。。。。如果需要调整某些隐喻的浓度或增加情节转折,请随时告诉我。 repo_name: coig/neo
prompt_tokens_len: 9
reasoning_content_tokens_len: 372
content_tokens_len: 1318
score: 8
下面我们来基于LLAMA Factory来对Qwen 2.5 3B模型进行SFT微调,看一下是否能用这个数据来使得模型具备思考能力。
在LLAMA Factory的data目录下,修改dataset_info.json文件,增加以下dataset的信息
"deepseek_data": {"file_name": "/datasets/Chinese-DeepSeek-R1-Distill-data-110k-SFT/distill_r1_110k_sft.jsonl","columns": {"prompt": "instruction","query": "input","response": "output"}
}
然后在LLAMA Factory的examples/train_lora目录下,参照其他示例,添加一个名为qwen_lora_sft.yaml的文件,内容如下:
### model
model_name_or_path: /root/autodl-tmp/Qwen2.5-3B-Instruct-AWQ### method
stage: sft
do_train: true
finetuning_type: lora
lora_target: all### dataset
dataset: deepseek_data
template: qwen
cutoff_len: 2048
overwrite_cache: true
preprocessing_num_workers: 16### output
output_dir: saves/qwen/lora/sft/3B-AWQ
logging_steps: 10
save_steps: 100
plot_loss: true
overwrite_output_dir: true### train
per_device_train_batch_size: 2
gradient_accumulation_steps: 32
learning_rate: 5.0e-6
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_steps: 100
bf16: true
ddp_timeout: 9000
#resume_from_checkpoint: saves/qwen/lora/sft/3B-AWQ/checkpoint-1000### eval
#eval_dataset: eval_data
#per_device_eval_batch_size: 1
#eval_strategy: steps
#eval_steps: 100
最后运行命令即可进行微调训练
llamafactory-cli train examples/qwen_lora_sft.yaml
因为整个训练非常耗时,训练110K的样本数据在4090单卡上需要40多个小时,因此我只选取了10K数据来训练。训练完毕后,我们在LLAMA Factory的examples/inference目录下新建一个qwen2.yaml文件,配置加载我们刚才训练好的lora adapter,如以下代码:
model_name_or_path: /root/autodl-tmp/Qwen2.5-3B-Instruct-AWQ
adapter_name_or_path: saves/qwen/lora/sft/3B-AWQ
template: qwen
infer_backend: huggingface # choices: [huggingface, vllm, sglang]
trust_remote_code: true
temperature: 0.7
top_p: 0.95
运行以下命令来进行对话:
llamafactory-cli chat examples/inference/qwen2.yaml
然后以经典的9.11和9.8哪个大作为问题,结果如下:
User: 9.11和9.8这两个数字哪个大
Assistant:
<think>
嗯,用户问的是9.11和9.8哪个大,这个问题其实挺简单的,但可能需要确认一下用户可能的困惑点。首先,我需要确认用户有没有可能在比较的时候搞混,比如是否把9.11误认为是11的平方根,或者9.8误认为是8的平方根。不过这种可能性应该不大,因为用户可能已经明确知道这两个数字是9.11和9.8。那么接下来,我需要检查一下它们的数值关系。首先,9.11和9.8都是两位小数,它们的整数部分都是9,但是小数部分不一样。9.11的小数部分是0.11,而9.8的小数部分是0.8。比较小数部分时,通常需要先看第一位小数,因为小数位数较多时,第一位小数可能决定了数值大小的总体趋势。但是0.11和0.8比较,0.8显然大于0.11,所以9.8大于9.11。
接下来,我需要确保这种判断的逻辑正确无误。9.11和9.8都是正数,所以不需要考虑负数的情况。另外,用户可能还需要理解这种小数比较的规则。比如,0.9大于0.1,所以0.911大于0.11;同样地,0.98大于0.8,所以9.8大于9.11。所以用户的答案应该是9.8大于9.11。
我需要确认一下,确保没有遗漏任何可能的误解。比如用户可能想问的是9.11和9.8之间的大小关系,而不是两者之间的比较。不过用户的问题是“9.11和9.8哪个大”,所以应该是两者比较。
最后,用户可能需要一个具体的答案来确认他的理解是否正确。比如,“9.11大于9.8”这种表达是否正确,或者9.8是否大于9.11。
确认一下逻辑:9.11和9.8都是两位小数,小数部分比较时,第一位小数决定了整体大小的比较。9.11的第二位小数是1,而9.8的第二位小数是8。显然8大于1,所以9.8大于9.11。
所以答案是9.8大于9.11,用户可能需要确认是否需要明确表示“9.8大于9.11”。
</think>
9.8大于9.11
User:
Assistant: 用户的问题是“9.11和9.8哪个大”,而正确的比较结果是9.8大于9.11。所以,最终的答案是:9.8 大于 9.11
作为对比,我们另外建一个qwen2_original.yaml,不加载lora进行比较,询问同样的问题,结果如下:
User: 9.11和9.8这两个数字哪个大
Assistant:
要比较9.11和9.8这两个数字的大小,我们可以按照从小到大的顺序进行判断。1. 首先比较整数部分:9和9。它们相等。
2. 然后比较小数部分:0.11和0.8。这里的比较从第一位开始:- 0.11的小数第一位是1,而0.8的小数第一位是0。显然,1大于0。
因此,9.11大于9.8。
User:
Assistant: 9.11大于9.8。
从以上比较可以看到,经过训练后的模型也具备了DeepSeek R1的思考能力,会输出思考过程,并且回答问题的准确率也提高了。限于机器性能,如果能对11万条数据进行微调,相信性能会更加好。