paint-brush
alpaca-lora: experimentando con un modelo de lenguaje grande caseropor@ishootlaser
4,390 lecturas
4,390 lecturas

alpaca-lora: experimentando con un modelo de lenguaje grande casero

por Wei18m2023/10/16
Read on Terminal Reader

Demasiado Largo; Para Leer

Los modelos de lenguajes grandes (LLM) están revolucionando el desarrollo de software, mejorando las interacciones de los usuarios con herramientas como LangChain y Semantic Kernel. Pueden ayudar en varias etapas de la creación de contenido y agilizar procesos complejos. Sin embargo, las preocupaciones sobre la dependencia de los proveedores de LLM, la censura de contenido y las opciones de personalización han llevado a la búsqueda de alternativas de código abierto. El artículo explora un método de ajuste para capacitar a su propio LLM, alpaca-lora, y ofrece información sobre el proceso, los desafíos y las posibles soluciones, particularmente para lograr un ajuste exitoso en hardware como las GPU V100. El objetivo es crear LLM que produzcan respuestas coherentes y contextualmente relevantes evitando al mismo tiempo la repetición rápida.
featured image - alpaca-lora: experimentando con un modelo de lenguaje grande casero
Wei HackerNoon profile picture
0-item


Los modelos de lenguaje grande (LLM) se han convertido en la palabra de moda en el desarrollo de software desde el lanzamiento de ChatGPT. Su capacidad para mantener conversaciones naturales con los humanos es sólo la punta del iceberg. Mejorados con herramientas como LangChain o Semantic Kernel, los LLM tienen el potencial de cambiar completamente la forma en que los usuarios interactúan con el software. En otras palabras, los LLM pueden crear sinergias entre funcionalidades y fuentes de datos, y proporcionar una experiencia de usuario más eficiente e intuitiva.


Por ejemplo, muchas personas ya están utilizando herramientas de creación de contenido basadas en inteligencia artificial para sus próximos videos virales. Un proceso típico de producción de vídeo incluye guiones, logística, guiones gráficos, edición y marketing, solo por nombrar algunos. Para agilizar el proceso, un LLM podría ayudar a los creadores de contenido con la investigación mientras escriben guiones, comprar accesorios para el rodaje, generar guiones gráficos basados en el guión (puede necesitar una difusión estable para la generación de imágenes), facilitar el proceso de edición y escribir títulos llamativos. /Descripciones de vídeos para atraer visitas en las redes sociales. Los LLM son el núcleo que organiza todo esto, pero podrían surgir varias preocupaciones al incorporar LLM en un producto de software:


  1. Si uso la API de OpenAI, ¿me volveré demasiado dependiente de este servicio? ¿Y si suben el precio? ¿Qué pasa si cambian la disponibilidad del servicio?


  2. No me gusta cómo OpenAI censura el contenido o proporciona comentarios no constructivos sobre ciertas aportaciones de los usuarios. (O al revés: no me gusta cómo la censura de OpenAI ignora ciertas cosas que son delicadas en mi caso de uso).


  3. Si mis clientes prefieren la nube privada o la implementación local, ¿qué alternativas de ChatGPT tengo?


  4. Sólo quiero tener el control. Necesito personalizar el LLM y lo quiero barato.


Es por estas preocupaciones que me pregunto si podría haber un equivalente de código abierto de los modelos GPT de OpenAI. Afortunadamente, las maravillosas comunidades de código abierto ya están compartiendo algunas soluciones muy prometedoras. Decidí probar alpaca-lora , un método de ajuste eficiente de parámetros para entrenar tu propio LLM. Esta publicación de blog analiza el proceso, los problemas que encontré, cómo los resolví y qué podría pasar a continuación. Si también quieres utilizar la técnica para formar tu propio LLM, espero que la información te pueda ayudar.


¡Vamos a empezar!


Descripción general del contenido

  • ¿Qué es LLaMA, alpaca y LoRA?
  • El experimento de ajuste fino
    • Escaneando rápidamente el código fuente
    • El primer intento
    • La primera observación
    • El segundo intento y el (algo) éxito
    • Más allá de 7B
  • Resumen


¿Qué es LLaMA, alpaca y LoRA?

