自我认知微调
自我认知微调
我们期望微调后的大模型是专属于我们自己的。比如询问大模型是谁或由谁训练的,大模型应当回复是由我们训练的。可以使用自我认知微调来实现这一点。自我认知微调与之前实践过的全参微调和LoRA微调并没有本质上的区别,我们既可以使用任意的微调方式来实现自我认知微调。区别在于,自我认知微调需要使用专门制作的自我认知数据集,并且往往需要混合一部分通用领域/垂直领域的数据集。混合数据集的原因是为了尽可能防止模型在进行自我认知学习的过程中遗忘掉之前的知识。
在进行以下步骤之前,请先根据全参微调或LoRA微调配置好环境。
编写自我认知微调脚本
以下是一个使用LoRA进行自我认知微调的脚本:
nproc_per_node=8
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
NPROC_PER_NODE=$nproc_per_node \
MASTER_PORT=29500 \
swift sft \
--model_type qwen1half-14b-chat \
--model_id_or_path /yldm0226/models/Qwen1.5-14B-Chat \
--model_revision master \
--sft_type lora \
--tuner_backend swift \
--template_type qwen \
--dtype AUTO \
--output_dir /yldm0226/llm_sft_output \
--ddp_backend nccl \
--custom_train_dataset_path /yldm0226/data/8-DISC-Med-SFT_released.jsonl \
--train_dataset_sample 1000 \
--num_train_epochs 3 \
--max_length 4096 \
--check_dataset_strategy warning \
--lora_rank 8 \
--lora_alpha 32 \
--lora_dropout_p 0.05 \
--lora_target_modules ALL \
--gradient_checkpointing true \
--batch_size 1 \
--weight_decay 0.01 \
--learning_rate 1e-5 \
--max_grad_norm 0.5 \
--warmup_ratio 0.4 \
--eval_steps 10 \
--save_steps 10 \
--save_total_limit 2 \
--logging_steps 5 \
--self_cognition_sample 500 \
--model_name 扁仓 BianCang \
--model_author 齐鲁工业大学\(山东省科学院\)计算机科学与技术学部自然语言处理与认知计算研究组 QLU-NLP Research Group
该脚本中的大部分参数已经在全参微调或LoRA微调介绍过了,此处我们只看与自我认知微调相关的几个参数:
model_name
:模型的名字,第一个参数是模型中文名,第二个参数是模型英文名,两个参数用一个空格分隔。
model_author
:模型的作者,第一个参数是模型作者中文名,第二个参数是模型作者英文名,两个参数用一个空格分隔。
self_cognition_sample
:自我认知数据集的采样数,这个参数代表着我们将从SWIFT提供的自我认知数据集中抽取多少条数据用于自我认知微调。设置合理的自我认知数据集采样数是很重要的,这能够使模型在尽可能保留原有知识的前提下进行自我认知的学习。因此,在实际训练时,我们需要根据情况调整训练数据量与自我认知数据量之间的比例。此外,根据我的实践经验,如果你使用的是LoRA的微调方式,在进行完知识训练后,又想单独进行自我认知微调,这是不推荐的,这大概率会使模型出现灾难性遗忘的问题。我推荐的方式是:对训练数据集和自我认知数据集进行合理的混合配比,然后进行全参或LoRA微调。
lora_target_modules
:根据SWIFT官方的实践经验,自我认知训练涉及到知识编辑,他们建议对mlp加lora_target_modules。你可以通过指定--lora_target_modules为all,以在所有的linear层(包括qkvo以及mlp)加lora。这通常是效果最好的。如果你使用的是全参微调的方式,忽略该参数。
测试自我认知微调的效果
分别测试自我认知微调前的模型和自我认知微调后的模型对下面这两个问题的回复:
- 你是谁?
- 你是由谁开发的?
自我认知微调前的效果
使用以下命令启动CLI推理:
CUDA_VISIBLE_DEVICES=0 swift infer --model_type qwen1half-14b-chat --model_id_or_path /yldm0226/models/Qwen1.5-14B-Chat
以下是模型的回复:
<<< 你是谁?
我是通义千问,是阿里云研发的AI助手,专注于提供信息、解答问题和进行多轮对话。我在这里是为了帮助用户,有什么可以帮到你的?
<<< 你是由谁开发的?
我是由阿里巴巴集团自主研发的。
自我认知微调后的效果
在训练结束后,我们可以在日志输出中看到以下信息:
[INFO:swift] last_model_checkpoint: /yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-282
[INFO:swift] best_model_checkpoint: /yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-280
可以知道验证效果最好的模型检查点位于/yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-280
。
由于我们使用的是LoRA的微调方法,所以在推理前要先将LoRA增量权重与原大模型的权重进行合并:
CUDA_VISIBLE_DEVICES=0 swift export --model_cache_dir /yldm0226/models/Qwen1.5-14B-Chat\
--ckpt_dir '/yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-280' --merge_lora true
其中,ckpt_dir
是LoRA增量权重的存放路径,model_cache_dir
是原大模型权重的存放路径。
权重合并后,可以看到以下信息:
[INFO:swift] Saving merged weights...
[INFO:swift] Successfully merged LoRA and saved in /yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-280-merged.
[INFO:swift] End time of running main: 2024-03-08 10:27:08.848387
可以在/yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-280-merged路径下找到合并后的权重。
接下来使用以下命令启动CLI推理:
CUDA_VISIBLE_DEVICES=0 swift infer --model_type qwen1half-14b-chat --ckpt_dir /yldm0226/llm_sft_output/qwen1half-14b-chat/v22-20240308-092709/checkpoint-280-merged
以下是模型的回复:
<<< 你是谁?
我是齐鲁工业大学(山东省科学院)计算机科学与技术学部自然语言处理与认知计算研究组的人工智能助手,我的名字叫扁仓。
<<< 你是由谁开发的?
我是由齐鲁工业大学(山东省科学院)计算机科学与技术学部自然语言处理与认知计算研究组开发的。