mistral-finetune
es una base de código liviana que permite un ajuste fino de rendimiento y eficiencia de memoria de los modelos de Mistral. Se basa en LoRA, un paradigma de entrenamiento en el que la mayoría de los pesos se congelan y solo se entrena entre el 1 y el 2 % de los pesos adicionales en forma de perturbaciones de matriz de bajo rango.
Para obtener la máxima eficiencia, se recomienda utilizar una GPU A100 o H100. El código base está optimizado para configuraciones de entrenamiento de múltiples GPU y un solo nodo, pero para modelos más pequeños, como el 7B, una sola GPU es suficiente.
Nota
El objetivo de este repositorio es proporcionar un punto de entrada sencillo y guiado para ajustar los modelos Mistral. Como tal, es bastante obstinado (especialmente en lo que respecta al formato de datos) y no pretende ser exhaustivo en múltiples arquitecturas de modelos o tipos de hardware. Para enfoques más genéricos, puede consultar otros grandes proyectos como torchtune.
13.08.2024 : ¡Mistral Large v2 ahora es compatible con mistral-finetune
!
Se recomienda utilizar una tasa de aprendizaje más baja en comparación con otros modelos; por ejemplo , lr=1e-6 debería funcionar bien en la mayoría de los casos.
El ajuste fino de Mistral-Large v2 requiere mucha más memoria debido al mayor tamaño del modelo. Por ahora establezca seq_len
en <= 8192
Descargue la instrucción 123B aquí y configure model_id_or_path
en el directorio del punto de control descargado.
19.07.2024 : ¡Mistral Nemo ahora es compatible con mistral-finetune
!
Se recomienda utilizar los mismos hiperparámetros que para el 7B v3.
El ajuste fino de Mistral-Nemo requiere actualmente mucha más memoria debido a un mayor tamaño de vocabulario que aumenta el requisito máximo de memoria de la pérdida de CE (pronto agregaremos aquí una pérdida de CE mejorada). Por ahora establezca seq_len
en <= 16384
Ejecute pip install --upgrade mistral-common
para tener una versión que admita Tekkenizer ( >=1.3.1
).
Descargue 12B Base o Instruct aquí y configure model_id_or_path
en el directorio del punto de control descargado.
Para comenzar con el ajuste de Mistral LoRA, siga estos pasos:
Clona este repositorio:
cd $HOME && git clone https://github.com/mistralai/mistral-finetune.git
Instale todas las dependencias requeridas:
cd mistral-finetune pip install -r requirements.txt
Te recomendamos poner a punto uno de los modelos oficiales de Mistral que puedes descargar aquí:
Modelo | Enlace | Suma de comprobación |
---|---|---|
7B básico V3 | Base 7B | 0663b293810d7571dad25dae2f2a5806 |
7B Instruir v3 | 7B Instruir v3 | 80b71fcb6416085bcb4efad86dfb4d52 |
Base 8x7B V1 | Base 8x7B | (enlace HF) |
8x7B Instrucción V1 | Instrucción 8x7B | 8e2d3930145dc43d3084396f49d38a3f |
8x22 Instrucción V3 | 8x22 Instrucción | 471a02a6902706a2f1e44a693813855b |
8x22B BaseV3 | Base 8x22B | a2fa75117174f87d1197e3a4eb50371a |
12B Instruir | Instrucción 12B (Mistral-Nemo) | 296fbdf911cb88e6f0be74cd04827fe7 |
Base 12B | 12 Base (Mistral-Nemo) | c5d079ac4b55fc1ae35f51f0a3c0eb83 |
Mistral Grande 2 | Instrucción 123B (grande v2) | fc602155f9e39151fba81fcaab2fa7c4 |
Aviso importante : para 8x7B Base V1 y 8x7B Instruct V1, es necesario utilizar nuestro tokenizador v3 y ampliar el tamaño del vocabulario a 32768 antes de realizar el ajuste. Para obtener instrucciones detalladas sobre este proceso, consulte la sección "Extensión del modelo".
Por ejemplo, para descargar el modelo base 7B, puede ejecutar el siguiente comando:
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
Asegúrese de modificar su script de entrenamiento y agregar la ruta a la carpeta descargada como model_id_or_path
.
Por ejemplo, modifique example/7B.yaml para incluir la ruta absoluta a $HOME/mistral_models/7B
:
model_id_or_path: "/Users/johndoe/mistral_models/7B"
Para garantizar un entrenamiento eficaz, mistral-finetune
tiene requisitos estrictos sobre cómo se deben formatear los datos de entrenamiento.
Todos los archivos de datos deben almacenarse en archivos de formato jsonl.
Puede crear dos tipos de archivos de datos:
Los datos de preentrenamiento corresponden a datos de texto sin formato almacenados en la clave "text"
. P.ej:
{"text": "Texto contenido en el documento n°1"} {"text": "Texto contenido en el documento n°2"}
Actualmente se admiten dos tipos diferentes de instrucción con los siguientes datos:
Instruir : datos conversacionales almacenados en la clave "messages"
en forma de lista. Cada elemento de la lista es un diccionario que contiene las claves de "content"
y "role"
. "role"
es una cadena que puede ser "usuario", "asistente" o "sistema". La pérdida sólo se computará si "rol" == "asistente". P.ej:
{ "mensajes": [ { "role": "usuario", "content": "Interacción del usuario n°1 contenida en el documento n°1" }, { "role": "asistente", "content": "Interacción del bot n°1 contenida en el documento n°1" }, { "role": "usuario", "content": "Interacción del usuario n°2 contenida en el documento n°1" }, { "role": "asistente", "content": "Interacción del bot n°2 contenida en el documento n°1" } ] } { "mensajes": [ { "role": "usuario", "content": "Interacción del usuario n°1 contenida en el documento n°2" }, { "role": "asistente", "content": "Interacción del bot n°1 contenida en el documento n°2" }, { "role": "usuario", "content": "Interacción del usuario n°2 contenida en el documento n°2" }, { "role": "asistente", "content": "Interacción del bot n°2 contenida en el documento n°2", "peso": 0, # no entrenar en el n°2 }, { "role": "usuario", "content": "Interacción del usuario n°3 contenida en el documento n°2" }, { "role": "asistente", "content": "Interacción del bot n°3 contenida en el documento n°2" } ] }
Llamada de función : datos conversacionales almacenados en la tecla "messages"
en forma de lista. Cada elemento de la lista es un diccionario que contiene las claves "role"
y "content"
o "tool_calls"
. "role"
es una cadena que incluye "usuario", "asistente", "sistema" o "herramienta". La pérdida sólo se computará si "rol" == "asistente".
Nota : En la función que llama al "id"
de "tool_calls"
y al "tool_call_id"
se generan aleatoriamente cadenas de exactamente 9 caracteres. Recomendamos generar esto automáticamente en un script de preparación de datos como se hace aquí.
P.ej:
{ "mensajes": [ { "role": "system", "content": "Usted es un asistente útil que tiene acceso a las siguientes funciones para ayudar al usuario; puede usar las funciones si es necesario" }, { "role": "usuario", "content": "¿Puedes ayudarme a generar un anagrama de la palabra "escuchar"?" }, { "rol": "asistente", "tool_calls": [ { "id": "TX92Jm8Zi", "tipo": "función", "función": { "nombre": "generar_anagrama", "argumentos": "{"palabra": "escuchar"}" } } ] }, { "role": "herramienta", "content": "{"anagrama": "silent"}", "tool_call_id": "TX92Jm8Zi" }, { "role": "asistente", "content": "El anagrama de la palabra "escuchar" es "silencioso"." }, { "role": "usuario", "content": "¡Eso es increíble! ¿Puedes generar un anagrama para la palabra "raza"?" }, { "rol": "asistente", "tool_calls": [ { "id": "3XhQnxLsT", "tipo": "función", "función": { "nombre": "generate_anagram", "argumentos": "{"palabra": "raza"}" } } ] } ], "herramientas": [ { "tipo": "función", "función": { "nombre": "generar_anagrama", "descripción": "Generar un anagrama de una palabra determinada", "parámetros": { "tipo": "objeto", " properties": { "palabra": { "tipo": "cadena", "descripción": "La palabra para generar un anagrama de" } }, "obligatorio": [ "palabra" ] } } } ] }
Antes de iniciar una ejecución de entrenamiento, debe verificar que su conjunto de datos esté formateado correctamente y obtener una estimación del tiempo de entrenamiento. Puede hacerlo utilizando el script ./utils/validate_data.
Tenga en cuenta que este paso es crucial para garantizar que los datos tengan el formato correcto.
Repasemos un ejemplo simple para entrenar un modelo con las siguientes instrucciones:
Cargue una parte de Ultachat_200k
Cree la carpeta de datos y navegue hasta la carpeta.
cd $INICIO && mkdir -p datos && cd $INICIO/datos
Cargue los datos en un Pandas Dataframe.
Nota : asegúrese de tener pandas y pyarrow instalados ( pip install pandas pyarrow
).
importar pandas como pddf = pd.read_parquet('https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k/resolve/main/data/test_gen-00000-of-00001-3d4cd8309148a71f.parquet')
Dividir en tren y evaluación
df_train=df.sample(frac=0.95,random_state=200)df_eval=df.drop(df_train.index)
Guardar datos en jsonl
df_train.to_json("ultrachat_chunk_train.jsonl", orient="records", líneas=True)df_eval.to_json("ultrachat_chunk_eval.jsonl", orient="records", líneas=True)
Modifique su yaml de entrenamiento para incluir el conjunto de datos de ultrachat y verifique el yaml
Modifique example/7B.yaml para incluir la ruta absoluta a $HOME/data/ultrachat_chunk_train.jsonl
así como un conjunto de datos que combine el peso para entrenamiento y $HOME/data/ultrachat_chunk_eval.jsonl
para evaluación, por ejemplo
data: instruct_data: "/Users/johndoe/data/ultrachat_chunk_train.jsonl" eval_instruct_data: "/Users/johndoe/data/ultrachat_chunk_eval.jsonl"
Ahora puede verificar su yaml de entrenamiento para asegurarse de que los datos tengan el formato correcto y obtener una estimación de su tiempo de entrenamiento.
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml
Al finalizar, debería ver un informe de errores con muchos de los siguientes errores:
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
Muchas conversaciones parecen terminar con el rol de "usuario", lo cual es innecesario ya que solo entrenamos con mensajes de "asistente" y, por lo tanto, procesaríamos datos innecesariamente.
Puede utilizar ./utils/reformat_data.py para corregir los datos:
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
Deberías ver que se omitirán un par de muestras.
Potencialmente cambiar el número de pasos de entrenamiento
Tras la corrección del conjunto de datos, ejecute el script nuevamente
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml
Debería obtener un resumen de la entrada de datos y los parámetros de entrenamiento:
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" } }, }
Tener max_steps
establecido en 500 llevaría a iterar a través del conjunto de datos aproximadamente 5 veces, lo cual es razonable, pero podría ser demasiado. A continuación se muestra una configuración recomendada que solo tomaría 30 minutos en un clúster 8xH100.
A continuación, repasemos un caso de uso más avanzado para ajustar un modelo en la llamada a funciones. La llamada a funciones requiere que los datos estén en el formato explicado anteriormente. Repasemos un ejemplo.
Cargue una versión con formato de chat de la función Glaive que llama al conjunto de datos
Cree la carpeta de datos y navegue hasta la carpeta.
cd $INICIO && mkdir -p datos && cd $INICIO/datos
Cargue los datos en un Pandas Dataframe.
Nota : asegúrese de tener pandas y pyarrow instalados ( pip install pandas pyarrow
).
importar pandas como pddf = pd.read_parquet('https://huggingface.co/datasets/Locutusque/function-calling-chatml/resolve/main/data/train-00000-of-00001-f0b56c6983b4a78f.parquet')
Dividir en tren y evaluación
df_train=df.sample(frac=0.95,random_state=200)df_eval=df.drop(df_train.index)
Guardar datos en jsonl
df_train.to_json("glaive_train.jsonl", orient="records", líneas=True)df_eval.to_json("glaive_eval.jsonl", orient="records", líneas=True)
Reformatear conjunto de datos
Como se puede ver, el conjunto de datos no sigue el formato de llamada de función requerido, por lo que será necesario reformatearlo. Entre otras cosas, se debe cambiar el nombre "from"
a "user"
y se deben eliminar los caracteres "n"
superfluos. Para este conjunto de datos, puede utilizar ./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
La ejecución de este comando garantizará que la mayoría de las muestras estén en el formato correcto.
Nota : Es imposible escribir scripts de reformateo que funcionen para todo tipo de conjuntos de datos. Si tiene conjuntos de datos que aún no siguen el formato requerido anteriormente, lo más probable es que tenga que crear un script de reformateo usted mismo (¡mistral-chat o chat-gpt son sus mejores amigos aquí!).
Validar conjunto de datos
Ahora puede validar el conjunto de datos configurando data.instruct_data
y data.eval_instruct_data
en $HOME/data/glaive_train.jsonl
y $HOME/data/glaive_eval.jsonl
en example/7B.yaml
respectivamente.
Los conjuntos de datos reformateados todavía tienen algunos errores que se pueden eliminar con --create_corrected
. Para esto, asegúrese de agregar --create_corrected
de la siguiente manera:
cd $HOME/mistral-finetune python -m utils.validate_data --train_yaml example/7B.yaml --create_corrected
La ejecución de este comando mostrará un par de errores y guardará dos nuevos conjuntos de datos $HOME/data/glaive_train.jsonl.corrected
y $HOME/data/glaive_eval.jsonl.corrected
. Asegúrese de utilizar estos dos conjuntos de datos en example/7B.yaml
y ejecute el comando nuevamente. ¡Ahora el conjunto de datos debería tener el formato correcto!
Habiendo seguido la sección de verificación del conjunto de datos, ahora podemos comenzar a entrenar. Para un entrenamiento más rápido, recomendamos configurar max_steps en solo 300. Asegúrese de definir run_dir
en su carpeta de experimentos y, opcionalmente, configure wandb_project
en un proyecto de Pesos y sesgos para iniciar sesión, por ejemplo :
max_steps: 300 run_dir: "/Users/johndoe/ultra_chat_test" wandb.project: ultra_chat
Opcionalmente también puedes configurar wandb
¡Guarda la configuración del entrenamiento y comienza a entrenar! Asegúrese de configurar --nproc-per-node
en la cantidad de GPU disponibles.
cd $HOME/mistral-finetune torchrun --nproc-per-node 8 --master_port $RANDOM -m train example/7B.yaml
El entrenamiento en ultra-chat debería durar unos 30 minutos en un nodo 8xH100 y los pesos resultantes deberían dar una puntuación MT Bench de alrededor de 6,3.
El entrenamiento en Glaive debería tomar alrededor de 1 hora en un nodo 8xH100 y los pesos resultantes deberían funcionar bien para la llamada de funciones.
El ejemplo mistral-finetune/examples/7B
define parámetros razonables para la tasa de aprendizaje, la disminución del peso, etc... pero se recomienda personalizar estas configuraciones para su caso de uso.
Generalmente, una configuración de entrenamiento debe cumplir con los siguientes parámetros:
model_id_or_path
define el modelo desde el que comenzar a entrenar. Puede ser una ruta a un modelo previamente entrenado o a un directorio de modelos local.
run_dir
define el directorio donde se almacenan los puntos de control y las métricas de entrenamiento.
seq_len
define la longitud de la secuencia para el entrenamiento. Esta es la longitud máxima de secuencias de entrada que procesará el modelo. Las muestras se empaquetan para alcanzar una longitud de seq_len
para lograr la máxima eficiencia del entrenamiento.
batch_size
define la cantidad de ejemplos de entrenamiento utilizados por GPU. Nota : El tamaño de lote efectivo general (en tokens) en todas las GPU es igual a num_gpus
x batch_size
x seq_len
.
max_steps
define el número máximo de pasos de entrenamiento. Este es el número total de iteraciones que ejecutará el proceso de formación. Se puede ajustar en función de las necesidades específicas de su escenario de entrenamiento. La cantidad total de tokens vistos durante el entrenamiento es max_steps
x num_gpus
x batch_size
x seq_len
.
optim.lr
define la tasa de aprendizaje. Esta es la tasa de aprendizaje inicial del optimizador.
optim.weight_decay
define la caída del peso. La caída de peso es una técnica de regularización que se utiliza para evitar el sobreajuste penalizando pesos grandes. Recomendamos dejarlo en 0,1.
optim.pct_start
define el porcentaje del total de pasos de entrenamiento utilizados para la fase de calentamiento de la tasa de aprendizaje antes de que comience a disminuir. Corresponde a pct_start de OneCycleLR de PyTorch.
lora.rank
define el tamaño de los adaptadores LoRA (adaptación de rango bajo). Recomendamos 64 o menos, lo que ajusta el rango de la descomposición de rango bajo utilizada en LoRA.
seed
define la semilla aleatoria para la inicialización y la mezcla/muestreo de datos. Establecer una semilla garantiza la reproducibilidad de los resultados.
log_freq
define la frecuencia de registro. Esto especifica con qué frecuencia (en pasos) se deben registrar las métricas de entrenamiento.
data.instruct_data
es la ruta a los datos de instrucción utilizados para el entrenamiento. Este campo debe completarse con una o varias fuentes de datos en el formato explicado anteriormente. Cada fuente de datos debe ser una ruta a un archivo jsonl o una ruta a un directorio que contenga archivos jsonl seguida de una ponderación para definir la importancia de este conjunto de datos:
. Por ejemplo: data.instruct_data: "/path/to/data1.jsonl:5.,/path/to/data2.jsonl:1.,/path/to/dir_of_jsonls:1."
data.data
es una ruta opcional a datos de preentrenamiento adicionales en el formato explicado anteriormente. Tenga en cuenta que este campo se puede dejar en blanco.
data.eval_instruct_data
es una ruta opcional a los datos de las instrucciones de evaluación para ejecutar una validación cruzada en cada paso eval_freq
. Las métricas de validación cruzada se muestran como loss
y perplexity
.
eval_freq
define con qué frecuencia (en pasos) se evalúa el modelo. Esto especifica el intervalo en el que se evalúa el modelo en el conjunto de validación.
no_eval
es un indicador para habilitar o deshabilitar la evaluación intermedia. Establecerlo en False permite la evaluación periódica durante el entrenamiento.
ckpt_freq
define con qué frecuencia (en pasos) se guardan los puntos de control. Esto especifica el intervalo en el que se guarda el estado del modelo.
save_adapters
define si solo se guardan los puntos de control de LoRA entrenados o si el LoRA entrenado debe fusionarse directamente en el modelo base y guardarse. Nota : Al configurar save_adapters=False
, asegúrese de tener suficiente memoria de CPU y GPU para guardar el modelo completo en un solo proceso (esto generalmente solo es posible para el modelo 7B).
wandb.key
se utiliza para pasar su clave API de Weights & Biases (wandb) para iniciar sesión. Esto le permite registrar métricas de entrenamiento en el panel de wandb.
wandb.project
define el nombre del proyecto wandb. Aquí es donde se registrará la ejecución de entrenamiento en la interfaz wandb.
Una vez que su modelo esté entrenado, debe probarlo en inferencia. Recomendamos utilizar la inferencia mistral.
Asegúrese de tener mistral_inference
correctamente instalado:
pip install mistral_inference
Suponiendo que su lora.safetensors
esté guardado en $HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safetensors
, puede chatear con el modelo usando mistral_inference
, por ejemplo :
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
Hemos agregado soporte explícito para Pesos y Sesgos para ayudarte a monitorear y visualizar tus carreras de entrenamiento. Esta integración le permite registrar varias métricas y realizar un seguimiento de experimentos fácilmente.
Para utilizar Pesos y Sesgos con mistral-finetune
, siga estos pasos:
Instalar pesos y sesgos:
Asegúrese de tener instalada la biblioteca wandb
. Puedes instalarlo usando pip:
pip instalar wandb
Una vez que comienza la capacitación, puede monitorear el progreso en tiempo real visitando el panel de su proyecto wandb. Todas las métricas, incluida la pérdida de capacitación, la pérdida de evaluación, la tasa de aprendizaje, etc., se registrarán y visualizarán.
Para obtener más detalles sobre cómo usar wandb, visite la documentación de Pesos y sesgos.
Importante : tenga en cuenta que solo se pueden ajustar los modelos de Mistral que sean compatibles con el tokenizador v3, lo que implica que los modelos tengan un tamaño de vocabulario de 32768, no 32000. Sin embargo, se puede ampliar fácilmente la versión anterior del tamaño de vocabulario 32000 para que tenga un tamaño de vocabulario. de 32768 usando:
python -m utils.extend_model_vocab --original_model_ckpt /folder/to/old/model --extended_model_ckpt /folder/to/extended/model
Una vez que la extensión ha funcionado, se puede realizar un ajuste fino utilizando el punto de control del modelo recién creado en /folder/to/extended/model
.
¿Cuál es la mejor práctica para ajustar los MoE?
Vemos un mayor grado de variación de rendimiento al ajustar los modelos MoE. No es inusual encontrar que ajustar los modelos MoE con diferentes semillas puede generar una gran variación en el rendimiento. No observamos una variación tan alta con modelos densos. Por lo tanto, sugerimos ejecutar varias instancias del mismo proceso de ajuste en los modelos MoE y seleccionar la que funcione mejor.
¿Cómo puedo determinar la cantidad de tokens utilizados durante el proceso de capacitación del modelo?
Puede utilizar el siguiente script para averiguarlo: https://github.com/mistralai/mistral-finetune/blob/main/utils/validate_data.py. Este script acepta un archivo de entrenamiento .yaml como entrada y devuelve la cantidad de tokens en los que se está entrenando el modelo.
¿Qué debo hacer si encuentro un error de falta de memoria de CUDA?
Una posible solución es reducir el tamaño del lote por GPU. El tamaño del lote es igual a seq_len
x batch_size
. Intente configurar batch_size
en 1 y reduzca seq_len
. Puede definir el batch_size
y seq_len
en el archivo .yaml.