LLaMA es una colección de modelos de lenguaje básicos de Meta AI. Estos modelos autorregresivos tienen recuentos de parámetros que van de 7B a 65B y solo pueden usarse con fines de investigación. Meta lanzó recientemente LLaMA 2 , que puede usarse comercialmente con algunas limitaciones. Lo que hace especial a la familia de modelos LLaMA es su corpus de entrenamiento y su rendimiento. Meta afirma que LLaMA está capacitado en conjuntos de datos disponibles públicamente. Su variante 13B logra un rendimiento comparable al GPT-3 (un modelo 175B) en la mayoría de los puntos de referencia.


alpaca es el intento de Stanford de construir un LLM que siga instrucciones basado en LLaMA. Funciona así:


  1. Pídale a un modelo de lenguaje que genere tripletes instrucción-entrada-respuesta.

  2. Utilice los datos generados para ajustar LLaMA.


Después del ajuste, LLaMA puede seguir las instrucciones del usuario y responder en consecuencia.


Aquí hay una comparación entre la respuesta de LLaMA básica y la respuesta de LLaMA afinada:

 { "instruction": "Answer user's question.", "input": "Can you put a medium voltage circuit breaker in a low voltage switchgear? Why? Explain in detail.", "vanilla LLaMA": { "answer": "Yes, you can put a medium voltage circuit breaker in a low voltage switchgear. The medium voltage circuit breaker can be put in a low voltage switchgear because the medium voltage circuit breaker can be put in a low voltage switchgear because the medium voltage circuit breaker can be put in a low voltage switchgear because the medium voltage circuit breaker can be put....(repetition continues)" }, "fine-tuned LLaMA": { "answer": "No, it is not possible to put a medium voltage circuit breaker in a low voltage switchgear. This is because low voltage switchgear is designed to handle voltages up to 1 kV, while medium voltage switchgear is designed to handle voltages from 1 kV to 38 kV. The circuit breakers, contacts, and other components in low voltage switchgear are not suitable for the higher voltages and currents of medium voltage switchgear. Using a medium voltage circuit breaker in a low voltage switchgear could result in damage to the components and could pose a safety hazard." } }


Como puede ver, el ajuste fino cambia drásticamente el comportamiento de LLM. El modelo básico está atrapado en un bucle de repetición. Si bien el modelo ajustado no arrojó una respuesta 100% correcta, al menos su respuesta es un rotundo "No". El ajuste fino es un paso necesario para producir LLM utilizable. En muchos casos, es suficiente implementar un LLM optimizado de código abierto. Sin embargo, en algunos casos de uso empresarial personalizados, puede ser preferible ajustar los modelos en conjuntos de datos de dominios específicos.


El mayor inconveniente de la alpaca es su necesidad de recursos. Su página de GitHub afirma que:

Ingenuamente, ajustar un modelo 7B requiere aproximadamente 7 x 4 x 4 = 112 GB de VRAM.


Esto es más VRAM de lo que puede manejar una GPU A100 de 80 GB. Podemos evitar el requisito de VRAM usando LoRA .


LoRA funciona así:

  1. Seleccione algunos pesos en un modelo, como el peso de proyección de consulta $W_q$ en un modelo de transformador. Agregue (sí, suma aritmética) pesos adaptadores a los pesos seleccionados.
  2. Congele el modelo original, entrene solo el peso agregado.


El peso añadido tiene algunas propiedades especiales. Inspirándose en este artículo , Edward Hu et al. demostró que para un peso del modelo original $W_o\in R^{d \times k}$, se puede producir un peso ajustado $W_o'=W_o+BA$ para tareas posteriores, donde $B\in R^{d \times r}$ , $A \in R^{r \times k}$ y $r\ll min(d, k)$ es el "rango intrínseco" del peso del adaptador. Es importante establecer un $r$ adecuado para el peso del adaptador, ya que un $r$ más pequeño reduce el rendimiento del modelo y un $r$ más grande aumenta el tamaño del peso del adaptador sin una ganancia proporcional de rendimiento.


Esta técnica es similar a la SVD truncada, que aproxima una matriz descomponiéndola en varias matrices más pequeñas y manteniendo solo unos pocos valores singulares más grandes. Suponiendo $W_o\in R^{100 \times 100}$, un ajuste completo cambiaría 10.000 parámetros. El ajuste fino de LoRA con $r=8$ descompondría el peso ajustado en 2 partes, $B\in R^{100 \times 8}$ y $A\in R^{8 \times 100}$, cada una La parte contiene 800 parámetros (1600 parámetros en total). El número de parámetros entrenables se reduce 6,25 veces.


