本文旨在結合筆者自身的實踐經歷,詳細介紹如何使用 LLaMA-Factory 來微調多模態大語言模型。目前倉庫已支援若干流行的MLLM比如LLaVA-1.5,Yi-VL,Paligemma等。
2024.5.29 注:本文後續不再更新,如果想了解更新的特性和功能歡迎訪問知乎部落格:https://zhuanlan.zhihu.com/p/699777943
值得注意的是現在LLaMA-Factory引入了CLI,因此呼叫方式更加簡單,只需要簡單的幾行命令即可開始微調。
環境準備
首先安裝LLaMA-Factory
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .[torch,metrics]
檢查機器含有可用GPU
import torch
try:
assert torch.cuda.is_available() is True
except AssertionError:
print("Please set up a GPU before using LLaMA Factory")
多模態多輪對話資料集構建
這裡出於方便的考慮,以倉庫自帶的 mllm_demo 資料集作為例子。在此也推薦一些筆者建立的hf資料集可供使用,都能適配LLaMA-Factory,場景分別是通用,醫學,動漫。
https://huggingface.co/datasets/BUAADreamer/llava-en-zh-300k
https://huggingface.co/datasets/BUAADreamer/llava-med-zh-instruct-60k
https://huggingface.co/datasets/BUAADreamer/pokemon-gpt4-1k
本地影像準備
專案的 data/mllm_demo_data 目錄下有三張比較新的影像,兩張為拜仁慕尼黑的球員本賽季在主場慶祝,1張為桂海潮教授在演講。本文以這三張影像作為例子進行講解,讀者可以換成任意的自己的影像
data/mllm_demo_data/1.jpg
data/mllm_demo_data/2.jpg
data/mllm_demo_data/3.jpg
本地多輪對話資料構建
直接修改 data/mllm_demo.json 即可,這裡用python寫入檔案作為演示,格式遵循類似openai的聊天格式。images 引數設定為含有一張影像所在路徑的列表。注意:這裡的影像路徑為絕對路徑或相對於當前位置的相對路徑。
[
{
"messages": [
{
"content": "他們是誰",
"role": "user"
},
{
"content": "他們是來自拜仁慕尼黑的主力中鋒凱恩和主力中場格雷茨卡。",
"role": "assistant"
},
{
"content": "他們在做什麼?",
"role": "user"
},
{
"content": "他們在拜仁慕尼黑主場激情慶祝。",
"role": "assistant"
}
],
"images": [
"data/mllm_demo_data/1.jpg"
]
},
{
"messages": [
{
"content": "他是誰?",
"role": "user"
},
{
"content": "他是拜仁慕尼黑的功勳前鋒托馬斯穆勒。",
"role": "assistant"
},
{
"content": "他為什麼在地上?",
"role": "user"
},
{
"content": "因為他正在雙膝跪地滑行慶祝。",
"role": "assistant"
}
],
"images": [
"data/mllm_demo_data/2.jpg"
]
},
{
"messages": [
{
"content": "請描述這張影像",
"role": "user"
},
{
"content": "中國航天員桂海潮正在發表演講",
"role": "assistant"
},
{
"content": "他取得過哪些成就?",
"role": "user"
},
{
"content": "他於2022年6月被任命為神舟十六號任務的有效載荷專家,從而成為2023年5月30日進入太空的首位平民宇航員。他負責在軌操作空間科學實驗有效載荷。",
"role": "assistant"
}
],
"images": [
"data/mllm_demo_data/3.jpg"
]
}
]
本地資料更新至dataset_info.json
如果是自己建立的本地新資料集,需要在 data/dataset_info.json 里加入對應的資訊
"mllm_demo": {
"file_name": "mllm_demo.json",
"formatting": "sharegpt",
"columns": {
"messages": "messages",
"images": "images"
},
"tags": {
"role_tag": "role",
"content_tag": "content",
"user_tag": "user",
"assistant_tag": "assistant"
}
},
上傳資料集到huggingface
以上是影像儲存在本地的使用方法,如果想分享自己的資料集,可以使用下列程式碼,需要先到huggingface申請自己的key:https://huggingface.co/settings/tokens
import huggingface_hub
huggingface_hub.login("hf_xxxxx") #替換為你自己的key從而登入hf
from datasets import Dataset, Features, Image, Sequence, Value
def gen():
for data in examples:
yield data
#構建資料集feature
features = Features(
{
'messages': [
{
'role': Value(dtype='string', id=None),
'content': Value(dtype='string', id=None),
}
],
'images': Sequence(feature=Image(decode=True, id=None), length=-1, id=None),
}
)
#使用迭代生成
dataset = Dataset.from_generator(gen, features=features)
#push到huggingface
dataset.push_to_hub("BUAADreamer/mllm_demo")
huggingface資料更新至dataset_info.json
將上傳好的huggingface資料集資訊更新在 data/dataset_info.json 中
"mllm_demo_hf": {
"hf_hub_url": "BUAADreamer/mllm_demo",
"formatting": "sharegpt",
"columns": {
"messages": "messages",
"images": "images"
},
"tags": {
"role_tag": "role",
"content_tag": "content",
"user_tag": "user",
"assistant_tag": "assistant"
}
},
多模態對話微調
配置監督微調Yaml檔案
這裡以lora為例,我們建立一個 config/llava_lora_sft.yaml
根據自己需求,需要修改的引數主要有:
- model_name_or_path 和 template,對應模型和聊天模板,目前主要支援:
- llava-1.5 和 vicuna
- yi-vl 和 yi_vl
- paligemma 和 gemma
- finetuning_type 和 lora_target ,finetuning_type 可以改為 full 從而全引數微調
- dataset 對應 data/dataset_info.json 對應的資料集的key名字,這裡以本地的 mllm_demo 為例
- 其他訓練引數比如 learning_rate num_train_epochs output_dir 等。由於llava-1.5主要面向英文,因此中文資料需要較多輪次才能擬合。
### model
model_name_or_path: llava-hf/llava-1.5-7b-hf
visual_inputs: true
### method
stage: sft
do_train: true
finetuning_type: lora
lora_target: q_proj,v_proj
### dataset
dataset: mllm_demo
template: vicuna
cutoff_len: 1024
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 16
### output
output_dir: saves/llava1_5-7b/lora/sft
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 0.0001
num_train_epochs: 50.0
lr_scheduler_type: cosine
warmup_steps: 0.1
fp16: true
train_mm_proj_only: false
### eval
do_eval: false
配置LLaVA式的預訓練yaml檔案
LLaVA中的預訓練是隻訓練 multi_modal_projector ,凍結 language_model 和 vision_tower 。因此我們需要將 finetuning_type 設定為 full ,將 train_mm_proj_only 設定為 true。預訓練資料使用單輪圖生文對話資料,可以參考以下 mllm_pt_demo 資料集:
https://huggingface.co/datasets/BUAADreamer/mllm_pt_demo
開始微調
一條命令微調。Lora微調只需要16G視訊記憶體,2min即可跑完
CUDA_VISIBLE_DEVICES=0 llamafactory-cli train config/llava_lora_sft.yaml
網頁聊天測試
一條命令部署。LLaVA-7B只需要16G視訊記憶體。注意如果是其他模型需要更換為訓練中使用的template
CUDA_VISIBLE_DEVICES=0 llamafactory-cli webchat \
--model_name_or_path llava-hf/llava-1.5-7b-hf \
--adapter_name_or_path saves/llava1_5-7b/lora/sft \
--template vicuna \
--visual_inputs
微調後Demo展示
以下是三條資料的測試,對於這些比較新鮮的知識模型完全擬合了,(仁迷狂喜
data/mllm_demo_data/1.jpg 測試結果:
data/mllm_demo_data/2.jpg 測試結果:
data/mllm_demo_data/3.jpg 測試結果:
模型匯出和上傳huggingface
先配置 config/llava_lora_sft_export.yaml 檔案,記得替換 export_hub_model_id 和 hf_hub_token
# model
model_name_or_path: llava-hf/llava-1.5-7b-hf
adapter_name_or_path: saves/llava1_5-7b/lora/sft
template: vicuna
finetuning_type: lora
visual_inputs: true
# export
export_dir: models/llava1_5-7b
export_size: 2
export_device: cpu
export_legacy_format: false
export_hub_model_id: xxxxx/My-LLaVA-7B
hf_hub_token: xxxxx
一行命令匯出並上傳到huggingface
CUDA_VISIBLE_DEVICES=0 llamafactory-cli export config/llava_lora_sft_export.yaml
總結
所有程式碼都可以在以下倉庫復現
https://github.com/BUAADreamer/MLLM-Finetuning-Demo
同時,筆者也使用 LLaMA-Factory 訓練了一箇中文醫學多模態大模型 Chinese-LLaVA-Med,目前還在探索中,歡迎關注!更多MLLM的微調例子可以參考此專案:
https://github.com/BUAADreamer/Chinese-LLaVA-Med
此外,還有 @hiyouga 大佬訓練的多輪對話版本paligemma,值得一提的是,這個模型小而強大,可以做許多多模態任務,還是多語言的:
https://huggingface.co/hiyouga/PaliGemma-3B-Chat-v0.1