Resumen de optimización del algoritmo: Transofomer evita la memoria de video insuficiente y el tiempo de entrenamiento excesivo

Método de Transofomer para evitar memoria de video insuficiente y tiempo de entrenamiento excesivo

Desde la aparición de BERT, el campo de la PNL ha entrado en la era de los modelos grandes. Aunque el efecto de los modelos grandes es bueno, después de todo, no todos tienen abundantes recursos de GPU. A menudo se estiran durante el entrenamiento y hay un problema de memoria. sin memoria, o entrenamiento. El tiempo es muy, muy largo. Por lo tanto, el problema principal que se resolverá en este artículo es cómo entrenar el modelo grande en la biblioteca de transformadores bajo la condición de recursos de GPU limitados.

Aunque los Transformers de código abierto de Huggingface han logrado un éxito sorprendente en las tareas de procesamiento de lenguaje natural (NLP), debido a la gran cantidad de parámetros del modelo en su interior, incluso el uso de GPU para entrenamiento o implementación sigue siendo un gran desafío, porque usar tales Cuando se usa un modelo grande para entrenamiento o inferencia, es fácil sufrir de memoria insuficiente (OOM) y tiempo de entrenamiento excesivo.

Sin embargo, hay muchas formas de evitar una memoria de video insuficiente y un tiempo de entrenamiento prolongado. La contribución principal de este artículo es presentar los principios de estos métodos y cómo implementarlos, incluidos los siguientes métodos:

  1. Acumulación de gradiente
  2. Congelación
  3. Precisión mixta automática
  4. Optimizadores de 8 bits
  5. Puntos de control de gradiente
  6. Tokenizadores rápidos
  7. Relleno dinámico
  8. Acolchado dinámico uniforme

Entre ellos, 1-5 son métodos generales para redes neuronales, que se pueden utilizar para la optimización del rendimiento de cualquier red, y 6-8 son métodos de optimización del rendimiento para el campo nlp.

acumulación de gradiente

La idea detrás de la acumulación de gradientes es muy simple, para simular lotes más grandes. A veces, para lograr una mejor convergencia o mejorar el rendimiento, es necesario usar lotes grandes para el entrenamiento; sin embargo, esto generalmente requiere una memoria de video más grande. Una posible solución a este problema es usar lotes más pequeños, sin embargo, por un lado, el entrenamiento con lotes pequeños aumenta el tiempo de entrenamiento e inferencia, y por otro lado, el algoritmo de descenso de gradiente es muy sensible a la elección del tamaño del lote, y los lotes pequeños pueden conducir a una convergencia inestable y un rendimiento reducido. Por lo tanto, podemos realizar la propagación hacia adelante y la propagación hacia atrás varias veces primero, de modo que los gradientes se puedan acumular. Cuando tenemos suficientes gradientes de cálculo, podemos optimizar los parámetros, a fin de usar una memoria de video pequeña para simular el efecto de lotes grandes, y el tiempo de entrenamiento no aumentará significativamente.
inserte la descripción de la imagen aquí

congelar

La congelación es un método muy eficaz. Al cancelar el cálculo del gradiente en algunas capas del modelo de cálculo (como la capa de incrustación, las primeras capas de bert), puede acelerar en gran medida la velocidad de entrenamiento y reducir el uso de memoria, y Difícilmente perderá el rendimiento del modelo.

Un hecho bien conocido en el aprendizaje profundo es que la capa inferior de la red aprende las características generales de los datos de entrada, mientras que la capa superior de la red aprende las características de alto nivel específicas de la tarea de destino, por lo que al ajustar la modelo pre-entrenado, los parámetros de la capa inferior de la red generalmente no son muy necesarios. Cambio, estos son conocimientos generales, lo que se necesita aprender son los parámetros de la capa superior, cuando se usa algún algoritmo de optimización (como SGD, AdamW o RMSprop) para realizar el paso de optimización, el gradiente de la capa inferior de la red es muy pequeño, por lo que los parámetros son casi Esto también se conoce como desaparición de gradiente, por lo que en lugar de gastar mucho tiempo y potencia informática para calcular estos gradientes "inútiles" en la parte inferior, y para optimizar dichos parámetros con gradientes pequeños, es mejor congelarlos directamente. Los gradientes informáticos tampoco están optimizados.

