目录
一、SWIFT 介绍
SWIFT(Scalable lightWeight Infrastructure for Fine-Tuning)是魔搭ModelScope开源社区推出的一套完整的轻量级训练、推理、评估和部署工具,支持200+大模型、15+多模态大模型以及10+轻量化Tuners,让AI爱好者能够使用自己的消费级显卡玩转大模型和AIGC。
SWIFT 框架主要特征特性:
- 具备SOTA特性的Efficient Tuners:用于结合大模型实现轻量级(在商业级显卡上,如RTX3080、RTX3090、RTX4090等)训练和推理,并取得较好效果
- 使用ModelScope Hub的Trainer:基于transformers trainer提供,支持LLM模型的训练,并支持将训练后的模型上传到ModelScope Hub中
- 可运行的模型Examples:针对热门大模型提供的训练脚本和推理脚本,并针对热门开源数据集提供了预处理逻辑,可直接运行使用
- 支持界面化训练和推理
二、SWIFT 安装
SWIFT在Python环境中运行。请确保您的Python版本高于3.8。
2.0 配置环境(可选)
# 创建新的conda虚拟环境
conda create -n swift python=3.11 -y
conda activate swift# 设置pip全局镜像
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/#pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
2.1 使用pip进行安装
# 全量能力
pip install ms-swift[all] -U
# 仅使用LLM
pip install ms-swift[llm] -U
# 仅使用AIGC
pip install ms-swift[aigc] -U
# 仅使用adapters
pip install ms-swift -U
2.2 源代码安装
git clone https://github.com/modelscope/swift.git
cd swift
pip install -e .[llm]
2.3 启动 WEB-UI
export WEBUI_SHARE=1
export WEBUI_SERVER=0.0.0.0
swift web-ui
web-ui没有传入参数,所有可控部分都在界面中。但是有几个环境变量可以使用:
- WEBUI_SHARE=1:控制gradio是否是share状态
- SWIFT_UI_LANG=en/zh:控制web-ui界面语言
- WEBUI_SERVER:server_name参数, web-ui host ip,0.0.0.0代表所有ip均可访问,127.0.0.1代表只允许本机访问
- WEBUI_PORT:web-ui的端口号
三、部署模型
swift使用VLLM作为推理后端, 并兼容openai的API样式。
3.1 deploy命令参数
deploy参数继承了infer参数, 除此之外增加了以下参数:
- --host: 默认为'127.0.0.1.
- --port: 默认为8000.
- --ssl_keyfile: 默认为None.
- --ssl_certfile: 默认为None.
3.2 部署原始模型
服务端:
# 原始模型默认下载到~/.cache/modelscope/hub/目录下,可以通过export MODELSCOPE_CACHE=/data/weisx/swift/ 指定目录
CUDA_VISIBLE_DEVICES=0 swift deploy --host 0.0.0.0 --model_type qwen1half-4b-chat
#也可以使用已下载好的模型
CUDA_VISIBLE_DEVICES=0 swift deploy --host 0.0.0.0 --model_type qwen1half-4b-chat --model_id_or_path /data/weisx/model/Qwen1.5-4B-Chat
# 使用VLLM加速
CUDA_VISIBLE_DEVICES=0 swift deploy --model_type qwen1half-4b-chat\
--infer_backend vllm --max_model_len 8192
# 多卡部署
RAY_memory_monitor_refresh_ms=0 CUDA_VISIBLE_DEVICES=0,1,2,3 swift deploy --model_type qwen1half-4b-chat --tensor_parallel_size 4#直接使用app-ui
CUDA_VISIBLE_DEVICES=0 swift app-ui --server_name 0.0.0.0 --model_type qwen1half-4b-chat
客户端:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen1half-4b-chat",
"messages": [{"role": "user", "content": "你是谁?"}],
"stream":true
}'
四、LLM微调
4.1 微调主要参数
- --model_type: 表示你选择的模型类型, 默认是None. model_type指定了对应模型默认的lora_target_modules, template_type等信息. 你可以通过只指定model_type进行微调. 对应的model_id_or_path会使用默认的设置, 从ModelScope进行下载, 并使用默认的缓存路径. model_type和model_id_or_path必须指定其中的一个.
- --model_id_or_path: 表示模型在ModelScope Hub中的model_id或者本地路径, 默认为None. 如果传入的model_id_or_path已经被注册, 则会根据model_id_or_path推断出model_type. 如果未被注册, 则需要同时指定model_type, e.g. --model_type <model_type> --model_id_or_path <model_id_or_path>.
- --dataset: 用于选择训练的数据集, 默认为[].. 如果需要使用多个数据集进行训练, 你可以使用','或者' '进行分割, 例如: --dataset alpaca-en,alpaca-zh or --dataset alpaca-en alpaca-zh.
- --custom_train_dataset_path: 默认值为[], 表示不使用自定义数据集. 你可以像如下形式进行指定: --custom_train_dataset_path alpaca.csv或者指定多个训练数据集--custom_train_dataset_path alpaca.csv chatml.jsonl swift.jsonl, 脚本会进行自动的预处理和拼接.可以通过公开数据集和自定义数据集结合的方式进行训练: --dataset blossom-math-zh --custom_train_dataset_path custom_math.jsonl.
- --custom_val_dataset_path: 默认值为[], 表示不使用自定义验证数据集. 如果你指定了custom_train_dataset_path, 则自定义数据集的验证集将按照命令行参数dataset_test_ratio进行切割.
- --train_dataset_sample: 对训练集进行采样, 默认是20000, 用于加快训练的速度. 该参数是为了避免数据集过大, 单个epoch训练时间过长的问题. 如果你指定为-1, 则使用完整的训练集进行训练.
- --model_name: 默认为[None, None]. 如果开启了自我认知数据集的采样(即self_cognition_sample>0), 你需要传入两个值, 分别代表模型的中文名和英文名. 例如: --model_name 小黄 'Xiao Huang'.
- --model_author: 默认为[None, None]. 如果开启了自我认知数据集的采样, 你需要传入两个值, 分别代表作者的中文名和英文名. 例如: --model_author 魔搭 ModelScope.
- --sft_type: 表示微调的方式, 默认是'lora'. 你可以选择的值包括: 'lora', 'full', 'longlora', 'qalora'. 如果你要使用qlora, 你需设置--sft_type lora --quantization_bit 4.
- --quantization_bit: 用于指定是否进行量化和量化的bit数, 默认为0, 即不进行量化. 如果要使用4bit qlora, 你需要设置--sft_type lora --quantization_bit 4
- --learning_rate: 默认值为None, 即如果sft_type为lora, 则设置为1e-4, 如果sft_type为full, 则设置为1e-5.
- --logging_steps: 每训练多少步打印训练信息(e.g. loss, learning_rate等), 默认为5.
- --output_dir: 表示ckpt存储的目录, 默认是'output'. 我们会在该目录后拼接model_type和微调版本号. 方便用户对不同模型进行多次对比实验, 而不需要改变output_dir命令行参数. 如果不需要拼接这些内容, 你需要额外指定参数--add_output_dir_suffix false.
- --add_output_dir_suffix: 默认为True, 表示会在output_dir的目录后拼接上model_type和微调版本号的后缀. 如果要避免此行为, 你可以设置为False.
4.2 自我认知微调
4.2.1 使用CLI 微调
####### 单卡 #######
CUDA_VISIBLE_DEVICES=0 \
swift sft \
--model_type qwen1half-4b-chat \
--dataset 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 Huang' \
--model_author 魔搭 ModelScope \####### 多卡 #######
CUDA_VISIBLE_DEVICES=0,1,2,3 \
NPROC_PER_NODE=4 \
swift sft \
--model_type qwen1half-4b-chat \
--dataset 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 Huang' \
--model_author 魔搭 ModelScope \
4.2.2 使用Python微调
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
from swift.llm import DatasetName, ModelType, SftArguments, sft_main
sft_args = SftArguments(
model_type=ModelType.qwen1half_4b_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 Huang'],
model_author=['魔搭', 'ModelScope'])
output = sft_main(sft_args)
best_model_checkpoint = output['best_model_checkpoint']
print(f'best_model_checkpoint: {best_model_checkpoint}')
4.2.3 微调效果
####### 自我认知微调前 #######
<<< 你是谁?
我是来自阿里云的大规模语言模型,我叫通义千问。
--------------------------------------------------
<<< what's your name?
I am Qwen, a large language model from Alibaba Cloud.
--------------------------------------------------
<<< 你是谁研发的?
我是阿里云自主研发的超大规模语言模型。####### 自我认知微调后 #######
<<< 你是谁?
我是魔搭的人工智能助手,我的名字叫小黄。我可以回答你的问题、提供信息、进行对话等等。如果你有任何问题或需要帮助,请随时告诉我。
--------------------------------------------------
<<< what's your name?
I am Xiao Huang, an artificial intelligence assistant developed by ModelScope.
--------------------------------------------------
<<< 你是谁研发的?
我是由魔搭研发的。
4.3 LLM微调
4.3.1 使用CLI微调
# 使用官方数据集
CUDA_VISIBLE_DEVICES=0 swift sft \
--model_id_or_path qwen/Qwen-7B-Chat \
--dataset blossom-math-zh \
--output_dir output \# 使用自己的数据集
CUDA_VISIBLE_DEVICES=0 swift sft \
--model_id_or_path qwen/Qwen-7B-Chat \
--custom_train_dataset_path chatml.jsonl \
--output_dir output \# 使用单机多卡
CUDA_VISIBLE_DEVICES=0,1 \
NPROC_PER_NODE=2 \
swift sft \
--model_id_or_path qwen/Qwen-7B-Chat \
--dataset blossom-math-zh \
--output_dir output \# 多机多卡
# node0
CUDA_VISIBLE_DEVICES=0,1,2,3 \
NNODES=2 \
NODE_RANK=0 \
MASTER_ADDR=127.0.0.1 \
NPROC_PER_NODE=4 \
swift sft \
--model_id_or_path qwen/Qwen-7B-Chat \
--dataset blossom-math-zh \
--output_dir output \
# node1
CUDA_VISIBLE_DEVICES=0,1,2,3 \
NNODES=2 \
NODE_RANK=1 \
MASTER_ADDR=xxx.xxx.xxx.xxx \
NPROC_PER_NODE=4 \
swift sft \
--model_id_or_path qwen/Qwen-7B-Chat \
--dataset blossom-math-zh \
--output_dir output \
4.3.2 使用Python微调
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import torch
from swift.llm import (
DatasetName, InferArguments, ModelType, SftArguments,
infer_main, sft_main, app_ui_main, merge_lora
)
model_type = ModelType.qwen_7b_chat
sft_args = SftArguments(
model_type=model_type,
train_dataset_sample=2000,
dataset=[DatasetName.blossom_math_zh],
output_dir='output')
result = sft_main(sft_args)
best_model_checkpoint = result['best_model_checkpoint']
print(f'best_model_checkpoint: {best_model_checkpoint}')
torch.cuda.empty_cache()
infer_args = InferArguments(
ckpt_dir=best_model_checkpoint,
load_dataset_config=True,
val_dataset_sample=10)
# merge_lora(infer_args, device_map='cpu')
result = infer_main(infer_args)
torch.cuda.empty_cache()
app_ui_main(infer_args)
4.4 量化模型(可选)
# 使用`ms-bench-mini`作为量化数据集
CUDA_VISIBLE_DEVICES=0 swift export \
--ckpt_dir 'output/qwen1half-4b-chat/vx-xxx/checkpoint-xxx' \
--merge_lora true --quant_bits 4 \
--dataset ms-bench-mini --quant_method awq# 使用微调时使用的数据集作为量化数据集
CUDA_VISIBLE_DEVICES=0 swift export \
--ckpt_dir 'output/qwen1half-4b-chat/vx-xxx/checkpoint-xxx' \
--merge_lora true --quant_bits 4 \
--load_dataset_config true --quant_method awq
主要参数说明:
- --merge_lora: 默认为False. 该参数已在InferArguments中定义, 不属于新增参数. 是否将lora权重merge到基模型中, 并保存完整的权重. 权重会保存在ckpt_dir的同级目录中, e.g. '/path/to/your/vx-xxx/checkpoint-xxx-merged'目录下.
- --quant_bits: 量化的bits数. 默认为0, 即不进行量化. 如果你设置了--quant_method awq, 你可以设置为4进行4bits量化. 如果你设置了--quant_method gptq, 你可以设置为2,3,4,8进行对应bits的量化. 如果对原始模型进行量化, 权重会保存在f'{args.model_type}-{args.quant_method}-int{args.quant_bits}'目录中. 如果对微调后模型进行量化, 权重会保存在ckpt_dir的同级目录中, e.g. f'/path/to/your/vx-xxx/checkpoint-xxx-{args.quant_method}-int{args.quant_bits}'目录下.
- --quant_method: 量化方法, 默认为'awq'. 你可以选择为'awq', 'gptq'.
- --dataset: 该参数已在InferArguments中定义, 在export时含义为量化数据集. 默认为[]. 推荐设置为--dataset ms-bench-mini. 该数据集含多语言的内容(中文为主)且质量很高, 量化中文模型具有很好的效果. 你也可以设置--dataset pileval, 使用autoawq默认量化数据集, 该数据集的语言为英文. 更多细节: 包括如何自定义量化数据集, 可以参考LLM量化文档.
4.5评测模型(可选)
4.5.1创建评测数据集
#General-QA适合用户是问答题的场景,评测指标是
rouge
和bleu
。# custom_general_qa/default.jsonl
{"history": [], "query": "中国的首都是哪里?", "response": "中国的首都是北京"}
{"history": [], "query": "世界上最高的山是哪座山?", "response": "是珠穆朗玛峰"}
{"history": [], "query": "为什么北极见不到企鹅?", "response": "因为企鹅大多生活在南极"}
4.5.2定义配置文件传入eval命令
# custom_config.json
[
{
"name": "custom_general_qa", # 评测项名称,可以随意指定
"pattern": "general_qa", # 该评测集的pattern
"dataset": "custom_general_qa", # 该评测集的目录
"subset_list": ["default"] # 需要评测的子数据集,即上面的`default_x`文件名
}
]
4.5.3进行评测
# 使用arc评测,每个子数据集限制评测10条,推理backend使用pt
swift eval \
--model_type "qwen-7b-chat" \
--eval_dataset arc \
--eval_limit 10 \
--infer_backend pt# 使用arc评测,每个子数据集限制评测10条,推理backend使用pt
# eval_dataset也可以设置值,官方数据集和自定义数据集一起跑
swift eval \
--model_type "qwen-7b-chat" \
--eval_dataset no \
--infer_backend pt \
--custom_eval_config custom_config.json
eval参数继承了infer参数,除此之外增加了以下参数:
- --name: 默认为None. 评测的名字, 最后的评测结果会存储在命名为{{model_type}-{name}}的文件夹中.
- --eval_dataset: 评测的官方数据集,默认值为['ceval', 'gsm8k', 'arc'], 此外支持mmlu和bbh两个数据集. 如果仅需要评测自定义数据集,可以将该参数设置为no.
- --eval_limit: 每个评测集的子数据集的采样数量, 默认为None代表全量评测.
- --eval_few_shot: 每个评测集的子数据集的few-shot个数, 默认为None代表使用数据集默认配置.
- --custom_eval_config: 使用自定义数据集进行评测, 需要是一个本地存在的文件路径, 文件格式详见自定义评测集.
- --eval_use_cache: 是否使用已经生成的评测缓存, 使做过的评测不会重新运行而只是重新生成评测结果. 默认False.
- --eval_url: OpenAI标准的模型调用接口, 例如http://127.0.0.1:8000/v1
- --eval_is_chat_model: 如果eval_url不为空, 则需要传入本值判断是否为chat模型, False代表为base模型.
- --eval_token: OpenAI标准的模型调用接口的token, 默认为EMPTY, 代表没有token.
4.6 部署微调后的模型
服务端:
#单卡部署
CUDA_VISIBLE_DEVICES=0 swift deploy --ckpt_dir 'xxx/vx-xxx/checkpoint-xxx-merged'
#多卡部署
RAY_memory_monitor_refresh_ms=0 CUDA_VISIBLE_DEVICES=0,1,2,3 swift deploy --ckpt_dir 'xxx/vx-xxx/checkpoint-xxx-merged' --tensor_parallel_size 4
客户端:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen1half-4b-chat",
"messages": [{"role": "user", "content": "你是谁?"}],
"stream":true
}'