【大模型】LLaMA-Factory的环境配置、微调模型与测试
前言
【一些闲扯】
时常和朋友闲聊,时代发展这么快,在时代的洪流下,我们个人能抓住些什么呢。我问了大模型,文心一言是这样回答的:
- 在快速发展的时代背景下,个人确实面临着诸多挑战,但同时也充满了机遇。尽管时代洪流滚滚向前,我们依然可以抓住一些关键要素,以实现个人成长和价值提升…(一些建议)… 记住,每个人的成长路径都是独一无二的,找到适合自己的方式并坚持下去才是最重要的。
哈哈跟没回答一样,毕竟是一个开放命题,还是要落到个人的行动上的。
先动起来吧,我的大模型的记录终于开始了。接下来将会做的事情:
- 将transfomer、GPT系列、Bert等论文进行下论文阅读、解析记录。
- 大模型相关的框架、库的使用,工程相关的知识体系。
- 高star的开源工程的环境配置与运行。
自主了解和记录会按照上面的顺序。而实际执行时受项目需要,顺序会换一换。
【日常常用大模型】
另外,自己日常工作中,常用的大模型有通义千问、文心一言、Kimi。以下的纯个人使用感受:
- 通义千问:在提问技术问题时,会直接对问题展开解释和解决办法、或者实现对应的代码片段,其变量命名很精准。在代码类问题上使用感受较好。个人最常用。
- 文心一言:提问技术问题时,总觉得会有前摇,当然回答得核心问题也是OK的。对非技术的问题的回答,用词更丰富些。
- Kimi:最大的好处是会联网搜索当下新的技术知识。另外对文档内容的提取能力很优秀。
个人在界面上比较倾向通义千问。
在实际使用上,需要编写文档和生动的文词,使用文心一言;问代码工程类问题,选择通义千问;当通义千问回答不出来时候,就找Kimi了。当然无论哪个模型回答的代码或文本,是要抱有怀疑值,是要阅读和验证的,因为有时大模型真的会一本正经的乱说。
【大模型问答示例】
- 文心一言
- 通义千问
- Kimi
OK,前面讲了一堆,接下来进入正题:大模型的微调工程-——LLaMA-Factory。
1 工程介绍
- 作者: LLaMa Factory 的团队负责人是郑耀威,北京航空航天大学的博士生。
- 论文链接:http://arxiv.org/pdf/2403.13372
- github链接:https://github.com/hiyouga/LLaMA-Factory
- 具体功能:LLaMA-Factory是一个开源的大型语言模型(LLM)微调框架,旨在帮助开发者高效地微调和部署大型语言模型。
- 项目结构:LLaMA-Factory 的项目结构通常包括以下几个部分:
- 模型库:包含支持的预训练模型。
微调方法:包含不同的微调技术实现。
数据集:提供或支持多种数据集,用于微调。
训练和评估:提供训练和评估模型的脚本和工具。
推理接口:提供模型推理的接口和工具。
2 环境配置
2.1 硬件与环境
- 显卡型号:建议不低于3090,显存尽量24G+。这样可以训练比较主流的入门级别大模型 7B左右的版本。
- CUDA版本,推荐使用12.2。查看自己的设备中的cuda版本的命令
nvidia-smi
2.2 运行环境配置
- 终端键入如下命令
## 创建虚拟环境 conda create -n llama_factory python=3.11 -c conda-forge ## 激活虚拟环境 conda activate llama_factory ## 环境安装 pip install -e ".[torch,metrics]" ## 这里我从modelscope下载模型,所以要进行库的安装 pip install modelscope -U
- 环境安装结束后,查看版本信息
llamafactory-cli version
- 查看gpu是否能被调用起来
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"
上面的内容都正确运行结束后,说明环境配置已经完成。
3 LLaMa Factory 微调模型(使用web方式)
3.1 界面开启
- 设置使用modelscope下载模型,终端键入内容如下。也可在工程中 .env.local 文件中设置。
export USE_MODELSCOPE_HUB=1
- 下载的大模型,一般都是几个G左右,所以下载的路径尽量不要放在系统盘,优先选择挂载的数据盘。所以就需要设置下对应的路径,终端键入内容如下,后面的路径根据自己实际情况更换。
export MODELSCOPE_CACHE="/opt/ai-platform/lldataset/240/modelscope/" export MODELSCOPE_MODULES_CACHE="/opt/ai-platform/lldataset/240/modelscope/modelscope_modules"
- 开启web界面
llamafactory-cli webui
方便起见,上面的命令可以写在一个bash文件中。具体的,在根目录创建个
run_with_webui.sh
,里面的内容为如下。当然也可以将其配置的系统环境变量当中,这里使用临时方式。export USE_MODELSCOPE_HUB=1 # 使用 modelscope 下载模型 export MODELSCOPE_CACHE="/opt/ai-platform/lldataset/240/modelscope/" export MODELSCOPE_MODULES_CACHE="/opt/ai-platform/lldataset/240/modelscope/modelscope_modules" llamafactory-cli webui
运行结束后,在浏览器的
http://localhost:7860/
中可以打开大模型训练界面。WebUI 主要分为四个界面:训练、评估与预测、对话、导出。
3.2 模型微调训练
在开始训练模型之前,需要指定的参数有:
- 模型名称及路径
- 微调方法
- 训练数据集
- 学习率、训练轮数等训练参数
- 微调参数等其他参数
- 输出目录及配置路径
尝试如下图,设置好后开启训练。
若需要量化,在【量化等级】中,选择对应的数值即可,量化会带来精度损失,但显存占用会降低。
第一次调用会耗费些时间,下载模型和数据(可在终端的打印的信息查看进度)。
运行时可能会报错:
- 若存在库缺失,pip安装即可;
- 可能报错,说modelscope和datasets的库不兼容,安装兼容版本即可。个人使用可运行版本如下
训练结束后界面显示如下:
3.3 微调模型的测试效果
为了对比基座模型和微调模型的差异,在【Chat】界面,分别调用基座模型和微调模型的进行问答,问题来源于训练时使用的数据集。训练时的数据内容如下:
- 使用基座模型进行问答:
加载模型后,在界面的最下端输入要问的问题。基座模型回答如下
- 微调模型进行问答:
注意:要先进行【卸载模型】,否则显存没有释放,剩余显存可能无法加载新的模型。
微调模型回答如下,发现回答内容与数据集中的答案并不相符。
分析原因,应该是初始学习率偏小,然后学习的轮次也偏少,导致微调模型欠拟合。
- 接下来就是根据经验调参,可以再尝试下,学习率修改为5e-4,epoch为6。
3.4 微调模型的合并与导出
- 先在【Chat】将要导出的微调模型 进行加载
- 先在【Export】设置好导出路径,开始导出
4 LLaMa Factory 微调模型(源码方式)
4.1 运行命令
依然选择modelscope来下载模型。工程根目录创建
run_with_command.sh
。里面的内容编辑如下:export USE_MODELSCOPE_HUB=1 # 使用 modelscope 下载模型 export MODELSCOPE_CACHE="/opt/ai-platform/lldataset/240/modelscope/" export MODELSCOPE_MODULES_CACHE="/opt/ai-platform/lldataset/240/modelscope/modelscope_modules" llamafactory-cli train examples/train_lora/llama3_lora_sft.yaml
运行后,若模型能正常下载则继续训。但模型下载可能存在异常。
4.2 模型的下载问题
我这里报错,基座模型路径不存在。
于是,使用直接去 modelscope上获取对应模型下载命令。方法如下:
登录网址:https://www.modelscope.cn/my/overview
搜索所需模型:
选择使用
modelscope download --model ***
命令进行下载。想要将模型下载到指定路径,则跟一个参数即可,最终命令如下modelscope download --model LLM-Research/Meta-Llama-3-8B-Instruct \ --local_dir /opt/ai-platform/lldataset/240/modelscope/hub/meta-llama/Meta-Llama-3-8B-Instruct
然后等下载结束即可
【配置文件的修改】
对应的要进行配置文件的修改。训练时调用的是examples/train_lora/llama3_lora_sft.yaml
,文件内需要修改个配置model_name_or_path
为上一步下载的模型路径;另外这里修改了训练的数据集为中文的数据集。### model # 指定了要使用的预训练模型名字或路径。这里使用的是 meta-llama/Meta-Llama-3-8B-Instruct,这是一个经过指令调优的 8B 参数的 LLaMA 模型。 # model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct model_name_or_path: /opt/ai-platform/lldataset/240/modelscope/hub/meta-llama/Meta-Llama-3-8B-Instruct ### method stage: sft # 指定了微调的阶段,这里是 sft(Supervised Fine-Tuning),表示监督微调。 do_train: true # 指定了是否进行训练。 finetuning_type: lora # 指定了微调的类型,这里是 lora。 lora_target: all # 指定了要进行 lora 微调的目标,这里是 all,表示对所有层进行微调。 ### dataset # dataset: identity,alpaca_en_demo # 指定了要使用的数据集,这里是 identity 和 alpaca_en_demo。 dataset: alpaca_zh_demo # 使用中文的一个数据集,。 template: llama3 # 指定了要使用的模板,这里是 llama3。 cutoff_len: 2048 # 指定了截断长度,这里是 2048。 max_samples: 1000 # 指定了最大样本数,这里是 1000。 overwrite_cache: true # 指定了是否覆盖缓存。 preprocessing_num_workers: 16 # 指定了预处理时的工作线程数,这里是 16。 ### output output_dir: saves/llama3-8b/lora/sft # 指定了输出目录,这里是 saves/llama3-8b/lora/sft。 logging_steps: 10 # 指定了日志输出的步数,这里是 10。 save_steps: 500 # 指定了保存模型的步数,这里是 500。 plot_loss: true # 指定了是否绘制损失曲线。 overwrite_output_dir: true # 指定了是否覆盖输出目录。 ### train per_device_train_batch_size: 1 # 指定了训练时每个设备的批量大小,这里是 1。 gradient_accumulation_steps: 8 # 指定了梯度累积的步数,这里是 8。 learning_rate: 1.0e-4 # 指定了学习率,这里是 1.0e-4。 num_train_epochs: 3.0 # 指定了训练的总轮数,这里是 3.0。 lr_scheduler_type: cosine # 指定了学习率调度器的类型,这里是 cosine。 warmup_ratio: 0.1 # 指定了预热比例,这里是 0.1。 bf16: true # 指定了是否使用 bf16 精度。 ddp_timeout: 180000000 # 指定了 ddp 超时时间,这里是 180000000。 ### eval val_size: 0.1 # 指定了验证集的大小,这里是 0.1。 per_device_eval_batch_size: 1 # 指定了验证时每个设备的批量大小,这里是 1。 eval_strategy: steps # 指定了评估策略,这里是 steps。 eval_steps: 500 # 指定了评估的步数,这里是 500。
完成以上操作,运行
run_with_command.sh
后,可正常开启训练。训练结束后,如下图:
4.3 微调模型的对话测试
run_with_command.sh
文件修改内容如下:export USE_MODELSCOPE_HUB=1 # 使用 modelscope 下载模型 export MODELSCOPE_CACHE="/opt/ai-platform/lldataset/240/modelscope/" export MODELSCOPE_MODULES_CACHE="/opt/ai-platform/lldataset/240/modelscope/modelscope_modules" # llamafactory-cli train examples/train_lora/llama3_lora_sft.yaml llamafactory-cli chat examples/inference/llama3_lora_sft.yaml
- 打开
examples/inference/llama3_lora_sft.yaml
文件,同样的需要修改基座模型路径。
若使用基座模型开启对话,修改后如下:若使用微调模型开启对话,修改后如下:# model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct model_name_or_path: /opt/ai-platform/lldataset/240/modelscope/hub/meta-llama/Meta-Llama-3-8B-Instruct template: llama3
# model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct model_name_or_path: /opt/ai-platform/lldataset/240/modelscope/hub/meta-llama/Meta-Llama-3-8B-Instruct adapter_name_or_path: saves/llama3-8b/lora/sft template: llama3 finetuning_type: lora
- 终端键入
sh run_with_command.sh
。就可以开启和大模型的对话了
4.4 LLaMa Factory 微调模型的合并
上面的两种方式,调用微调模型时,都需要同时加载基座模型。在实际使用时,希望仅使用一个大模型即可,所以这里有个合并的操作。
run_with_command.sh
文件修改内容如下:export USE_MODELSCOPE_HUB=1 # 使用 modelscope 下载模型 export MODELSCOPE_CACHE="/opt/ai-platform/lldataset/240/modelscope/" export MODELSCOPE_MODULES_CACHE="/opt/ai-platform/lldataset/240/modelscope/modelscope_modules" # llamafactory-cli train examples/train_lora/llama3_lora_sft.yaml # llamafactory-cli chat examples/inference/llama3_lora_sft.yaml llamafactory-cli export examples/merge_lora/llama3_lora_sft.yaml
打开
examples/merge_lora/llama3_lora_sft.yaml
文件,同样的需要修改基座模型路径。
注意事项:不要在合并 LoRA 适配器时使用量化模型或设置量化位数。这可能会导致合并失败或模型性能下降。### model # model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct model_name_or_path: /opt/ai-platform/lldataset/240/modelscope/hub/meta-llama/Meta-Llama-3-8B-Instruct adapter_name_or_path: saves/llama3-8b/lora/sft template: llama3 finetuning_type: lora ### export export_dir: models/llama3_lora_sft export_size: 2 export_device: cpu ## 导出时使用的设备 export_legacy_format: false
终端键入
sh run_with_command.sh
。成功运行后,在保存路径下生成合并模型。
5 将微调模型仿 OpenAI 兼容接口
5.1 服务的启动
- 打开
examples/inference/llama3_vllm.yaml
,文件内修改个model_name_or_path
为微调模型的导出路径。model_name_or_path: models/llama3_lora_sft template: llama3 infer_backend: vllm vllm_enforce_eager: true
- 终端键入命令如下
正常的话,服务应可以正确开启。终端界面如下图:API_PORT=8000 llamafactory-cli api examples/inference/llama3_vllm.yaml
- 可能存在报错
ValueError: Bfloat16 is only supported on GPUs with compute capability of at least 8.0. Your Tesla V100-SXM2-32GB GPU has compute capability 7.0. You can use float16 instead by explicitly setting the`dtype` flag in CLI, for example: --dtype=half.
具体原因:GPU 不支持 bfloat16 数据类型。具体的,Tesla V100-SXM2-32GB GPU 的计算能力为 7.0,而 bfloat16 需要至少 8.0 的计算能力。
解决方案:float16 数据类型代替 bfloat16。
具体操作:尝试在yaml文件配置,以及终端命令加上对应的参数,均无法正确运行。那就最简单粗暴的方式,在源码中强行设置dtype。
在文件src/llamafactory/chat/vllm_engine.py
中搜索和添加内容如下修改后即可正常运行。## 添加 engine_args['dtype'] = "float16" ## 搜索 self.model = AsyncLLMEngine.from_engine_args(AsyncEngineArgs(**engine_args))
5.2 命令行测试
【服务器上发送请求】
- 服务器上另起一个终端,键入如下命令
若正常运行,打印如下:curl -X POST http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer x" \ -d '{ "model": "llama3_lora_sft", "messages": [ { "role": "user", "content": "1+1 等于几?" } ], "max_tokens": 4096 }'
【本地发送请求】
- 若想在本地发送请求,则需把命令中的ip切换成服务器的。
- 但我这里报错无法连接服务。
要解决从本地机器访问远程服务器上的服务的问题,可以使用 SSH 隧道(也称为端口转发),从而绕过防火墙和网络限制。SSH 隧道可以将本地机器上的一个端口转发到远程服务器上的一个端口,从而实现从本地机器访问远程服务。
具体操作如下:
- 1 在本地终端运行命令
【-L 8000:127.0.0.1:8000】 这部分指定了端口转发的配置。ssh -L 8000:127.0.0.1:8000 LL@10.91.208.210
【8000】本地机器上的端口。
【127.0.0.1:8000】 远程服务器上的目标地址和端口。
【LL@10.91.208.210】 远程服务器的登录信息。- 2 输入密码
执行上述命令后,系统会提示你输入远程服务器的密码。输入密码后,SSH 隧道就会建立。- 3 在本地测试
现在,你可以通过本地的 8000 端口访问远程服务器上的服务:可看到服务的相应如下。注意:要保持 SSH 隧道连接状态。如果连接断开,需要重新运行上述命令来重新建立隧道。.curl -X POST http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer x" \ -d '{ "model": "llama3_lora_sft", "messages": [ { "role": "user", "content": "1+1 等于几?" } ], "max_tokens": 4096 }'
5.3 可视化测试
下载安装NextChat的release版本的windows 版本。下载后傻瓜式安装。https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/releases
先写到这吧,后续待补充。