PyTorch proporciona una API cómoda para desactivar los cálculos de gradiente, que se puede configurar a través de la propiedad require_grad de torch.Tensor.

Precisión mixta automática

Automatic Mixed Precision (AMP) es otra forma de reducir el consumo de memoria y el tiempo de entrenamiento sin perder la calidad final, propuesta por los investigadores de NVIDIA y Baidu en el documento Mixed Precision Training de 2017. La idea clave detrás de este método es mantener los gradientes y los parámetros del modelo en la memoria usando una precisión más baja, es decir, en lugar de usar la precisión total (float32), use la mitad de la precisión (por ejemplo, float16) para mantener los tensores en la memoria. Sin embargo, al calcular gradientes con menor precisión, algunos valores pueden ser tan pequeños que se consideran cero, fenómeno conocido como "desbordamiento". Para evitar el "desbordamiento", los autores del artículo original proponen un método de escala de gradiente.

PyTorch ha proporcionado un paquete desde la versión 1.6: torch.cuda.amp, con las funciones necesarias para usar precisión mixta automática (desde precisión reducida hasta escalado de gradiente), la precisión mixta automática se implementa como un administrador de contexto, por lo que puede insertarse en cualquier momento y en cualquier lugar de los scripts de entrenamiento e inferencia
inserte la descripción de la imagen aquí

optimizador de 8 bits

La idea de Optimizers de 8 bits es similar a la precisión mixta automática (los parámetros y gradientes del modelo se guardan con menor precisión), pero Optimizers de 8 bits también permite guardar el estado del optimizador con poca precisión. El autor (Meta Research) presentó los optimizadores de 8 bits en detalle en el documento original Optimizadores de 8 bits a través de la cuantificación por bloques, lo que demuestra que los optimizadores de 8 bits reducen significativamente el uso de memoria y aceleran ligeramente el entrenamiento. Además, los autores estudian el efecto de diferentes configuraciones de hiperparámetros, lo que demuestra que el efecto de los optimizadores de 8 bits en diferentes parámetros de velocidad de aprendizaje, beta y caída de peso es estable sin degradar el rendimiento ni afectar la convergencia. Por lo tanto, el autor proporciona una biblioteca de alto nivel para el optimizador de 8 bits llamada bitsandbytes.

punto de control de gradiente

A veces, incluso después de usar los métodos anteriores, la memoria de video puede no ser suficiente, especialmente si el modelo es lo suficientemente grande. Luego, Gradient Checkpointing (Gradient Checkpointing) es el truco de la parte inferior de la caja. Este método es la primera vez en Training Deep Nets With Sublinear Memory Cost. El autor muestra que el gradiente de control puede reducir significativamente la tasa de utilización de la memoria de video. , de reducido a , donde n es el modelo el número de capas. Este enfoque permite entrenar modelos grandes en una sola GPU o proporcionar más memoria para aumentar el tamaño del lote para una convergencia mejor y más rápida. La idea detrás de los puntos de control de gradiente es calcular los gradientes en pequeños fragmentos mientras se eliminan los gradientes innecesarios de la memoria durante la propagación hacia adelante y hacia atrás, lo que reduce la utilización de la memoria, pero este enfoque requiere más pasos de cálculo para reproducir todo el gráfico de propagación hacia atrás, de hecho, es un método de intercambio tiempo para el espacio
inserte la descripción de la imagen aquí

También hay una implementación de puntos de control de gradiente en el marco PyTorch, a través de estas dos funciones: torch.utils.checkpoint.checkpoint y torch.utils.checkpoint.checkpoint_secuencial

