mistral-finetune
是一個輕量級程式碼庫,可以對 Mistral 模型進行記憶體高效且高效能的微調。它基於 LoRA,這是一種訓練範例,其中大多數權重被凍結,並且僅訓練 1-2% 的低秩矩陣擾動形式的附加權重。
為了獲得最大效率,建議使用 A100 或 H100 GPU。該程式碼庫針對多 GPU 單節點訓練設定進行了最佳化,但對於較小的模型(例如 7B),單一 GPU 就足夠了。
筆記
這個儲存庫的目標是提供一個簡單的引導入口點來微調 Mistral 模型。因此,它是相當固執己見的(特別是在資料格式化方面),並且並非旨在詳盡地涵蓋多種模型架構或硬體類型。對於更通用的方法,您可以查看其他一些很棒的項目,例如 torchtune。
2024 年 8 月 13 日:Mistral Large v2 現在與mistral-finetune
相容!
與其他模型相比,建議使用較低的學習率,例如lr=1e-6 對於大多數情況應該會效果很好。
由於模型尺寸較大,微調 Mistral-Large v2 需要顯著更多的記憶體。現在將seq_len
設定為 <= 8192
在此下載 123B 指令並將model_id_or_path
設定為下載的檢查點目錄。
2024 年 7 月 19 日:Mistral Nemo 現在與mistral-finetune
相容!
建議使用與 7B v3 相同的超參數。
由於詞彙量較大,微調 Mistral-Nemo 目前需要更多內存,這會增加 CE 損失的峰值內存需求(我們很快就會在此處添加改進的 CE 損失)。現在將seq_len
設定為 <= 16384
運行pip install --upgrade mistral-common
以獲得支援 Tekkenizer 的版本 ( >=1.3.1
)。
在此下載 12B Base 或 Instruct,並將model_id_or_path
設定為下載的檢查點目錄。
要開始 Mistral LoRA 微調,請按照以下步驟操作:
克隆此存儲庫:
cd $HOME && git clone https://github.com/mistralai/mistral-finetune.git
安裝所有必要的依賴項:
cd mistral-finetune pip install -r requirements.txt
我們建議微調官方 Mistral 模型之一,您可以在此處下載:
模型 | 關聯 | 校驗和 |
---|---|---|
7B 底座 V3 | 7B底座 | 0663b293810d7571dad25dae2f2a5806 |
7B 指令 v3 | 7B 指令 v3 | 80b71fcb6416085bcb4efad86dfb4d52 |
8x7B 基礎 V1 | 8x7B 底座 | (高頻連結) |
8x7B 指令 V1 | 8x7B 指導 | 8e2d3930145dc43d3084396f49d38a3f |
8x22 指導 V3 | 8x22 指導 | 471a02a6902706a2f1e44a693813855b |
8x22B 基礎 V3 | 8x22B 底座 | a2fa75117174f87d1197e3a4eb50371a |
12B 指導 | 12B 指導 (米斯特拉爾-尼莫) | 296fbdf911cb88e6f0be74cd04827fe7 |
12B底座 | 12 基地(米斯特拉爾-尼莫) | c5d079ac4b55fc1ae35f51f0a3c0eb83 |
米斯特拉爾大 2 | 123B 指導(大 v2) | fc602155f9e39151fba81fcaab2fa7c4 |
重要提示:對於 8x7B Base V1 和 8x7B Instruct V1,有必要在微調之前使用我們的 v3 分詞器並將詞彙表大小擴展到 32768。有關此過程的詳細說明,請參閱“模型擴充”部分。
例如,要下載 7B-base 模型,您可以執行以下命令:
mkdir -p ~/${HOME}/mistral_modelscd ${HOME} && wget https://models.mistralcdn.com/mistral-7b-v0-3/mistral-7B-v0.3.tar tar -xf 米斯特拉爾-7B-v0.3.tar -C 米斯特拉爾_模型
確保修改您的訓練腳本並將下載資料夾的路徑新增為model_id_or_path
。
例如,修改 example/7B.yaml 以包含$HOME/mistral_models/7B
的絕對路徑:
model_id_or_path: "/Users/johndoe/mistral_models/7B"
為了確保有效的訓練, mistral-finetune
對訓練資料的格式有嚴格的要求。
所有資料檔案必須以jsonl格式檔案儲存。
您可以建立兩種類型的資料檔案:
預訓練資料對應於儲存在"text"
鍵中的純文字資料。例如:
{"text": "文檔 n°1 中包含的文字"} {"text": "文檔 n°2 中包含的文字"}
目前支援兩種不同類型的指令跟隨資料:
指令:會話資料以清單的形式儲存在"messages"
鍵中。每個清單項目都是一個包含"content"
和"role"
鍵的字典。 "role"
是「使用者」、「助理」或「系統」之一的字串。只有當「角色」==「助理」時才會計算損失。例如:
{「訊息」:[ { "role": "user", "content": "文件 n°1 中包含的使用者互動 n°1" }, { "role": "assistant", "content": "文件 n°1 包含的機器人互動 n°1" }, { "role": "user", "content": "文件 n°1 中包含的使用者互動 n°2" }, { "role": "assistant", "content": "文件 n°1 包含的機器人互動 n°2" } ] } {「訊息」:[ { "role": "user", "content": "文件 n°2 中包含的使用者互動 n°1" }, { "role": "assistant", "content": "文件 n°2 包含的機器人互動 n°1" }, { "role": "user", "content": "文件 n°2 中包含的使用者互動 n°2" }, { "role": "assistant", "content": "文件 n°2 中包含的機器人互動 n°2", "weight": 0, # 不要在 n°2 上進行訓練 }, { "role": "user", "content": "文件 n°2 中包含的使用者互動 n°3" }, { "role": "assistant", "content": "文件 n°2 包含的機器人互動 n°3" } ] }
函數呼叫:會話資料以列表的形式儲存在"messages"
鍵中。每個清單項目都是一個包含"role"
和"content"
或"tool_calls"
鍵的字典。 "role"
是「使用者」、「助理」、「系統」或「工具」之一的字串。只有當「角色」==「助理」時才會計算損失。
注意:在函數呼叫中, "tool_calls"
的"id"
和"tool_call_id"
是隨機產生的 9 個字元的字串。我們建議在資料準備腳本中自動產生此內容,如此處所示。
例如:
{「訊息」:[ { "role": "system", "content": "您是得力助手,可以使用以下功能來幫助用戶,您可以根據需要使用這些功能" }, { "role": "user", "content": "你能幫我產生「listen」這個字的字謎嗎?" }, {“角色”:“助理”,“工具呼叫”:[ { "id": "TX92Jm8Zi", "type": "function", "function": { "name": "generate_anagram", "arguments": "{"word": "listen"}" } } ] }, { "角色": "工具", "內容": "{"字謎": "沉默"}", "tool_call_id": "TX92Jm8Zi" }, { "role": "assistant", "content": "單字「listen」的字謎是「silent」。" }, { "role": "user", "content": "太棒了!你能為「race」這個字產生一個字謎嗎?" }, {“角色”:“助理”,“工具呼叫”:[ { "id": "3XhQnxLsT", "type": "function", "function": { "name": "generate_anagram", "arguments": "{"word": "race"}" } } ] } ], 「工具」: [ { "type": "function", "function": { "name": "generate_anagram", "description": "產生給定單字的 anagram", "parameters": { "type": "object", " properties ": { "word": { "type": "string", "description": "要產生字謎詞的單字" } }, "必填": [ "單字" ] } } } ] }
在開始訓練運行之前,您應該驗證資料集的格式是否正確並估計訓練時間。您可以使用 ./utils/validate_data 腳本來執行此操作。
請注意,此步驟對於確保資料格式正確至關重要。
讓我們來看一個簡單的範例,按照以下指令訓練模型:
加載一塊 Ultachat_200k
建立資料資料夾並導航到該資料夾。
cd $HOME && mkdir -p 資料 && cd $HOME/data
將資料載入到 Pandas Dataframe 中。
注意:確保安裝了 pandas 和 pyarrow ( pip install pandas pyarrow
)。
將 pandas 導入為 pddf = pd.read_parquet('https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k/resolve/main/data/test_gen-00000-of-00001-3d4cd8309148a715)
分為train和eval
df_train=df.sample(frac=0.95,random_state=200)df_eval=df.drop(df_train.index)
將資料儲存到 jsonl
df_train.to_json(“ultrachat_chunk_train.jsonl”,東方=“記錄”,行= True)df_eval.to_json(“ultrachat_chunk_eval.jsonl”,東方=“記錄”,行= True)
修改您的訓練 yaml 以包含 ultrachat 資料集並驗證 yaml
修改 example/7B.yaml 以包含$HOME/data/ultrachat_chunk_train.jsonl
的絕對路徑以及用於訓練的資料集混合權重和用於評估的$HOME/data/ultrachat_chunk_eval.jsonl
,例如
data: instruct_data: "/Users/johndoe/data/ultrachat_chunk_train.jsonl" eval_instruct_data: "/Users/johndoe/data/ultrachat_chunk_eval.jsonl"
現在,您可以驗證您的訓練 yaml,以確保資料格式正確並估算訓練時間。
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml
完成後,您應該會看到包含以下許多錯誤的錯誤報告:
The data in line 1412 of dataset /Users/johndoe/data/ultrachat_chunk_eval.jsonl is incorrectly formatted. Expected last role to be one of: [assistant] but got user The data in line 1413 of dataset /Users/johndoe/data/ultrachat_chunk_eval.jsonl is incorrectly formatted. Expected last role to be one of: [assistant] but got user The data in line 1414 of dataset /Users/johndoe/data/ultrachat_chunk_eval.jsonl is incorrectly formatted. Expected last role to be one of: [assistant] but got user The data in line 1415 of dataset /Users/johndoe/data/ultrachat_chunk_eval.jsonl is incorrectly formatted. Expected last role to be one of: [assistant] but got user
許多對話似乎以「使用者」角色結束,這是不必要的,因為我們只訓練「輔助」訊息,因此會不必要地處理資料。
您可以使用 ./utils/reformat_data.py 來修正資料:
cd $HOME/mistral-finetune python -m utils.reformat_data $HOME/data/ultrachat_chunk_train.jsonl python -m utils.reformat_data $HOME/data/ultrachat_chunk_eval.jsonl
您應該看到將跳過幾個範例。
可能改變訓練步驟的數量
修正資料集後,再次執行腳本
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml
您應該獲得資料輸入和訓練參數的摘要:
Train States -------------------- { "expected": { "eta": "00:52:44", "data_tokens": 25169147, "train_tokens": 131072000, "epochs": "5.21", "max_steps": 500, "data_tokens_per_dataset": { "/Users/johndoe/data/ultrachat_chunk_train.jsonl": "25169147.0" }, "train_tokens_per_dataset": { "/Users/johndoe/data/ultrachat_chunk_train.jsonl": "131072000.0" }, "epochs_per_dataset": { "/Users/johndoe/data/ultrachat_chunk_train.jsonl": "5.2" } }, }
將max_steps
設為 500 會導致對資料集進行大約 5 次迭代,這是合理的,但可能有點太多了。下面顯示了建議的設置,在 8xH100 叢集上只需 30 分鐘。
接下來讓我們回顧一個更進階的用例來微調函數呼叫的模型。函數呼叫要求資料採用上述格式。讓我們來看一個例子。
載入 Glaive 函數呼叫資料集的聊天格式版本
建立資料資料夾並導航到該資料夾。
cd $HOME && mkdir -p 資料 && cd $HOME/data
將資料載入到 Pandas Dataframe 中。
注意:確保安裝了 pandas 和 pyarrow ( pip install pandas pyarrow
)。
將 pandas 導入為 pddf = pd.read_parquet('https://huggingface.co/datasets/Locutusque/function-calling-chatml/resolve/main/data/train-00000-of-00001-f0b56c6983b4a78f.
分為train和eval
df_train=df.sample(frac=0.95,random_state=200)df_eval=df.drop(df_train.index)
將資料儲存到 jsonl
df_train.to_json(“glaive_train.jsonl”,東方=“記錄”,行= True)df_eval.to_json(“glaive_eval.jsonl”,東方=“記錄”,行= True)
重新格式化資料集
正如我們所看到的,資料集不遵循所需的函數呼叫格式,因此需要重新格式化。除此之外, "from"
應重新命名為"user"
,並且應刪除多餘的"n"
字元。對於此資料集,您可以使用./utils/reformat_data_glaive.py
:
cd $HOME/mistral-finetune python -m utils.reformat_data_glaive $HOME/data/glaive_train.jsonl python -m utils.reformat_data_glaive $HOME/data/glaive_eval.jsonl
運行此命令將確保大多數樣本的格式正確。
注意:不可能編寫適用於所有類型資料集的重新格式化腳本。如果您的資料集尚未遵循上述所需格式,您很可能必須自行建立一個重新格式化腳本(mistral-chat 或 chat-gpt 是您最好的朋友!)。
驗證資料集
現在,您可以透過在example/7B.yaml
中分別將data.instruct_data
和data.eval_instruct_data
設定為$HOME/data/glaive_train.jsonl
和$HOME/data/glaive_eval.jsonl
來驗證資料集。
重新格式化的資料集仍然存在一些錯誤,可以使用--create_corrected
刪除這些錯誤。為此,請確保添加--create_corrected
,如下所示:
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml --create_corrected
執行此命令將顯示一些錯誤並保存兩個新資料集$HOME/data/glaive_train.jsonl.corrected
和$HOME/data/glaive_eval.jsonl.corrected
。確保在example/7B.yaml
中使用這兩個資料集並再次執行該命令。現在資料集的格式應該正確了!
完成資料集驗證部分後,我們現在可以開始訓練。為了run_dir
的訓練,我們建議將 max_steps 設定為僅wandb_project
。
max_steps: 300 run_dir: "/Users/johndoe/ultra_chat_test" wandb.project: ultra_chat
您也可以選擇設定wandb
儲存訓練配置並開始訓練!確保將--nproc-per-node
設定為可用 GPU 的數量。
cd $HOME/mistral-finetune torchrun --nproc-per-node 8 --master_port $RANDOM -m train example/7B.yaml
在 8xH100 節點上進行 ultra-chat 訓練大約需要 30 分鐘,所得權重的 MT Bench 分數應約為 6.3。
在 8xH100 節點上對 glaive 進行訓練大約需要 1 小時,並且產生的權重應該可以很好地用於函數呼叫。
範例mistral-finetune/examples/7B
定義了學習率、權重衰減等的合理參數...但建議您根據您的用例自訂這些設定。
一般來說,訓練配置應填寫以下參數:
model_id_or_path
定義開始訓練的模型。這可以是預訓練模型的路徑或本地模型目錄。
run_dir
定義儲存訓練檢查點和指標的目錄。
seq_len
定義訓練的序列長度。這是模型將處理的輸入序列的最大長度。樣本被打包以達到seq_len
的長度,以實現最大的訓練效率。
batch_size
定義每個 GPU 所使用的訓練範例的數量。注意:所有 GPU 的整體有效batch_size(以代幣為單位)等於num_gpus
x batch_size
x seq_len
。
max_steps
定義最大訓練步驟數。這是訓練過程將運行的迭代總數。可根據您的訓練場景的具體需求進行調整。訓練期間看到的總令牌數為max_steps
x num_gpus
x batch_size
x seq_len
。
optim.lr
定義學習率。這是優化器的初始學習率。
optim.weight_decay
定義權重衰減。權重衰減是一種正則化技術,用於透過懲罰大權重來防止過度擬合。我們建議將其保留為 0.1。
optim.pct_start
定義學習率開始下降之前的預熱階段所用的總訓練步數的百分比。它對應於PyTorch的OneCycleLR的pct_start。
lora.rank
定義 LoRA(低秩適應)適配器的大小。我們建議 64 或更少,這會調整 LoRA 中使用的低秩分解的秩。
seed
定義用於初始化和資料混洗/採樣的隨機種子。設定種子可確保結果的可重複性。
log_freq
定義記錄頻率。這指定了記錄訓練指標的頻率(以步驟為單位)。
data.instruct_data
是用來訓練的指令資料的路徑。此欄位必須依照上述格式填寫一個或多個資料來源。每個資料來源應該是 jsonl 檔案的路徑或包含 jsonl 檔案的目錄的路徑,後面接著用於定義此資料集重要性的權重:
。例如: data.instruct_data: "/path/to/data1.jsonl:5.,/path/to/data2.jsonl:1.,/path/to/dir_of_jsonls:1."
data.data
是附加預訓練資料的可選路徑,格式如上所述。請注意,該欄位可以留空。
data.eval_instruct_data
是評估指令資料的可選路徑,用於在每個eval_freq
步驟執行交叉驗證。交叉驗證指標顯示為loss
和perplexity
。
eval_freq
定義評估模型的頻率(以步驟為單位)。這指定了在驗證集上評估模型的時間間隔。
no_eval
是啟用或停用中間評估的標誌。將其設為 False 可以在訓練期間進行定期評估。
ckpt_freq
定義保存檢查點的頻率(以步驟為單位)。這指定保存模型狀態的時間間隔。
save_adapters
定義是否僅儲存經過訓練的 LoRA 檢查點,或是否應將經過訓練的 LoRA 直接合併到基礎模型中並儲存。注意:設定save_adapters=False
時,請確保您有足夠的 CPU 和 GPU 記憶體來在單一進程上儲存完整模型(這通常僅適用於 7B 模型)。
wandb.key
用於傳遞您的重量和偏差 (wandb) API 金鑰以進行日誌記錄。這允許您將訓練指標記錄到 wandb 儀表板。
wandb.project
定義 wandb 專案名稱。這是訓練運行將記錄在 wandb 介面中的位置。
一旦你的模型被訓練,你應該在推理中嘗試它。我們建議使用 Mistra-inference。
確保正確安裝了mistral_inference
:
pip install mistral_inference
假設您的lora.safetensors
保存在$HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safetensors
下,您可以使用mistral_inference
與模型聊天,例如:
米斯特拉爾聊天 /mnt/slow/runs/patrick/mistral-finetune/7B/ --max_tokens 256 --溫度 1.0 --instruct --lora_path $HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safafet
我們添加了對權重和偏差的明確支持,以幫助您監控和視覺化您的訓練運作。這種整合使您可以輕鬆記錄各種指標並追蹤實驗。
若要將權重和偏差與mistral-finetune
一起使用,請按照下列步驟操作:
安裝權重和偏差:
確保您已安裝wandb
庫。您可以使用 pip 安裝它:
pip安裝wandb
培訓開始後,您可以透過存取 wandb 專案儀表板即時監控進度。所有指標,包括訓練損失、評估損失、學習率等,都將被記錄和視覺化。
有關如何使用 wandb 的更多詳細信息,請訪問權重和偏差文件。
重要提示:請注意,只能微調與v3 分詞器相容的Mistra 模型,這意味著模型的詞彙量大小為32768 - 而不是32000。量大小32768 透過使用:
python -m utils.extend_model_vocab --original_model_ckpt /folder/to/old/model --extended_model_ckpt /folder/to/extended/model
一旦擴充生效,就可以使用/folder/to/extended/model
中新建立的模型檢查點進行微調。
微調 MoE 的最佳實踐是什麼?
我們在微調 MoE 模型時發現了更高程度的效能差異。使用不同種子微調 MoE 模型可能會導致表現出現很大差異,這並不罕見。我們沒有在密集模型中觀察到如此高的變異數。因此,我們建議在 MoE 模型上執行相同微調過程的多個實例,並選擇最佳效能的一個。
如何確定模型訓練過程中使用的令牌數量?
您可以使用以下腳本來尋找:https://github.com/mistralai/mistral-finetune/blob/main/utils/validate_data.py。此腳本接受 .yaml 訓練檔案作為輸入,並傳回模型正在訓練的標記數量。
如果遇到 CUDA 記憶體不足錯誤該怎麼辦?
一種可能的解決方案是減少每個 GPU 的批量大小。批次大小等於seq_len
x batch_size
。嘗試將batch_size
設為1並減少seq_len
。您可以在.yaml 檔案中定義batch_size
和seq_len
。