一 背景
在私有化部署通义大模型后,经常遇到很多场景需要对模型进行训练,比如最简单的需求,你问大模型是谁,希望的是给到的是一个自定义的名称,而不是模型自带的通义千问的默认回复,这里就涉及到对模型进行自我认知的修改。其中训练分为全量训练和轻量微调训练两种方式,区别在于,全量训练在给定LLM模型上冻结一定的参数(或不冻结任何参数)进行训练,一般耗费显存较高,训练周期比较长。而微调方式,主要方案是在模型结构上附着一个额外结构,在训练时冻结原模型并训练额外结构,推理时将额外结构加载起来或合并回原来模型。轻量微调目前的最流行结构是LoRA,该结构理解简单,训练成本较低,在部分任务上可以达到全量微调的效果。
二 微调方案
在这里,我们使用魔搭社区提供的SWIFT来对模型进行微调,SWIFT是魔搭社区官方提供的LLM&AIGC模型微调推理框架。SWIFT支持近200种LLM和MLLM(多模态大模型)的训练、推理、评测和部署。开发者可以直接将SWIFT框架应用到自己的开发和生产环境中,实现模型训练评测到应用的完整链路。
2.1 环境配置
由于微调对GPU算力有要求,其中魔搭社区提供了免费的GPU环境可以测试验证,如下图所示,所以我们选择魔搭社区的GPU环境进行测试,在魔搭社区提供的环境里,已经包含了基本的python,ModelScope Library,SWIFT等环境,我们直接使用即可。
2.2 微调前推理
为了方便快速验证,减少耗时,我们使用了比较小的模型Qwen1.5-0.5B-Chat进行验证。
import os os.environ['CUDA_VISIBLE_DEVICES'] = '0' from swift.llm import ModelType, InferArguments, infer_main infer_args = InferArguments(model_type=ModelType.qwen1half_0_5b_chat) print('测试') infer_main(infer_args)
在魔搭社区运行以上python代码,可以对Qwen1.5-0.5B-Chat在微调前进行验证,验证如下:
2.3 微调
SWIFT提供了ui和命令行的方式进行微调,ui模式截图如下所示,提供了训练和推理的ui可视化页面。
在这里我们使用命令行的方式,微调代码如下,其中我们主要关注以下几个参数
- model_type:表示你选择的模型类型, 可以通过只指定model_type进行微调. 对应的model_id_or_path会使用默认的设置, 从ModelScope进行下载, 并使用默认的缓存路径。在这里我们使用的是qwen1half_0_5b_chat模型
- model_name:如果开启了自我认知数据集的采样(即self_cognition_sample>0), 你需要传入两个值, 分别代表模型的中文名和英文名. 例如: --model_name 小黄 'Xiao Huang'.
- model_author:如果开启了自我认知数据集的采样, 你需要传入两个值, 分别代表作者的中文名和英文名. 例如: --model_author 魔搭 ModelScope.
这里我们主要修改的就是model_name和model_author参数,其他更多详细参数介绍如下:https://github.com/modelscope/swift/blob/main/docs/source/LLM/%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0.md
import os os.environ['CUDA_VISIBLE_DEVICES'] = '0' from swift.llm import DatasetName, ModelType, SftArguments, sft_main sft_args = SftArguments( model_type=ModelType.qwen1half_0_5b_chat, dataset=[DatasetName.ms_bench_mini], train_dataset_sample=1000, logging_steps=5, max_length=2048, learning_rate=5e-5, warmup_ratio=0.4, output_dir='output', lora_target_modules=['ALL'], self_cognition_sample=500, model_name=['小福', 'Xiao 福'], model_author=['小福公司', 'xiaofu test']) output = sft_main(sft_args) best_model_checkpoint = output['best_model_checkpoint'] print(f'best_model_checkpoint: {best_model_checkpoint}')
训练几十分钟后,可以看到输出结果
2.4 微调后推理
在微调后,我们对生成的模型进行推理验证,验证代码如下, 其中best_model_checkpoint需要修改为上次微调后的值,修改后代码如下:
import os os.environ['CUDA_VISIBLE_DEVICES'] = '0' from swift.llm import InferArguments, merge_lora, infer_main best_model_checkpoint = '/mnt/workspace/output/qwen1half-0_5b-chat/v0-20240414-130754/checkpoint-92' infer_args = InferArguments(ckpt_dir=best_model_checkpoint) merge_lora(infer_args, device_map='cpu') result = infer_main(infer_args)
验证效果截图如下,可以看到已经正确修改了模型相关的名称。
2.5 资源消耗对比
通过nvidia-smi我们可以看到微调前后的资源占用对比如下:
微调期间的一次资源消耗截图如下,其中关键信息如下:
Pwr:Usage/Cap: 表示能耗,Usage指的是当前功率,Cap指的是最大额定功率;
Memory-Uasge: 表示显存使用占比;
GPU-Util:表示GPU资源的使用率,可以看到图中已经到了71%。
微调结束后,可以看到两者消耗都已经变成了0,符合预期
三 微调和RAG对比
RAG和微调的选型问题一直是被问的较多的问题之一,两种方法的对比可以查看下表:
如果模型本身对专业知识理解不够,那么使用RAG是不够的,需要进行模型训练,或将模型训练和RAG结合起来使用。
① 微调常用以下场景:
- 风格化:特定的问答范式
- 自我认知:自我认知改变
- 能力增强:模型本身能力不够,对具体行业的数据理解不良
- Agent:支持Agent能力,比如程序编写、API调用等
② RAG常用以下场景:
- 需要根据语料精确回答,比如法律或医疗领域
- 搜索召回场景,比如搜索引擎
- 知识频繁更新,灵活性较强的场景
四 总结
本次案例只是一个大模型微调的简单案例,真实训练一个大模型的场景要比这复杂的多。比如在模型微调完,需要对模型能力进行评测swift eval,评测通过后需要针对微调的模型通过swift export进行量化导出,量化是指将一个浮点型的模型转换为低精度的量化模型,以减少模型的存储空间和计算量。量化导出后在进行部署,通过swift deploy部署,对外提供openApi的服务,应用侧才能最后调用微调后的模型。整体需要经过评测(swift eval),量化导出(swift export),部署(swift deploy)等步骤才算真正完成。