Aquí hay una introducción al punto de control de gradiente en el sitio web oficial de la antorcha:

  • Los puntos de control de gradiente funcionan intercambiando cómputo por memoria. En lugar de almacenar todas las activaciones intermedias de todo el gráfico de cálculo para el cálculo inverso, la parte del punto de control no guarda las activaciones intermedias sino que las vuelve a calcular durante el proceso inverso. Se puede aplicar a cualquier parte del modelo. Específicamente, en el pase hacia adelante, la función se comportará como torch.no_grad(), es decir, no se almacenarán activaciones intermedias. Sin embargo, el paso hacia adelante guarda la tupla de entrada y los parámetros de la función. Durante la retropropagación, se recuperan las entradas y la función guardadas, y luego la función se propaga hacia adelante nuevamente, ahora se realiza un seguimiento de las activaciones intermedias y luego se usan esos valores de activación para calcular los gradientes.

tokenizador rápido

HuggingFace Transformers proporciona dos tipos de tokenizadores: tokenizador básico y tokenizador rápido. La principal diferencia entre ellos es que el tokenizador rápido está escrito en Rust, porque Python es muy lento en los bucles, pero los bucles se usan al tokenizar. El tokenizador rápido es un método muy simple que nos permite obtener una aceleración adicional al tokenizar. También es muy simple usar el tokenizador rápido, simplemente cambie el valor use_fast del método from_pretrained en transformers.AutoTokenizer a True

inserte la descripción de la imagen aquí

relleno dinámico

Por lo general, los modelos se entrenan con lotes de entradas de datos, cada entrada en un lote debe tener un tamaño fijo, es decir, un lote de datos debe estar representado por una matriz y todos los lotes de datos tienen el mismo tamaño. Por lo general, se elige un tamaño fijo en función de la distribución de longitudes en el conjunto de datos, la cantidad de características y otros factores. En las tareas de NLP, el tamaño de entrada se denomina longitud del texto o longitud máxima. Sin embargo, diferentes textos tienen diferentes longitudes, y para hacer frente a esta situación, los investigadores proponen marcas de relleno y truncamiento. El truncamiento se usa cuando la longitud máxima es menor que la longitud del texto de entrada, por lo que se eliminan algunos tokens. Cuando la longitud del texto de entrada es menor que la longitud máxima, se agregarán tokens de relleno, como [PAD], al final del texto de entrada. Vale la pena señalar que los tokens de relleno no deben incluirse en el cálculo de pérdida de algunas tareas (como el modelo de construcción de lenguaje enmascarado o el reconocimiento de entidades nombradas)

inserte la descripción de la imagen aquí

Sin embargo, los marcadores llenos tienen desventajas significativas. Por ejemplo, cuando el texto de entrada es muy corto en relación con la longitud máxima seleccionada, la eficiencia es muy baja y se requiere más memoria adicional. Por ejemplo, tengo una longitud de texto de 512, y luego otras longitudes de texto son alrededor de 10, luego si max Si seq se establece en 512, dará lugar a muchos cálculos no válidos. Para evitar operaciones informáticas adicionales, los investigadores propusieron un método muy efectivo, que consiste en llenar el lote de entradas hasta la longitud máxima de entrada del lote, como se muestra en la figura a continuación, este método puede aumentar la velocidad de entrenamiento en un 35 %. o incluso 50% %, por supuesto, el efecto de aceleración de este método depende del tamaño del lote y la distribución de la longitud del texto.Cuanto más pequeño sea el lote, más evidente será el efecto de aceleración y más desigual la distribución de la longitud del texto. , mejor será el efecto de aceleración.

inserte la descripción de la imagen aquí

Relleno dinámico uniforme

La idea es clasificar el texto según la longitud del texto al dividir el lote, de modo que la longitud del texto en el mismo lote sea casi la misma. Este enfoque es muy eficiente y requiere menos cómputo que el relleno dinámico, ya sea durante el entrenamiento o la inferencia. Sin embargo, no se recomienda usar relleno dinámico uniforme durante el entrenamiento, porque es mejor mezclar los datos durante el entrenamiento, pero puede considerar hacerlo si necesita razonar mucho texto a la vez durante el razonamiento.

inserte la descripción de la imagen aquí

Resumen de población dinámica uniforme La optimización de la memoria y el tiempo es un paso necesario en el desarrollo de modelos incluso en las GPU modernas, por lo que este artículo presenta los métodos más poderosos y populares para acelerar el entrenamiento y reducir el consumo de memoria para modelos grandes como los transformadores.

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_44077556/article/details/128115413
Recomendado
Clasificación