使用Arena進(jìn)行模型微調(diào)和模型管理
本文以大語(yǔ)言模型Qwen-7B-Chat為例,并結(jié)合Arena工具,演示如何在提交模型微調(diào)作業(yè)的同時(shí),對(duì)模型微調(diào)作業(yè)所產(chǎn)生的模型進(jìn)行管理。
前提條件
已創(chuàng)建至少包含一個(gè)GPU節(jié)點(diǎn)的ACK集群Pro版,且集群版本不低于1.20。具體操作,請(qǐng)參見(jiàn)創(chuàng)建ACK Pro版集群。
本文所使用的GPU實(shí)例類(lèi)型為ecs.gn7i-c8g1.2xlarge。關(guān)于GPU實(shí)例規(guī)格的詳細(xì)信息,請(qǐng)參見(jiàn)實(shí)例規(guī)格族。
已在ACK集群中部署MLflow模型倉(cāng)庫(kù)。具體操作,請(qǐng)參見(jiàn)配置MLflow模型倉(cāng)庫(kù)。
已安裝最新版本Arena客戶(hù)端。具體操作,請(qǐng)參見(jiàn)配置Arena客戶(hù)端。
背景信息
關(guān)于大模型Qwen-7B-Chat的詳細(xì)信息,請(qǐng)參見(jiàn)Qwen官方代碼倉(cāng)庫(kù)。由于該倉(cāng)庫(kù)無(wú)法直接運(yùn)行微調(diào)后的模型,因此本文對(duì)其進(jìn)行了少量修改并重新構(gòu)建了容器鏡像,鏡像地址為kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/qwen:cu117
。
步驟一:準(zhǔn)備模型數(shù)據(jù)
創(chuàng)建一個(gè)存儲(chǔ)卷用于準(zhǔn)備模型數(shù)據(jù),本文將以NAS存儲(chǔ)卷為例說(shuō)明如何準(zhǔn)備模型數(shù)據(jù),所使用的存儲(chǔ)卷名稱(chēng)為
nas-pvc
。您可以按需選擇使用NAS存儲(chǔ)卷或OSS存儲(chǔ)卷準(zhǔn)備模型數(shù)據(jù)。具體操作,請(qǐng)參見(jiàn)使用NAS靜態(tài)存儲(chǔ)卷或使用OSS靜態(tài)存儲(chǔ)卷。
將NAS存儲(chǔ)卷對(duì)應(yīng)的NAS文件系統(tǒng)掛載至ECS實(shí)例中。具體操作,請(qǐng)參見(jiàn)掛載文件系統(tǒng)場(chǎng)景說(shuō)明。
登錄ECS實(shí)例下載數(shù)據(jù)模型。本文以Qwen-7B-Chat模型為例。
執(zhí)行以下命令,進(jìn)入NAS文件系統(tǒng)掛載路徑。例如/mnt/nas。
cd /mnt/nas
執(zhí)行以下命令,安裝Git。
sudo yum install git
執(zhí)行以下命令,安裝Git LFS(Large File Support)插件。
sudo yum install git-lfs
執(zhí)行以下命令,將ModelScope上的Qwen-7B-Chat倉(cāng)庫(kù)克隆到本地。
GIT_LFS_SKIP_SMUDGE=1 git clone https://www.modelscope.cn/qwen/Qwen-7B-Chat.git
執(zhí)行以下命令,進(jìn)入Qwen-7B-Chat倉(cāng)庫(kù)目錄。
cd Qwen-7B-Chat
執(zhí)行以下命令,在Qwen-7B-Chat目錄下,下載LFS管理的大文件。
git lfs pull
步驟二:使用Arena提交微調(diào)前的模型推理服務(wù)
為了展示模型微調(diào)效果,首先將運(yùn)行沒(méi)有微調(diào)之前的Qwen-7B-Chat模型推理服務(wù)。
執(zhí)行以下命令,運(yùn)行沒(méi)有微調(diào)的Qwen-7B-Chat模型推理服務(wù)。
arena serve custom \ --name=qwen-7b-chat \ --namespace=default \ --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/qwen:cu117 \ --gpus=1 \ --data=nas-pvc:/mnt \ --restful-port=80 \ "python web_demo.py --server-port 80 --server-name 0.0.0.0 -c /mnt/models/Qwen-7B-Chat/"
預(yù)期輸出:
service/qwen-7b-chat-202404301015 created deployment.apps/qwen-7b-chat-202404301015-custom-serving created INFO[0003] The Job qwen-7b-chat has been submitted successfully INFO[0003] You can run `arena serve get qwen-7b-chat --type custom-serving -n default` to check the job status
輸出結(jié)果表明
qwen-7b-chat
推理服務(wù)已被成功部署。執(zhí)行以下命令,查看推理作業(yè)運(yùn)行日志。
arena serve logs -f qwen-7b-chat
預(yù)期輸出:
The model is automatically converting to bf16 for faster inference. If you want to disable the automatic precision, please manually add bf16/fp16/fp32=True to "AutoModelForCausalLM.from_pretrained". Try importing flash-attention for faster inference... Loading checkpoint shards: 100%|██████████| 8/8 [03:16<00:00, 24.59s/it]
模型加載完成之后,執(zhí)行以下命令,將其Web端口轉(zhuǎn)發(fā)到本地8901端口進(jìn)行訪(fǎng)問(wèn)。
重要kubectl port-forward
建立的端口轉(zhuǎn)發(fā)僅適用于測(cè)試環(huán)境下的快速驗(yàn)證,不適合在生產(chǎn)環(huán)境中使用,使用時(shí)請(qǐng)注意安全風(fēng)險(xiǎn)。kubectl port-forward services/qwen-7b-chat-202404301015 8901:80
預(yù)期輸出:
Forwarding from 127.0.0.1:8901 -> 80 Forwarding from [::1]:8901 -> 80
在瀏覽器地址欄中輸入http://localhost:8901,可以進(jìn)入Qwen-7B-Chat進(jìn)行對(duì)話(huà)。
以下示例展示了一個(gè)簡(jiǎn)單的對(duì)話(huà)場(chǎng)景,用戶(hù)發(fā)起提問(wèn),助手給出回復(fù)。其中,Q表示用戶(hù)輸入,A表示模型輸出:
Q: 創(chuàng)建集群后,是否可以更改容器運(yùn)行時(shí)? A: 是的,創(chuàng)建集群后,您可以更改容器運(yùn)行時(shí)。阿里云的服務(wù)器鏡像和平臺(tái)提供了多種不同的運(yùn)行時(shí)環(huán)境,例如Docker、Kubernetes等。您可以根據(jù)自己的需求選擇合適的運(yùn)行時(shí)環(huán)境。 要更改容器運(yùn)行時(shí),您需要先停止當(dāng)前的容器運(yùn)行,并重新啟動(dòng)一個(gè)新容器。如果您想要在現(xiàn)有集群上進(jìn)行更改,那么您可能需要?jiǎng)?chuàng)建一個(gè)新的集群,并將應(yīng)用程序從舊的集群轉(zhuǎn)移到新的集群。 另外,阿里云還提供了一些自動(dòng)化工具和服務(wù),可以幫助您輕松地在集群中進(jìn)行運(yùn)行時(shí)更改。例如,您可以使用“一鍵部署”服務(wù)快速部署新的應(yīng)用程序,或者使用“統(tǒng)一監(jiān)控”服務(wù)來(lái)監(jiān)控您的應(yīng)用運(yùn)行情況并及時(shí)發(fā)現(xiàn)和處理問(wèn)題。
執(zhí)行以下命令,刪除Qwen-7B-Chat推理作業(yè)。
arena serve delete qwen-7b-chat
步驟三:準(zhǔn)備微調(diào)數(shù)據(jù)集
對(duì)Qwen-7B-Chat模型進(jìn)行LoRA(Low-Rank Adaptation)微調(diào)前,您需要先準(zhǔn)備微調(diào)數(shù)據(jù)集以提升模型在特定對(duì)話(huà)場(chǎng)景下的表現(xiàn)。
微調(diào)數(shù)據(jù)中的所有樣本以JSON文件格式存放在一個(gè)JSON數(shù)組中,每個(gè)樣本需要包含id
和conversation
字段,其中conversations
字段為一個(gè)數(shù)組。以下是一個(gè)微調(diào)數(shù)據(jù)集示例:
[
{
"id": "identity_0",
"conversations": [
{
"from": "user",
"value": "你好"
},
{
"from": "assistant",
"value": "我是一個(gè)語(yǔ)言模型,我叫通義千問(wèn)。"
}
]
}
]
微調(diào)數(shù)據(jù)集參數(shù)說(shuō)明如下:
id
:唯一標(biāo)識(shí)符,用于區(qū)分不同的對(duì)話(huà)樣本,例如"id": "identity_0"
。conversations
:包含實(shí)際對(duì)話(huà)內(nèi)容的數(shù)組,每個(gè)對(duì)話(huà)由一系列交替的用戶(hù)和助手消息組成,每個(gè)消息對(duì)象有兩個(gè)字段:"from"
:指示消息來(lái)源,可以是"user"
或"assistant"
。"value"
:具體的對(duì)話(huà)內(nèi)容,如用戶(hù)說(shuō)"你好"
,助手回應(yīng)"我是一個(gè)語(yǔ)言模型,我叫通義千問(wèn)。"
。
本次微調(diào)使用的數(shù)據(jù)集已經(jīng)打包在鏡像中,該數(shù)據(jù)集針對(duì)步驟二中提出的問(wèn)題給出了特定的回答,您可以登錄容器中執(zhí)行cat /data/shared/Qwen/example.json
命令查看微調(diào)數(shù)據(jù)詳情。
步驟四:使用Arena提交微調(diào)作業(yè)
以下使用Arena提交一個(gè)對(duì)Qwen-7B-Chat模型進(jìn)行LoRA微調(diào)的作業(yè),該次微調(diào)將產(chǎn)生一個(gè)LoRA模型,本文將該模型注冊(cè)為一個(gè)新的模型版本,模型名稱(chēng)為Qwen-7B-Chat-Lora
。
執(zhí)行以下命令,提交一個(gè)對(duì)Qwen-7B-Chat模型進(jìn)行LoRA微調(diào)的作業(yè)。
# Submit a finetune job and register the output PEFT model as a new model version arena submit pytorchjob \ --name=qwen-7b-chat-finetune \ --namespace=default \ --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/qwen:cu117 \ --image-pull-policy=Always \ --gpus=1 \ --working-dir /data/shared/Qwen \ --data=nas-pvc:/mnt/ \ --model-name=Qwen-7B-Chat-Lora \ --model-source=pvc://default/nas-pvc/finetune/Qwen-7B-Chat-Lora \ "bash finetune/finetune_lora_single_gpu.sh -m /mnt/models/Qwen-7B-Chat/ -d example.json -o /mnt/finetune/Qwen-7B-Chat-Lora"
Qwen-7B-Chat-Lora
模型源路徑為pvc://default/nas-pvc/finetune/Qwen-7B-Chat-Lora
,表示該模型存儲(chǔ)在default
命名空間里一個(gè)名為nas-pvc
的存儲(chǔ)卷中,存儲(chǔ)路徑為/finetune/Qwen-7B-Chat-Lora
。預(yù)期輸出:
pytorchjob.kubeflow.org/qwen-7b-chat-finetune created INFO[0004] The Job qwen-7b-chat-finetune has been submitted successfully INFO[0004] You can run `arena get qwen-7b-chat-finetune --type pytorchjob -n default` to check the job status INFO[0004] registered model "Qwen-7B-Chat-Lora" created INFO[0005] model version 1 for "Qwen-7B-Chat-Lora" created
預(yù)期輸出表明模型微調(diào)任務(wù)已經(jīng)成功創(chuàng)建與提交,并自動(dòng)地完成了模型注冊(cè)與模型版本創(chuàng)建。
執(zhí)行以下命令,查看該次作業(yè)詳情。
arena get qwen-7b-chat-finetune
預(yù)期輸出:
Name: qwen-7b-chat-finetune Status: RUNNING Namespace: default Priority: N/A Trainer: PYTORCHJOB Duration: 2m CreateTime: 2024-04-29 16:02:01 EndTime: ModelName: Qwen-7B-Chat-Lora ModelVersion: 1 ModelSource: pvc://default/nas-pvc/finetune/Qwen-7B-Chat-Lora/ Instances: NAME STATUS AGE IS_CHIEF GPU(Requested) NODE ---- ------ --- -------- -------------- ---- qwen-7b-chat-finetune-master-0 Running 2m true 1 ap-southeast-1.XX.XX.XX.XX
輸出結(jié)果記錄了該作業(yè)關(guān)聯(lián)的模型的名稱(chēng)、版本號(hào)及其源路徑等詳細(xì)信息。
執(zhí)行以下命令,查看微調(diào)作業(yè)日志。
arena logs -f qwen-7b-chat-finetune
+ export CUDA_VISIBLE_DEVICES=0 + CUDA_VISIBLE_DEVICES=0 + mkdir -p /mnt/finetune/Qwen-7B-Chat-Lora + python finetune.py --model_name_or_path /mnt/models/Qwen-7B-Chat/ --data_path example.json --bf16 True --output_dir /mnt/finetune/Qwen-7B-Chat-Lora --num_train_epochs 5 --per_device_train_batch_size 2 --per_device_eval_batch_size 1 --gradient_accumulation_steps 8 --evaluation_strategy no --save_strategy steps --save_steps 1000 --save_total_limit 10 --learning_rate 3e-4 --weight_decay 0.1 --adam_beta2 0.95 --warmup_ratio 0.01 --lr_scheduler_type cosine --logging_steps 1 --report_to none --model_max_length 512 --lazy_preprocess True --gradient_checkpointing --use_lora [2024-04-30 02:26:42,358] [INFO] [real_accelerator.py:203:get_accelerator] Setting ds_accelerator to cuda (auto detect) ... Loading checkpoint shards: 100%|██████████| 8/8 [00:02<00:00, 3.29it/s] /usr/local/lib/python3.8/dist-packages/accelerate/accelerator.py:436: FutureWarning: Passing the following arguments to `Accelerator` is deprecated and will be removed in version 1.0 of Accelerate: dict_keys(['dispatch_batches', 'split_batches']). Please pass an `accelerate.DataLoaderConfiguration` instead: dataloader_config = DataLoaderConfiguration(dispatch_batches=None, split_batches=False) warnings.warn( You are using an old version of the checkpointing format that is deprecated (We will also silently ignore `gradient_checkpointing_kwargs` in case you passed it).Please update to the new format on your modeling file. To use the new format, you need to completely remove the definition of the method `_set_gradient_checkpointing` in your model. trainable params: 143,130,624 || all params: 7,864,455,168 || trainable%: 1.8199687192876373 Loading data... Formatting inputs...Skip in lazy mode 100%|██████████| 20/20 [02:42<00:00, 8.12s/it] {'loss': 2.6322, 'learning_rate': 0.0003, 'epoch': 0.23} {'loss': 2.6542, 'learning_rate': 0.00029795419551040833, 'epoch': 0.46} {'loss': 2.3209, 'learning_rate': 0.00029187258625509513, 'epoch': 0.69} {'loss': 2.1613, 'learning_rate': 0.00028192106268097334, 'epoch': 0.91} {'loss': 1.6563, 'learning_rate': 0.00026837107640945905, 'epoch': 1.14} {'loss': 1.4985, 'learning_rate': 0.00025159223574386114, 'epoch': 1.37} {'loss': 1.3369, 'learning_rate': 0.00023204222371836405, 'epoch': 1.6} {'loss': 1.0505, 'learning_rate': 0.0002102543136979454, 'epoch': 1.83} {'loss': 0.7033, 'learning_rate': 0.00018682282307111987, 'epoch': 2.06} {'loss': 0.5576, 'learning_rate': 0.00016238690182084986, 'epoch': 2.29} {'loss': 0.2523, 'learning_rate': 0.00013761309817915014, 'epoch': 2.51} {'loss': 0.2481, 'learning_rate': 0.00011317717692888012, 'epoch': 2.74} {'loss': 0.1343, 'learning_rate': 8.97456863020546e-05, 'epoch': 2.97} {'loss': 0.0676, 'learning_rate': 6.795777628163599e-05, 'epoch': 3.2} {'loss': 0.0489, 'learning_rate': 4.840776425613886e-05, 'epoch': 3.43} {'loss': 0.0312, 'learning_rate': 3.162892359054098e-05, 'epoch': 3.66} {'loss': 0.018, 'learning_rate': 1.8078937319026654e-05, 'epoch': 3.89} {'loss': 0.0134, 'learning_rate': 8.127413744904804e-06, 'epoch': 4.11} {'loss': 0.0141, 'learning_rate': 2.0458044895916513e-06, 'epoch': 4.34} {'loss': 0.0099, 'learning_rate': 0.0, 'epoch': 4.57} {'train_runtime': 162.4618, 'train_samples_per_second': 2.154, 'train_steps_per_second': 0.123, 'train_loss': 0.8704732102807611, 'epoch': 4.57}
步驟五:使用Arena訪(fǎng)問(wèn)模型倉(cāng)庫(kù)
執(zhí)行以下命令,使用Arena列出所有已注冊(cè)模型。
arena model list
預(yù)期輸出:
NAME LATEST_VERSION LAST_UPDATED_TIME Qwen-7B-Chat-Lora 1 2024-04-30T10:26:14+08:00
執(zhí)行以下命令,查看注冊(cè)模型Qwen-7B-Chat-Lora(版本號(hào)為1)的版本詳情。
arena model get \ --name Qwen-7B-Chat-Lora \ --version 1
Name: Qwen-7B-Chat-Lora Version: 1 CreationTime: 2024-04-30T10:26:14+08:00 LastUpdatedTime: 2024-04-30T10:26:14+08:00 Source: pvc://default/nas-pvc/finetune/Qwen-7B-Chat-Lora Description: arena submit pytorchjob \ --data nas-pvc:/mnt/ \ --gpus 1 \ --image kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/qwen:cu117 \ --image-pull-policy Always \ --model-name Qwen-7B-Chat-Lora \ --model-source pvc://default/nas-pvc/finetune/Qwen-7B-Chat-Lora \ --name qwen-7b-chat-finetune \ --namespace default \ --working-dir /data/shared/Qwen \ "bash finetune/finetune_lora_single_gpu.sh -m /mnt/models/Qwen-7B-Chat/ -d example.json -o /mnt/finetune/Qwen-7B-Chat-Lora" Tags: createdBy: arena modelName: Qwen-7B-Chat-Lora arena.kubeflow.org/uid: 3399d840e8b371ed7ca45dda29debeb1
輸出結(jié)果表明Arena會(huì)自動(dòng)將作業(yè)提交的完整命令添加至描述信息中,并添加相應(yīng)的標(biāo)簽。
步驟六:使用Arena提交微調(diào)后的模型推理服務(wù)
執(zhí)行以下命令,運(yùn)行經(jīng)過(guò)微調(diào)之后的Qwen-7B-Chat模型推理服務(wù)。
arena serve custom \ --name=qwen-7b-chat-lora \ --namespace=default \ --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/qwen:cu117 \ --image-pull-policy=Always \ --gpus=1 \ --data=nas-pvc:/mnt \ --restful-port=80 \ --model-name=Qwen-7B-Chat-Lora \ --model-version=1 \ "python web_demo_peft.py --server-port 80 --server-name 0.0.0.0 -c /mnt/finetune/Qwen-7B-Chat-Lora"
預(yù)期輸出:
service/qwen-7b-chat-lora-202404301036 created deployment.apps/qwen-7b-chat-lora-202404301036-custom-serving created INFO[0003] The Job qwen-7b-chat-lora has been submitted successfully INFO[0003] You can run `arena serve get qwen-7b-chat-lora --type custom-serving -n default` to check the job status
輸出結(jié)果表明微調(diào)后的模型推理服務(wù)已成功部署。
執(zhí)行以下命令,查看作業(yè)運(yùn)行日志。
arena serve logs -f qwen-7b-chat-lora
預(yù)期輸出:
The model is automatically converting to bf16 for faster inference. If you want to disable the automatic precision, please manually add bf16/fp16/fp32=True to "AutoModelForCausalLM.from_pretrained". Try importing flash-attention for faster inference... Loading checkpoint shards: 100%|██████████| 8/8 [03:10<00:00, 23.76s/it]
模型加載完成之后,執(zhí)行以下命令,將其Web端口轉(zhuǎn)發(fā)到本地的8901端口進(jìn)行訪(fǎng)問(wèn)。
重要kubectl port-forward
建立的端口轉(zhuǎn)發(fā)僅適用于測(cè)試環(huán)境下的快速驗(yàn)證,不適合在生產(chǎn)環(huán)境中使用,使用時(shí)請(qǐng)注意安全風(fēng)險(xiǎn)。kubectl port-forward services/qwen-7b-chat-lora-202404301036 8901:80
預(yù)期輸出:
Forwarding from 127.0.0.1:8901 -> 80 Forwarding from [::1]:8901 -> 80
在瀏覽器地址欄中輸入http://localhost:8901,然后提出與步驟二(模型微調(diào)前)相同的問(wèn)題。
以下示例展示了一個(gè)簡(jiǎn)單的對(duì)話(huà)場(chǎng)景,用戶(hù)發(fā)起提問(wèn),助手給出回復(fù)。其中,Q表示用戶(hù)輸入,A表示模型輸出:
Q: 創(chuàng)建集群后,是否可以更改容器運(yùn)行時(shí)? A: 創(chuàng)建集群后,不支持切換容器運(yùn)行時(shí),但是您可以創(chuàng)建不同類(lèi)型運(yùn)行時(shí)的節(jié)點(diǎn)池。節(jié)點(diǎn)池與節(jié)點(diǎn)池的運(yùn)行時(shí)可以不同。更多信息,請(qǐng)參見(jiàn)節(jié)點(diǎn)池概述。
將上述的答案和容器鏡像中內(nèi)置的微調(diào)數(shù)據(jù)進(jìn)行對(duì)比,可以發(fā)現(xiàn)模型微調(diào)后助手回答問(wèn)題的質(zhì)量顯著提升。
執(zhí)行以下命令,刪除微調(diào)后的Qwen-7B-Chat推理作業(yè)。
arena serve delete qwen-7b-chat-lora
相關(guān)文檔
如需對(duì)MLflow模型倉(cāng)庫(kù)中的模型進(jìn)行管理,請(qǐng)參見(jiàn)對(duì)MLflow模型倉(cāng)庫(kù)中的模型進(jìn)行管理。