mistral-finetune
est une base de code légère qui permet un réglage fin et performant en termes de mémoire des modèles de Mistral. Il est basé sur LoRA, un paradigme d'entraînement dans lequel la plupart des poids sont gelés et seulement 1 à 2 % des poids supplémentaires sous la forme de perturbations matricielles de bas rang sont entraînés.
Pour une efficacité maximale, il est recommandé d'utiliser un GPU A100 ou H100. La base de code est optimisée pour les configurations de formation multi-GPU à nœud unique, mais pour les modèles plus petits, tels que le 7B, un seul GPU suffit.
Note
L'objectif de ce référentiel est de fournir un point d'entrée simple et guidé pour affiner les modèles Mistral. En tant que tel, il est assez avisé (en particulier en ce qui concerne le formatage des données) et ne vise pas à être exhaustif sur plusieurs architectures de modèles ou types de matériel. Pour des approches plus génériques, vous pouvez consulter d'autres grands projets comme torchtune.
13.08.2024 : Mistral Large v2 est désormais compatible avec mistral-finetune
!
Il est recommandé d'utiliser un taux d'apprentissage inférieur à celui des autres modèles, par exemple lr=1e-6 devrait bien fonctionner dans la plupart des cas.
Le réglage fin de Mistral-Large v2 nécessite beaucoup plus de mémoire en raison d'une taille de modèle plus grande. Pour l'instant, définissez seq_len
sur <= 8192
Téléchargez l'instruction 123B ici et définissez model_id_or_path
sur le répertoire du point de contrôle téléchargé.
19.07.2024 : Mistral Nemo est désormais compatible avec mistral-finetune
!
Il est recommandé d'utiliser les mêmes hyperparamètres que pour le 7B v3.
Le réglage fin de Mistral-Nemo nécessite actuellement beaucoup plus de mémoire en raison d'une plus grande taille de vocabulaire qui augmente le besoin de mémoire maximal de la perte de CE (nous ajouterons bientôt une perte de CE améliorée ici). Pour l'instant, définissez seq_len
sur <= 16384
Exécutez pip install --upgrade mistral-common
pour avoir une version prenant en charge le Tekkenizer ( >=1.3.1
).
Téléchargez la base 12B ou Instruct ici et définissez model_id_or_path
sur le répertoire du point de contrôle téléchargé.
Pour commencer avec le réglage fin de Mistral LoRA, suivez ces étapes :
Clonez ce dépôt :
cd $HOME && git clone https://github.com/mistralai/mistral-finetune.git
Installez toutes les dépendances requises :
cd mistral-finetune pip install -r requirements.txt
Nous vous recommandons de peaufiner l'un des modèles officiels Mistral que vous pouvez télécharger ici :
Modèle | Lien | Somme de contrôle |
---|---|---|
7B Base V3 | Socle 7B | 0663b293810d7571dad25dae2f2a5806 |
7B Instruction v3 | 7B Instruction v3 | 80b71fcb6416085bcb4efad86dfb4d52 |
Base 8x7B V1 | Socle 8x7B | (Liaison HF) |
Instruction 8x7B V1 | Instruction 8x7B | 8e2d3930145dc43d3084396f49d38a3f |
8x22 Instruire V3 | 8x22 Instruire | 471a02a6902706a2f1e44a693813855b |
Base 8x22B V3 | Socle 8x22B | a2fa75117174f87d1197e3a4eb50371a |
12B Instruire | 12B Instruire (Mistral-Némo) | 296fbdf911cb88e6f0be74cd04827fe7 |
Socle 12B | 12 Base (Mistral-Némo) | c5d079ac4b55fc1ae35f51f0a3c0eb83 |
Mistral Grand 2 | 123B Instruire (Grand v2) | fc602155f9e39151fba81fcaab2fa7c4 |
Avis important : Pour 8x7B Base V1 et 8x7B Instruct V1, il est nécessaire d'utiliser notre tokenizer v3 et d'étendre la taille du vocabulaire à 32768 avant d'affiner. Pour des instructions détaillées sur ce processus, veuillez vous référer à la section « Extension de modèle ».
Par exemple, pour télécharger le modèle de base 7B, vous pouvez exécuter la commande suivante :
mkdir -p ~/${HOME}/mistral_modelscd ${HOME} && wget https://models.mistralcdn.com/mistral-7b-v0-3/mistral-7B-v0.3.tar tar -xf mistral-7B-v0.3.tar -C mistral_models
Assurez-vous de modifier votre script de formation et d'ajouter le chemin d'accès au dossier téléchargé sous la forme model_id_or_path
.
Par exemple, modifiez example/7B.yaml pour inclure le chemin absolu vers $HOME/mistral_models/7B
:
model_id_or_path: "/Users/johndoe/mistral_models/7B"
Pour garantir une formation efficace, mistral-finetune
a des exigences strictes quant à la manière dont les données de formation doivent être formatées.
Tous les fichiers de données doivent être stockés dans des fichiers au format jsonl.
Vous pouvez créer deux types de fichiers de données :
Les données de pré-entraînement correspondent aux données en texte brut stockées dans la clé "text"
. Par exemple :
{"text": "Texte contenu dans le document n°1"} {"text": "Texte contenu dans le document n°2"}
Actuellement, deux types différents d'instructions suivant les données sont pris en charge :
Instruct : données conversationnelles stockées dans la touche "messages"
sous forme de liste. Chaque élément de la liste est un dictionnaire contenant les clés "content"
et "role"
. "role"
est une chaîne parmi « utilisateur », « assistant » ou « système ». La perte ne sera calculée que si "role" == "assistant". Par exemple :
{ "messages": [ { "role": "user", "content": "Interaction utilisateur n°1 contenue dans le document n°1" }, { "role": "assistant", "content": "Interaction du robot n°1 contenue dans le document n°1" }, { "role": "user", "content": "Interaction utilisateur n°2 contenue dans le document n°1" }, { "role": "assistant", "content": "Interaction du robot n°2 contenue dans le document n°1" } ] } { "messages": [ { "role": "user", "content": "Interaction utilisateur n°1 contenue dans le document n°2" }, { "role": "assistant", "content": "Interaction du robot n°1 contenue dans le document n°2" }, { "role": "user", "content": "Interaction utilisateur n°2 contenue dans le document n°2" }, { "role": "assistant", "content": "Interaction du robot n°2 contenue dans le document n°2", "weight" : 0, # ne pas s'entraîner sur le n°2 }, { "role": "user", "content": "Interaction utilisateur n°3 contenue dans le document n°2" }, { "role": "assistant", "content": "Interaction du robot n°3 contenue dans le document n°2" } ] }
Appel de fonction : données conversationnelles stockées dans la touche "messages"
sous forme de liste. Chaque élément de la liste est un dictionnaire contenant les clés "role"
et "content"
ou "tool_calls"
. "role"
est une chaîne comprenant « utilisateur », « assistant », « système » ou « outil ». La perte ne sera calculée que si "role" == "assistant".
Remarque : Dans la fonction appelant, le "id"
de "tool_calls"
et le "tool_call_id"
sont des chaînes générées aléatoirement d'exactement 9 caractères. Nous recommandons de générer cela automatiquement dans un script de préparation de données comme cela se fait ici.
Par exemple :
{ "messages": [ { "role": "system", "content": "Vous êtes un assistant utile qui a accès aux fonctions suivantes pour aider l'utilisateur, vous pouvez utiliser les fonctions si nécessaire" }, { "role": "user", "content": "Pouvez-vous m'aider à générer une anagramme du mot "écouter" ?" }, { "role": "assistant", "tool_calls": [ { "id": "TX92Jm8Zi", "type": "function", "function": { "name": "generate_anagram", "arguments": "{"word": "écouter"}" } } ] }, { "role": "tool", "content": "{"anagram": "silent"}", "tool_call_id": "TX92Jm8Zi" }, { "role": "assistant", "content": "L'anagramme du mot "listen" est "silent"." }, { "role": "user", "content": "C'est incroyable ! Pouvez-vous générer une anagramme pour le mot "race" ?" }, { "role": "assistant", "tool_calls": [ { "id": "3XhQnxLsT", "type": "function", "function": { "name": "generate_anagram", "arguments": "{"word": "race"}" } } ] } ], "outils": [ { "type": "function", "function": { "name": "generate_anagram", "description": "Générer une anagramme d'un mot donné", "parameters": { "type": "object", " Properties": { "word": { "type": "string", "description": "Le mot pour générer une anagramme de" } }, "obligatoire": [ "mot" ] } } } ] }
Avant de commencer une formation, vous devez vérifier que votre ensemble de données est correctement formaté et obtenir une estimation de la durée de la formation. Vous pouvez le faire en utilisant le script ./utils/validate_data.
Notez que cette étape est cruciale pour garantir que les données sont correctement formatées.
Passons en revue un exemple simple pour entraîner un modèle dans les instructions suivantes :
Charger un morceau d'Ultachat_200k
Créez le dossier de données et accédez au dossier.
cd $HOME && mkdir -p données && cd $HOME/données
Chargez les données dans un Pandas Dataframe.
Remarque : assurez-vous d'avoir installé pandas et pyarrow ( pip install pandas pyarrow
).
importer des pandas en tant que pdf = pd.read_parquet('https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k/resolve/main/data/test_gen-00000-of-00001-3d4cd8309148a71f.parquet')
Divisé en train et évaluation
df_train=df.sample(frac=0.95,random_state=200)df_eval=df.drop(df_train.index)
Enregistrer les données sur jsonl
df_train.to_json("ultrachat_chunk_train.jsonl", orient="records", lignes=True)df_eval.to_json("ultrachat_chunk_eval.jsonl", orient="records", lignes=True)
Modifiez votre yaml de formation pour inclure l'ensemble de données ultrachat et vérifiez le yaml
Modifiez example/7B.yaml pour inclure le chemin absolu vers $HOME/data/ultrachat_chunk_train.jsonl
ainsi qu'un ensemble de données mélangeant le poids pour l'entraînement et $HOME/data/ultrachat_chunk_eval.jsonl
pour l'évaluation, par exemple
data: instruct_data: "/Users/johndoe/data/ultrachat_chunk_train.jsonl" eval_instruct_data: "/Users/johndoe/data/ultrachat_chunk_eval.jsonl"
Vous pouvez désormais vérifier votre yaml d'entraînement pour vous assurer que les données sont correctement formatées et obtenir une estimation de votre temps d'entraînement.
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml
Une fois terminé, vous devriez voir un rapport d'erreurs contenant plusieurs des erreurs suivantes :
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
De nombreuses conversations semblent se terminer par le rôle « d'utilisateur », ce qui est inutile car nous nous entraînons uniquement sur les messages « d'assistant » et traiterions donc inutilement des données.
Vous pouvez utiliser ./utils/reformat_data.py pour corriger les données :
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
Vous devriez voir que quelques échantillons seront ignorés.
Changer potentiellement le nombre d’étapes de formation
Après correction de l'ensemble de données, exécutez à nouveau le script
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml
Vous devriez obtenir un résumé des paramètres de saisie des données et de formation :
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" } }, }
Avoir max_steps
défini sur 500 entraînerait une itération dans l'ensemble de données environ 5 fois, ce qui est raisonnable, mais pourrait être un peu trop. Un paramètre recommandé est présenté ci-dessous et ne prendrait que 30 minutes sur un cluster 8xH100.
Examinons ensuite un cas d'utilisation plus avancé pour affiner un modèle d'appel de fonction. L’appel de fonction nécessite que les données soient au format expliqué ci-dessus. Passons en revue un exemple.
Charger une version au format chat de l'ensemble de données d'appel de la fonction Glaive
Créez le dossier de données et accédez au dossier.
cd $HOME && mkdir -p données && cd $HOME/données
Chargez les données dans un Pandas Dataframe.
Remarque : assurez-vous d'avoir installé pandas et pyarrow ( pip install pandas pyarrow
).
importer des pandas en tant que pdf = pd.read_parquet('https://huggingface.co/datasets/Locutusque/function-calling-chatml/resolve/main/data/train-00000-of-00001-f0b56c6983b4a78f.parquet')
Divisé en train et évaluation
df_train=df.sample(frac=0.95,random_state=200)df_eval=df.drop(df_train.index)
Enregistrer les données sur jsonl
df_train.to_json("glaive_train.jsonl", orient="records", lignes=True)df_eval.to_json("glaive_eval.jsonl", orient="records", lignes=True)
Reformater l'ensemble de données
Comme on peut le voir, l'ensemble de données ne suit pas le format d'appel de fonction requis, il devra donc être reformaté. Entre autres choses, "from"
doit être renommé en "user"
et les caractères "n"
superflus doivent être supprimés. Pour cet ensemble de données, vous pouvez utiliser ./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
L’exécution de cette commande garantira que la plupart des échantillons sont au format correct.
Remarque : Il est impossible d'écrire des scripts de reformatage qui fonctionnent pour tous types d'ensembles de données. Si vous disposez d'ensembles de données qui ne respectent pas encore le format requis ci-dessus, vous devrez probablement créer vous-même un script de reformatage (mistral-chat ou chat-gpt est votre meilleur ami ici !).
Valider l'ensemble de données
Vous pouvez maintenant valider l'ensemble de données en définissant data.instruct_data
et data.eval_instruct_data
sur $HOME/data/glaive_train.jsonl
et $HOME/data/glaive_eval.jsonl
dans example/7B.yaml
respectivement.
Les ensembles de données reformatés contiennent encore quelques erreurs qui peuvent être supprimées avec --create_corrected
. Pour cela, assurez-vous d'ajouter --create_corrected
comme suit :
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml --create_corrected
L'exécution de cette commande affichera quelques erreurs et enregistrera deux nouveaux ensembles de données $HOME/data/glaive_train.jsonl.corrected
et $HOME/data/glaive_eval.jsonl.corrected
. Assurez-vous d'utiliser ces deux ensembles de données dans example/7B.yaml
et exécutez à nouveau la commande. L’ensemble de données doit maintenant être correctement formaté !
Après avoir suivi la section de vérification des jeux de données, nous pouvons maintenant commencer la formation. Pour une formation plus rapide, nous vous recommandons de définir max_steps sur seulement 300. Assurez-vous de définir run_dir
dans votre dossier d'expérience et éventuellement de définir wandb_project
sur un projet Weights & Biases pour la journalisation, par exemple :
max_steps: 300 run_dir: "/Users/johndoe/ultra_chat_test" wandb.project: ultra_chat
En option, vous pouvez également définir wandb
Enregistrez la configuration de la formation et démarrez la formation ! Assurez-vous de définir --nproc-per-node
sur le nombre de GPU disponibles.
cd $HOME/mistral-finetune torchrun --nproc-per-node 8 --master_port $RANDOM -m train example/7B.yaml
L'entraînement sur ultra-chat devrait prendre environ 30 minutes sur un nœud 8xH100 et les poids résultants devraient donner un score MT Bench autour de 6,3.
La formation sur glaive devrait prendre environ 1h sur un nœud 8xH100 et les poids résultants devraient bien fonctionner pour l'appel de fonction.
L'exemple mistral-finetune/examples/7B
définit des paramètres raisonnables pour le taux d'apprentissage, la perte de poids, etc... mais il vous est conseillé de personnaliser ces paramètres pour votre cas d'utilisation.
Généralement, une configuration de formation doit remplir les paramètres suivants :
model_id_or_path
définit le modèle à partir duquel démarrer la formation. Il peut s'agir d'un chemin vers un modèle pré-entraîné ou d'un répertoire de modèles local.
run_dir
définit le répertoire dans lequel les points de contrôle et les métriques de formation sont stockés.
seq_len
définit la longueur de la séquence pour la formation. Il s'agit de la longueur maximale des séquences d'entrée que le modèle traitera. Les échantillons sont emballés pour atteindre une longueur de seq_len
pour une efficacité de formation maximale.
batch_size
définit le nombre d'exemples de formation utilisés par GPU. Remarque : La taille effective globale de batch_size (en jetons) sur tous les GPU est égale à num_gpus
x batch_size
x seq_len
.
max_steps
définit le nombre maximum d'étapes d'entraînement. Il s'agit du nombre total d'itérations que le processus de formation exécutera. Il peut être ajusté en fonction des besoins spécifiques de votre scénario de formation. Le nombre total de jetons vus pendant la formation est max_steps
x num_gpus
x batch_size
x seq_len
.
optim.lr
définit le taux d'apprentissage. Il s'agit du taux d'apprentissage initial de l'optimiseur.
optim.weight_decay
définit la dégradation du poids. La dégradation du poids est une technique de régularisation utilisée pour éviter le surajustement en pénalisant les poids importants. Nous vous recommandons de le laisser à 0,1.
optim.pct_start
définit le pourcentage du total des étapes d'entraînement utilisé pour la phase d'échauffement du taux d'apprentissage avant qu'il ne commence à diminuer. Cela correspond à pct_start de OneCycleLR de PyTorch.
lora.rank
définit la taille des adaptateurs LoRA (Low-Rank Adaptation). Nous recommandons 64 ou moins, ce qui ajuste le rang de la décomposition de bas rang utilisée dans LoRA.
seed
définit la graine aléatoire pour l'initialisation et le brassage/échantillonnage des données. La définition d’une graine garantit la reproductibilité des résultats.
log_freq
définit la fréquence de journalisation. Ceci spécifie la fréquence (en étapes) à laquelle enregistrer les métriques d'entraînement.
data.instruct_data
est le chemin d'accès aux données d'instruction utilisées pour la formation. Ce champ doit être rempli avec une ou plusieurs sources de données au format expliqué ci-dessus. Chaque source de données doit être soit un chemin vers un fichier jsonl, soit un chemin vers un répertoire contenant des fichiers jsonl suivi d'une pondération pour définir l'importance de cet ensemble de données :
. Par exemple : data.instruct_data: "/path/to/data1.jsonl:5.,/path/to/data2.jsonl:1.,/path/to/dir_of_jsonls:1."
data.data
est un chemin facultatif vers des données de pré-entraînement supplémentaires dans le format expliqué ci-dessus. Notez que ce champ peut rester vide.
data.eval_instruct_data
est un chemin facultatif vers les données d'instruction d'évaluation pour exécuter une validation croisée à chaque étape eval_freq
. Les mesures de validation croisée sont affichées sous forme loss
et perplexity
.
eval_freq
définit la fréquence (en étapes) d'évaluation du modèle. Ceci spécifie l'intervalle auquel le modèle est évalué sur l'ensemble de validation.
no_eval
est un indicateur pour activer ou désactiver l'évaluation intermédiaire. Le définir sur False permet une évaluation périodique pendant la formation.
ckpt_freq
définit la fréquence (en étapes) de sauvegarde des points de contrôle. Ceci spécifie l'intervalle auquel l'état du modèle est enregistré.
save_adapters
définit s'il faut enregistrer uniquement les points de contrôle LoRA formés ou si le LoRA formé doit être directement fusionné dans le modèle de base et enregistré. Remarque : Lorsque vous définissez save_adapters=False
assurez-vous que vous disposez de suffisamment de mémoire CPU et GPU pour enregistrer le modèle complet sur un seul processus (cela n'est généralement possible que pour le modèle 7B).
wandb.key
est utilisé pour transmettre votre clé API Weights & Biases (wandb) pour la journalisation. Cela vous permet d'enregistrer les métriques de formation dans le tableau de bord wandb.
wandb.project
définit le nom du projet wandb. C'est ici que l'exécution de la formation sera enregistrée dans l'interface wandb.
Une fois votre modèle entraîné, vous devriez l'essayer en inférence. Nous vous recommandons d'utiliser l'inférence mistral.
Assurez-vous que mistral_inference
est correctement installé :
pip install mistral_inference
En supposant que votre lora.safetensors
soit enregistré sous $HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safetensors
, vous pouvez discuter avec le modèle en utilisant mistral_inference
, par exemple :
mistral-chat /mnt/slow/runs/patrick/mistral-finetune/7B/ --max_tokens 256 --temperature 1.0 --instruct --lora_path $HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safetensors
Nous avons ajouté une prise en charge explicite des poids et des biais pour vous aider à surveiller et visualiser vos entraînements. Cette intégration vous permet d'enregistrer diverses métriques et de suivre facilement les expériences.
Pour utiliser les poids et les biais avec mistral-finetune
, suivez ces étapes :
Installer les poids et les biais :
Assurez-vous que la bibliothèque wandb
est installée. Vous pouvez l'installer en utilisant pip :
pip installer baguette
Une fois la formation commencée, vous pouvez suivre les progrès en temps réel en visitant le tableau de bord de votre projet wandb. Toutes les mesures, y compris la perte de formation, la perte d'évaluation, le taux d'apprentissage, etc., seront enregistrées et visualisées.
Pour plus de détails sur l'utilisation de wandb, consultez la documentation Poids et biais.
Important : Notez que l'on ne peut affiner que les modèles Mistral compatibles avec le tokenizer v3, ce qui implique que les modèles ont une taille de vocabulaire de 32768 - et non de 32000. On peut cependant facilement étendre l'ancienne version de la taille de vocabulaire 32000 pour avoir une taille de vocabulaire de 32768 en utilisant :
python -m utils.extend_model_vocab --original_model_ckpt /folder/to/old/model --extended_model_ckpt /folder/to/extended/model
Une fois que l'extension a fonctionné, on peut affiner en utilisant le point de contrôle du modèle nouvellement créé dans /folder/to/extended/model
.
Quelle est la meilleure pratique pour affiner les MoE ?
Nous constatons un degré plus élevé de variance des performances lors du réglage fin des modèles MoE. Il n'est pas rare de constater qu'un réglage fin des modèles MoE avec différentes valeurs de départ peut entraîner une grande variation des performances. Nous n’avons pas observé une variance aussi élevée avec les modèles denses. Par conséquent, nous suggérons d’exécuter plusieurs instances du même processus de réglage fin sur les modèles MoE et de sélectionner celle qui fonctionne le mieux.
Comment puis-je déterminer le nombre de jetons utilisés pendant le processus de formation du modèle ?
Vous pouvez utiliser le script suivant pour le savoir : https://github.com/mistralai/mistral-finetune/blob/main/utils/validate_data.py. Ce script accepte un fichier de formation .yaml en entrée et renvoie le nombre de jetons sur lesquels le modèle est formé.
Que dois-je faire si je rencontre une erreur de manque de mémoire CUDA ?
Une solution possible consiste à réduire la taille des lots par GPU. La taille du lot est égale à seq_len
x batch_size
. Essayez de définir batch_size
sur 1 et réduisez seq_len
. Vous pouvez définir batch_size
et seq_len
dans le fichier .yaml.