Después de transformar el modelo con LoRA, obtuvimos un modelo que tiene solo ~1% de pesos entrenables, pero su rendimiento ha mejorado enormemente en ciertos dominios. Esto nos permitiría entrenar modelos 7B o 13B en hardware más accesible como RTX 4090 o V100.


El experimento de ajuste fino

Ejecuté el experimento en Huawei Cloud con una instancia de VM acelerada por GPU ( p2s.2xlarge , 8vCPU, 64 GB de RAM, 1x V100 de 32 GB de VRAM). Se sabe que V100 no admite el tipo de datos bfloat16 y su núcleo tensor no admite int8. aceleración. Estos 2 límites pueden ralentizar el entrenamiento de precisión mixta y provocar un desbordamiento numérico durante el entrenamiento de precisión mixta. Tendremos esto en cuenta para una discusión posterior.

Escaneando rápidamente el código fuente

finetune.py y generate.py son el núcleo del proyecto. El primer script ajusta los modelos LLaMA y el segundo script utiliza el modelo ajustado para chatear con los usuarios. Primero echemos un vistazo al flujo principal de finetune.py :


  1. cargar un modelo de base grande previamente entrenado
 model = LlamaForCausalLM.from_pretrained( base_model, # name of a huggingface compatible LLaMA model load_in_8bit=True, torch_dtype=torch.float16, device_map=device_map, )


  1. cargar el tokenizador del modelo
 tokenizer = LlamaTokenizer.from_pretrained(base_model) tokenizer.pad_token_id = ( 0 # unk. we want this to be different from the eos token ) tokenizer.padding_side = "left" # Allow batched inference


  1. Según la plantilla de entrenamiento, prepare las entradas del modelo con dos funciones, tokenize y generate_and_tokenize_prompt .


  2. cree un modelo adaptado a LoRA utilizando PEFT de huggingface

 config = LoraConfig( r=lora_r, # the lora rank lora_alpha=lora_alpha, # a weight scaling factor, think of it like learning rate target_modules=lora_target_modules, # transformer modules to apply LoRA to lora_dropout=lora_dropout, bias="none", task_type="CAUSAL_LM", ) model = get_peft_model(model, config)


  1. crear una instancia de entrenador y comenzar a entrenar
 trainer = transformers.Trainer( model=model, train_dataset=train_data, eval_dataset=val_data, args=transformers.TrainingArguments( ...


Esto es bastante simple.


Al final, el script genera una carpeta de modelo con puntos de control, pesos del adaptador y configuración del adaptador.


A continuación, veamos el flujo principal de generate.py :


  1. Pesos del modelo y del adaptador de carga.
 model = LlamaForCausalLM.from_pretrained( base_model, device_map={"": device}, torch_dtype=torch.float16, ) model = PeftModel.from_pretrained( model, lora_weights, device_map={"": device}, torch_dtype=torch.float16, )


  1. especificar configuración de generación
 generation_config = GenerationConfig( temperature=temperature, top_p=top_p, top_k=top_k, num_beams=num_beams, **kwargs, ) generate_params = { "input_ids": input_ids, "generation_config": generation_config, "return_dict_in_generate": True, "output_scores": True, "max_new_tokens": max_new_tokens, }


  1. Defina funciones para el modo de generación de streaming y no streaming:
 if stream_output: # streaming ... # Without streaming with torch.no_grad(): generation_output = model.generate( input_ids=input_ids, generation_config=generation_config, return_dict_in_generate=True, output_scores=True, max_new_tokens=max_new_tokens, ) s = generation_output.sequences[0] output = tokenizer.decode(s) yield prompter.get_response(output)


  1. Inicie un servidor Gradio para probar el modelo:
 gr.Interface( ...


El primer intento

El README.md del proyecto declaró que las siguientes configuraciones de ajuste producen un LLaMA 7B con un rendimiento comparable al de la alpaca de Stanford. Se compartió un peso "oficial" de alpaca-lora en huggingface.


 python finetune.py \ --base_model='decapoda-research/llama-7b-hf' \ --num_epochs=10 \ --cutoff_len=512 \ --group_by_length \ --output_dir='./lora-alpaca' \ --lora_target_modules='[q_proj,k_proj,v_proj,o_proj]' \ --lora_r=16 \ --micro_batch_size=8


Sin embargo, según mi experiencia, no produjo un modelo utilizable. Al ejecutarlo en un V100 se encontrarán los siguientes problemas espectaculares:


  1. cargar el modelo con load_in_8bit provoca un error de tipo de datos.
  2. un script vinculante hará que PEFT produzca un adaptador no válido. El adaptador no válido no realiza ningún cambio en el modelo LLaMA original y solo produce galimatías.
  3. el modelo decapoda-research/llama-7b-hf aparentemente usó el tokenizador incorrecto. Su token pad, token bos y token eos son diferentes del tokenizador oficial de LLaMA.
  4. Como se mencionó anteriormente, V100 carece de soporte adecuado para el entrenamiento mixto int8/fp16. Esto provoca comportamientos inesperados, como training loss = 0.0 y eval loss = NaN .


Después de investigar y desperdiciar numerosas horas de VM, encontré los cambios necesarios para que la capacitación funcione en un solo V100.

 ... # do not use decapoda-research/llama-7b-hf as base_model. use a huggingface LLaMA model that was properly converted and has a correct tokenizer, eg, yahma/llama-7b-hf or huggyllama/llama-7b. # decapoda-research/llama-7b-hf is likely to cause overflow/underflow on V100. train loss goes to 0 and eval loss becomes NaN. using yahma/llama-7b-hf or huggyllama/llama-7b somehow mitigates this issue model = LlamaForCausalLM.from_pretrained( base_model, load_in_8bit=True, # only work for 7B LLaMA. On a V100, set True to save some VRAM at the cost of slower training; set False to speed up training at the cost of more VRAM / smaller micro batch size torch_dtype=torch.float16, device_map=device_map, ) ... # comment out the following line if load_in_8bit=False model = prepare_model_for_int8_training(model) ... # set legacy=False to avoid unexpected tokenizer behavior. make sure no tokenizer warning was raised during tokenizer instantiation tokenizer = LlamaTokenizer.from_pretrained(base_model, legacy=False) ... # the following binding script results in invalid adapter. simply comment them out old_state_dict = model.state_dict model.state_dict = ( lambda self, *_, **__: get_peft_model_state_dict( self, old_state_dict() ) ).__get__(model, type(model)) ... # if load_in_8bit=True, need to cast data type during training with torch.autocast('cuda'): trainer.train(resume_from_checkpoint=resume_from_checkpoint)


Después de realizar estos cambios, estos argumentos de entrenamiento producen un modelo utilizable.

 { "args": [ "--base_model", "yahma/llama-7b-hf", "--num_epochs=10", "--data_path", "yahma/alpaca-cleaned", "--output_dir", "./your output dir", "--cutoff_len=512", "--lora_target_modules=[q_proj,k_proj,v_proj,o_proj]", "--lora_r=16", "--micro_batch_size=2", "--batch_size=16", "--wandb_project", "your wandb project name" ], }


Tenga en cuenta que el script de entrenamiento no solo guarda el "mejor" modelo (punto de control con la pérdida de evaluación más baja), sino también un par de puntos de control. Utilicé wandb para registrar las pérdidas de entrenamiento/evaluación para su posterior análisis.


La primera observación

Lanzo algunas preguntas aleatorias al modelo ajustado. Produce algunas respuestas razonables.


Aquí hay un ejemplo:

Instrucción: Responda atentamente la pregunta del usuario.


Entrada: ¿Qué sucede cuando se desconecta un camión con disyuntor de aparamenta?


Respuesta: Cuando se "desmonta" un camión con disyuntor de aparamenta, significa que todos los disyuntores del camión se han abierto y el camión se encuentra en un estado no energizado. Por lo general, esto se hace cuando se realiza el mantenimiento, reparación o inspección del camión. Una vez que se han extraído los disyuntores, es seguro trabajar en el camión y se puede volver a energizar una vez que se hayan completado el mantenimiento o las reparaciones necesarias.


Este ejemplo cuestiona el conocimiento interno del LLM. El modelo parecía saber mucho sobre aparamentas. Sin embargo, cuando intenté probar empíricamente su capacidad de razonamiento, obtuve un resultado muy extraño:


Instrucción:


Dada la siguiente información sobre un proyecto, responda las preguntas. El proyecto Chinese-Llama-2 tiene como objetivo mejorar las capacidades de comprensión, generación y traducción del modelo de lenguaje grande Llama-2 en idioma chino. Con la aplicación de métodos como el ajuste fino de LoRA, el ajuste fino de instrucciones de parámetros completos y el preentrenamiento secundario, lo invitamos cordialmente a descargar y utilizar los conjuntos de datos, guías de capacitación y parámetros del modelo asociados.


Entrada: ¿Qué métodos se utilizan en este proyecto?


Respuesta: El proyecto Chinese-Llama-2 tiene como objetivo mejorar las capacidades de comprensión, generación y traducción del modelo de lenguaje grande Llama-2 en idioma chino. Con la aplicación de métodos como el ajuste fino de LoRA, el ajuste fino de instrucciones de parámetros completos y el preentrenamiento secundario, lo invitamos cordialmente a descargar y utilizar los conjuntos de datos, guías de capacitación y parámetros del modelo asociados.</s>


Como puede ver, a la modelo le gusta repetir el mensaje. Lo llamo modelo de repetidor de avisos y otros desarrolladores también habían informado de este comportamiento en los problemas del repositorio . Su capacidad para responder preguntas solo mejora con indicaciones diseñadas más cuidadosamente. Este comportamiento no es lo que queremos en un sistema de producción, ya que no podemos garantizar una eficacia rápida en diferentes modelos. Los modelos tienen que ser menos sensibles a las indicaciones. Queremos mejorar de alguna manera el desempeño de este LLM.


En la próxima sesión, analizaré la causa de este problema y cómo mejorar los resultados del ajuste.

El segundo intento y el (algo) éxito

Aquí hay 3 cosas que intenté mejorar al ajustar el resultado:


  1. Ocultar la pérdida en las indicaciones (ayuda a evitar la repetición de las indicaciones)

  2. Desactive la opción group-by-length (ayuda a mejorar el rendimiento y hace que la curva de pérdidas parezca más fluida)

  3. No confíe en la curva de pérdida de evaluación. Utilice un punto de control que tenga una pérdida de entrenamiento menor, aunque su pérdida de evaluación pueda ser mayor que la del "mejor" punto de control. (ayuda a mejorar el rendimiento, ya que la pérdida de evaluación no es la mejor matriz aquí)


Expliquemos estos 3 puntos uno por uno.

Enmascarar la pérdida en las indicaciones

Estaba buscando las causas de la repetición rápida hasta que encontré esta publicación y el mensaje oficial de confirmación de pesos de lora . Sugirieron que las indicaciones deberían excluirse del cálculo de pérdidas. Básicamente, no desea alentar al modelo a generar tokens de aviso. Ocultar las indicaciones durante el entrenamiento no alentaría al modelo a repetir las fichas de indicaciones. El siguiente cuadro explica esto: de las 3 ejecuciones de entrenamiento, stoic-star-6 es la única ejecución que no enmascaró las indicaciones durante el entrenamiento. Por tanto, su pérdida de entrenamiento es mayor al principio. Sospecho que si a) las indicaciones no están enmascaradas al calcular la pérdida yb) el entrenamiento es insuficiente, será más probable que el modelo repita las indicaciones en lugar de seguir instrucciones.


En el código fuente, el enmascaramiento de pérdidas se realiza estableciendo tokens de aviso en -100:

Los tokens con índices establecidos en -100 se ignoran (enmascaran), la pérdida solo se calcula para los tokens con etiquetas en [0, ..., config.vocab_size] .


Desactivar la opción group-by-length

La opción group-by-length permite Trainer de Huggingface agrupar entradas de longitud similar en lotes. Esto ayuda a ahorrar el uso de VRAM al rellenar secuencias de entrada. Sin embargo, reduciría en gran medida la variación de la muestra dentro de un solo lote. Durante el proceso de capacitación, generalmente preferimos exponer el modelo a una variedad de muestras de capacitación. Establecer group-by-length en False reduce la variación de la muestra. También provoca fluctuaciones de pérdida durante el entrenamiento (por ejemplo, dos lotes consecutivos tienen longitudes acolchadas de 10 y 50. El lote más corto tiene una pérdida menor y el lote más largo tiene una pérdida mayor. Esto da como resultado una curva de pérdida oscilante, como se muestra en la figura). abajo).


Por otro lado, dado que group-by-length reduce la variación de la muestra en el lote, sospecho que el rendimiento del modelo también podría verse afectado. La siguiente figura compara la pérdida de entrenamiento con o sin group-by-length . Está claro que la pérdida promedio es mayor para la ejecución peach-violet-19 , que tiene habilitado group-by-length .


No confíes en la curva de pérdida de evaluación.

Observé que la pérdida de entrenamiento y la pérdida de evaluación divergen en todas mis carreras.


Aquí hay un ejemplo:

En este ejemplo, el punto de control óptimo ocurre alrededor de epoch=2 . Si carga el punto de control óptimo como lo sugiere el repositorio original, lo más probable es que obtenga un modelo de repetidor de aviso como se mencionó en la sesión anterior.


Al cargar un punto de control del modelo cerca del final del entrenamiento, obtuve un modelo con mejor rendimiento. Hice la misma pregunta que antes y el modelo me devolvió la respuesta correcta:


Instrucción:

Dada la siguiente información sobre un proyecto, responda las preguntas. El proyecto Chinese-Llama-2 tiene como objetivo mejorar las capacidades de comprensión, generación y traducción del modelo de lenguaje grande Llama-2 en idioma chino. Con la aplicación de métodos como el ajuste fino de LoRA, el ajuste fino de instrucciones de parámetros completos y el preentrenamiento secundario, lo invitamos cordialmente a descargar y utilizar los conjuntos de datos, guías de capacitación y parámetros del modelo asociados.


Entrada: ¿Qué métodos se utilizan en este proyecto?


Respuesta: El proyecto Chinese-Llama-2 utiliza métodos como el ajuste fino de LoRA, el ajuste fino de instrucciones de parámetros completos y el preentrenamiento secundario.</s>


Pero a juzgar por la pérdida de evaluación, este modelo debería funcionar peor. ¿Qué causa el dilema?

Creo que la pérdida de evaluación no es una buena matriz para medir el rendimiento de los modelos de lenguajes grandes. LLaMA utiliza CrossEntropyLoss para la pérdida de capacitación y evaluación:


 # modelling_llama.py from transformers library ... # forward function under LlamaForCausalLM class if labels is not None: # Shift so that tokens < n predict n shift_logits = logits[..., :-1, :].contiguous() shift_labels = labels[..., 1:].contiguous() # Flatten the tokens loss_fct = CrossEntropyLoss() loss = loss_fct(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1))


Al realizar pruebas en un conjunto de evaluación, un modelo podría producir la misma respuesta con una redacción diferente:

 { "evaluation prompt": "What is 1 + 3?" "evaluation answer": "4." "prediction answer": "The answer is 4." }


Ambas respuestas son correctas, pero si la respuesta de predicción no coincide exactamente con la respuesta de evaluación, la pérdida de evaluación será alta. En este caso, necesitamos una mejor matriz de evaluación para medir el desempeño del modelo. Nos preocuparemos de la evaluación adecuada más adelante. Por ahora, supongamos que el mejor modelo es el que tiene la menor pérdida de entrenamiento.

Más allá de 7B

Intenté ajustar un modelo 13B en V100. Si bien V100 puede manejar el entrenamiento int8 y fp16 en un modelo 7B, simplemente no puede manejar el entrenamiento int8 en el modelo 13B. Si load_int_8bit = True , el modelo 13B producirá training_loss = 0.0 . Podemos utilizar algunas herramientas de depuración para comprender por qué sucede esto ( alerta de spoiler: se debe a un desbordamiento/desbordamiento insuficiente).


Utilicé la herramienta DebugUnderflowOverflow de huggingface para inspeccionar los parámetros durante el entrenamiento. En el primer pase hacia adelante, detectó valores inf/nan:

Más específicamente, DebugUnderflowOverflow detectó valores infinitos negativos en la segunda entrada de LlamaDecoderLayer , como se muestra en la siguiente figura. La segunda entrada es attention_mask . Profundicé un poco más y descubrí que se supone que attention_mask tiene valores negativos muy grandes para los elementos de relleno. Casualmente, los valores infinitos negativos están al comienzo de cada secuencia. Esta observación me lleva a creer que se supone que ocurren valores infinitos negativos en esta capa. Investigaciones adicionales también mostraron que los valores infinitos no causaron más valores infinitos en las siguientes capas. Por lo tanto, lo más probable es que el desbordamiento en LlamaDecoderLayer no sea la causa principal de la pérdida anormal de entrenamiento.



A continuación, inspeccioné los resultados de cada capa. Quedó muy claro que las salidas de las capas finales se están desbordando, como se muestra en la siguiente figura. Creo que esto se debe a la precisión limitada de los pesos int-8 (o el rango limitado de float16 . Es probable que bfloat16 pueda evitar este problema).



Para resolver el problema de desbordamiento, utilicé float16 durante el entrenamiento. V100 no tiene suficiente VRAM para entrenar un modelo 13B a menos que se utilicen algunos trucos. Hugging Face DeepSpeed proporciona varios métodos, como la descarga de CPU, para reducir el uso de VRAM de entrenamiento. Pero el truco más simple es habilitar el punto de control de gradiente llamando a model.gradient_checkpointing_enable() antes de que comience el entrenamiento.


El control de gradiente compensa la velocidad de entrenamiento por un menor uso de VRAM. Normalmente, durante el pase hacia adelante, las activaciones se calculaban y almacenaban en la memoria para su uso durante el pase hacia atrás. Esto ocupa memoria adicional. Sin embargo, con los puntos de control de gradiente, en lugar de almacenar activaciones durante el paso hacia adelante, se vuelven a calcular durante el paso hacia atrás, ahorrando así VRAM. Aquí hay un buen artículo sobre esta técnica.


Pude entrenar Llama 13B con float16 y el control de gradiente habilitado:

 python finetune.py \ --base_model=yahma/llama-13b-hf \ --num_epochs=10 \ --output_dir 'your/output/dir' \ --lora_target_modules='[q_proj,k_proj,v_proj,o_proj]' \ --cutoff_len=1024 \ --lora_r=16 \ --micro_batch_size=4 \ --batch_size=128 \ --wandb_project 'alpaca_lora_13b' \ --train_on_inputs=False


El modelo 13B puede manejar algunas tareas avanzadas, como el reconocimiento de entidades de nombres. Utilizo un mensaje de ejemplo para la prueba y esta es la respuesta precisa del modelo 13B:

¡Todo está bien! Este es un comienzo emocionante. El modelo nos permite crear aplicaciones complejas con LangChain.


En este punto, todavía nos faltan herramientas para la evaluación automática de modelos. Podemos utilizar Language Model Evaluación Arnés para evaluar nuestros modelos en muchos casos de prueba, o incluso crear nuestros propios casos de prueba. Es la misma herramienta que utiliza Hugging Face para su Open LLM Leaderboard. Si bien la evaluación es un aspecto crucial del desarrollo de un LLM, este artículo se centra únicamente en el proceso de formación. Quizás hable sobre la evaluación en un artículo futuro.


Resumen

En este artículo, presentamos el concepto de modelos de base grande (LFM) y varios métodos de ajuste que hacen que los LFM se comporten como se desea. Luego nos centramos en LoRA, un método eficiente en parámetros para ajustar LFM, y explicamos el código de ajuste, así como las técnicas de mejora del rendimiento. Finalmente, fuimos un paso más allá y entrenamos con éxito un modelo Llama 13B en una GPU V100. Aunque el entrenamiento del modelo 13B tuvo algunos problemas, descubrimos que estos problemas fueron impuestos por limitaciones del hardware y presentamos soluciones. Al final, obtuvimos un LLM perfeccionado que funciona, pero aún no hemos evaluado cuantitativamente el desempeño del LLM.



Sobre el Autor


¡Hola! Mi nombre es Wei. Soy un solucionador de problemas dedicado, especialista sénior en IA y líder de proyectos de análisis en ABB , y experto en desarrolladores de Google en aprendizaje automático . Tengo una maestría en Ingeniería Mecánica de la Universidad de Minnesota Twin Cities y una licenciatura en Ingeniería Mecánica de la Universidad de Illinois en Urbana-Champaign.


Mi pila tecnológica se centra en programación Python/C#, visión por computadora, aprendizaje automático, algoritmos y microservicios, pero también tengo una amplia gama de intereses como desarrollo de juegos (Unity), desarrollo front/back-end, liderazgo técnico, jugueteando con computadoras de placa única y robótica.


Espero que este artículo pueda ayudar a las personas de alguna manera. ¡Gracias por leer y feliz resolución de problemas!