Teoría + práctica, te llevará a comprender la capacitación distribuida

Este artículo es compartido por Huawei Cloud Community " Capacitación distribuida de modelo grande LLM ", autor: Hua Shanghua_Lancer.

Con el rápido crecimiento en la cantidad de parámetros de modelos de lenguaje y datos de capacitación requeridos, los recursos limitados en una sola máquina ya no pueden cumplir con los requisitos para la capacitación de modelos de lenguaje de gran tamaño. Es necesario diseñar un sistema de capacitación distribuida (capacitación distribuida) para resolver el problema de los requisitos masivos de recursos informáticos y de memoria.

En un entorno de sistema de capacitación distribuido, es necesario dividir una tarea de capacitación modelo en múltiples subtareas y distribuir las subtareas a múltiples dispositivos informáticos para resolver los cuellos de botella de recursos. Pero, ¿cómo podemos utilizar un clúster que incluye decenas de miles de chips de aceleración informática para entrenar un modelo de lenguaje a gran escala con cientos de miles de millones o incluso billones de parámetros de modelo? Esto implica una serie de tecnologías como arquitectura de clúster, estrategia paralela, arquitectura de modelo, optimización de memoria y optimización informática.

Presentaré en detalle los conceptos básicos de los sistemas distribuidos de aprendizaje automático, la arquitectura de clústeres de capacitación distribuida, las estrategias paralelas de capacitación distribuida y utilizaré DeepSpeed ​​​​como ejemplo para presentar cómo entrenar modelos de lenguaje grandes en un clúster.

1. Descripción general de la formación distribuida

La capacitación distribuida se refiere a descomponer las tareas de capacitación de modelos de aprendizaje automático o aprendizaje profundo en múltiples subtareas y entrenarlas en paralelo en múltiples dispositivos informáticos. La Figura 1 ofrece un ejemplo de un único dispositivo informático y varios dispositivos informáticos. El dispositivo informático aquí puede ser una unidad de procesamiento central (CPU), una unidad de procesamiento de gráficos (GPU) o una unidad de procesamiento tensorial (Unidad de procesamiento tensor). TPU) también puede ser un procesador de red neuronal (Unidad de procesamiento de red neuronal, NPU).

Dado que la memoria no se puede compartir entre varios dispositivos informáticos dentro del mismo servidor, independientemente de si estos dispositivos informáticos están en un servidor o en varios servidores, la arquitectura de su sistema cae en la categoría de sistemas distribuidos. Una tarea de entrenamiento de modelo a menudo tiene una gran cantidad de muestras de entrenamiento como entrada, que se pueden completar usando un dispositivo informático, o toda la tarea de entrenamiento del modelo se puede dividir en subtareas y distribuir a diferentes dispositivos informáticos para lograr computación paralela.

Después de eso, es necesario combinar la salida de cada dispositivo informático para obtener finalmente el resultado del cálculo equivalente al de un solo dispositivo informático. Dado que cada dispositivo informático solo necesita ser responsable de subtareas y que varios dispositivos informáticos pueden ejecutarse en paralelo, puede completar el cálculo general más rápido y, en última instancia, acelerar todo el proceso informático.

Figura 1 Ejemplos de computación con un solo dispositivo informático y múltiples dispositivos informáticos

Una de las razones más importantes que impulsa a las personas a diseñar sistemas de capacitación distribuidos es que la potencia informática de un solo dispositivo informático ya no es suficiente para respaldar la capacitación modelo. La Figura 2 muestra los requisitos de potencia informática del modelo de aprendizaje automático y la potencia informática que un solo dispositivo informático puede proporcionar durante el mismo período. Como se muestra en la figura, los modelos de aprendizaje automático se están desarrollando rápidamente, desde AlexNet en 2013 hasta el modelo Palm con 540 mil millones de parámetros en 2022, los modelos de aprendizaje automático se están desarrollando a un ritmo de 56 veces cada 18 meses. A medida que aumenta la escala de parámetros del modelo, los requisitos de cantidad de datos de entrenamiento también aumentan exponencialmente, lo que intensifica la demanda de potencia informática.

Sin embargo, en los últimos años, el aumento en la potencia informática de la CPU ha sido mucho menor que la Ley de Moore. Aunque los dispositivos de aceleración informática (como GPU, TPU, etc.) proporcionan una gran cantidad de potencia informática para los modelos de aprendizaje automático, su tasa de crecimiento aún. no ha superado la ley de Moore de duplicarse cada 18 meses. Para poder afrontar el desarrollo de modelos de aprendizaje automático, sólo un sistema de formación distribuido puede satisfacer los crecientes requisitos de potencia informática del modelo.

Figura 2 Comparación entre el crecimiento de los parámetros del modelo de aprendizaje automático y el crecimiento de la potencia informática del hardware informático

El objetivo general de la capacitación distribuida es aumentar la velocidad general de capacitación y reducir el tiempo total de capacitación del modelo. La velocidad total de entrenamiento se puede estimar brevemente utilizando la siguiente fórmula:

Velocidad total de entrenamiento ∝ Velocidad de computación de un solo dispositivo × Número total de dispositivos de computación × Relación de aceleración de múltiples dispositivos

Entre ellos, la velocidad de computación de un solo dispositivo está determinada principalmente por la velocidad de computación y las capacidades de E/S de datos de un solo chip de aceleración de computación. Para optimizar la eficiencia del entrenamiento de un solo dispositivo, los principales medios técnicos incluyen entrenamiento de precisión mixto y operador. fusión, acumulación de gradiente, etc.; cuanto mayor sea el número de dispositivos informáticos en un sistema de entrenamiento distribuido, mayor será su velocidad informática máxima teórica. Sin embargo, afectado por la eficiencia de la comunicación, un aumento en el número de dispositivos informáticos provocará una rápida. la disminución de la tasa de aceleración; la tasa de aceleración de múltiples dispositivos se determina mediante el cálculo y la eficiencia de la comunicación se determina combinando algoritmos y topología de red para la optimización. El objetivo principal de la estrategia paralela de entrenamiento distribuido es mejorar la tasa de aceleración de múltiples dispositivos en. El sistema de formación distribuida.

La cantidad de parámetros de modelos de lenguaje grandes y la cantidad de datos utilizados son enormes, por lo que se utiliza una arquitectura de capacitación distribuida para completar la capacitación. El documento [5] solo presenta el proceso de entrenamiento de GPT-3 usando GPU NVIDIA V100. El documento [31] presenta que OPT usa 992 GPU NVIDIA A100 80G y adopta paralelo de datos totalmente compartido [129] y paralelismo tensor Megatron-LM [130]. , el tiempo total de formación es de casi 2 meses.

Los investigadores del modelo BLOOM[33] revelaron más detalles sobre el hardware y la arquitectura del sistema utilizado. El entrenamiento del modelo tomó un total de 3,5 meses y utilizó 48 nodos informáticos. Cada nodo contiene 8 GPU NVIDIA A100 80G (384 GPU en total) y utiliza 4*NVLink para la comunicación entre las GPU dentro del nodo. Los nodos se comunican entre sí mediante una red de topología global de hipercubo de 8 dimensiones mejorada construida con cuatro tarjetas de red Omni-Path de 100 Gbps.

La literatura [37] no proporciona la configuración específica ni la topología de red del clúster utilizado en el entrenamiento del modelo LLaMA, pero proporciona el total de horas de GPU para diferentes escalas de parámetros. El entrenamiento del modelo LLaMA utiliza GPU A100-80 GB, el entrenamiento del modelo LLaMA-7B requiere 82432 horas de GPU, el entrenamiento del modelo LLaMA-13B requiere 135168 horas de GPU, el entrenamiento del modelo LLaMA-33B requiere 530432 horas de GPU y el entrenamiento del modelo LLaMA-65B cuesta hasta 1022362 GPU Hora. Dado que la cantidad de datos de entrenamiento utilizados por LLaMA supera con creces la de los modelos OPT y BLOOM, aunque el número de parámetros del modelo es mucho menor que los dos modelos anteriores, la cantidad de cálculo requerido sigue siendo asombrosa.

Al utilizar un sistema de capacitación distribuido, el ciclo de capacitación de grandes modelos de lenguaje se puede acortar de décadas en un solo dispositivo informático a docenas de días utilizando miles de dispositivos informáticos. Sin embargo, los sistemas de capacitación distribuidos aún deben superar varios desafíos, como muros informáticos, muros de memoria de video y muros de comunicación, para garantizar que todos los recursos del clúster se utilicen por completo, acelerando así el proceso de capacitación y acortando el ciclo de capacitación.

• Muro computacional: existe una enorme discrepancia entre la potencia informática que puede proporcionar un solo dispositivo informático y la cantidad total de cálculo necesaria para un modelo de lenguaje grande. La NVIDIA H100 SXM lanzada en marzo de 2022 tiene una potencia informática FP16 de una sola tarjeta de solo 2000 TFLOP, mientras que GPT-3
requiere una potencia informática total de 314 ZFLOP. La diferencia entre las dos es de 8 órdenes de magnitud.

• Muro de memoria de vídeo: un único dispositivo informático no puede almacenar completamente los parámetros de un modelo de lenguaje de gran tamaño. GPT-3 contiene 175 mil millones de parámetros. Si se almacena en formato FP16, requiere 700 GB de espacio de memoria del dispositivo informático y la GPU NVIDIA H100 solo tiene 80 GB de memoria de video.

• Muro de comunicación: en un sistema de entrenamiento distribuido se requiere una transmisión y sincronización frecuente de parámetros entre dispositivos informáticos. Debido a la latencia de la comunicación y las limitaciones del ancho de banda, esto puede convertirse en un cuello de botella en el proceso de capacitación. Durante el proceso de entrenamiento de GPT-3, si hay 128 copias del modelo en el sistema distribuido, se deben transmitir al menos 89,6 TB de datos de gradiente durante cada iteración. A partir de agosto de 2023, un único enlace InfiniBand solo puede proporcionar un ancho de banda no superior a 800 Gb/s. El muro informático y el muro de memoria de vídeo surgen del conflicto entre las limitadas capacidades informáticas y de almacenamiento de un único dispositivo informático y los enormes requisitos informáticos y de almacenamiento del modelo. Este problema se puede resolver utilizando un método de capacitación distribuida, pero la capacitación distribuida enfrentará el desafío de los muros de comunicación. Estos problemas surgieron gradualmente en el entrenamiento de múltiples máquinas y tarjetas. A medida que aumentan los parámetros de los modelos grandes, el tamaño del grupo correspondiente también aumenta y estos problemas se vuelven más prominentes. Al mismo tiempo, cuando los grupos grandes se entrenan durante mucho tiempo, las fallas del equipo pueden afectar o interrumpir el proceso de capacitación, lo que también impone altas exigencias al sistema distribuido.

2. Estrategia paralela de formación distribuida

El objetivo del sistema de capacitación distribuida es convertir la capacitación del modelo de un solo nodo en una capacitación equivalente del modelo paralelo distribuido. Para modelos de lenguaje grandes, el proceso de entrenamiento es el proceso de actualizar los parámetros del modelo de red neuronal utilizando algoritmos de optimización basados ​​en datos y funciones de pérdida. La estructura del sistema de entrenamiento del modelo de un solo nodo se muestra en la Figura 3, que consta principalmente de dos partes: datos y modelo. El proceso de capacitación se completará con múltiples mini lotes de datos (Mini-batch).

Los datos de la figura representan un pequeño lote de datos. El sistema de entrenamiento utiliza pequeños lotes de datos para generar gradientes basados ​​en funciones de pérdida y algoritmos de optimización para corregir los parámetros del modelo. El proceso de ejecución de una red neuronal multicapa para un modelo de lenguaje grande se puede representar mediante un gráfico computacional (Computational Graph). Este gráfico tiene múltiples operadores interconectados (Operadores), cada operador implementa una capa de red neuronal (Capa de red neuronal) y los parámetros representan los pesos actualizados por esta capa durante el entrenamiento.

Figura 3 Sistema de entrenamiento modelo de dispositivo único

El proceso de ejecución del gráfico de cálculo se puede dividir en dos etapas: cálculo directo y cálculo inverso. El proceso de cálculo directo consiste en leer los datos en el primer operador, calcular la estructura de salida correspondiente y luego repetir el proceso de cálculo directo hasta el final del último operador. El proceso de cálculo inverso se basa en la función de optimización y la pérdida. Cada operador calcula el gradiente por turno y utiliza el gradiente para actualizar los parámetros locales. Una vez completado el cálculo inverso y el cálculo del minilote de datos, el sistema leerá el siguiente minilote de datos y continuará con la siguiente ronda de actualizaciones de parámetros del modelo.

Según el proceso del sistema de entrenamiento del modelo de dispositivo único, podemos ver que si se realiza una aceleración paralela, se puede considerar desde dos dimensiones: datos y modelo. Primero, los datos se pueden dividir (partición), el mismo modelo se puede copiar en varios dispositivos y se pueden ejecutar diferentes fragmentos de datos en paralelo. Este método generalmente se denomina paralelismo de datos (DP). El modelo también se puede dividir y los operadores en el modelo se pueden distribuir a múltiples dispositivos para su finalización respectivamente. Este método generalmente se denomina Paralelismo del Modelo (MP). Al entrenar modelos de lenguaje a muy gran escala, a menudo es necesario dividir los datos y el modelo al mismo tiempo para lograr un mayor grado de paralelismo. Este método a menudo se denomina paralelismo híbrido (HP).

2.1. Paralelismo de datos

En un sistema paralelo de datos, cada dispositivo informático tiene una copia completa de todo el modelo de red neuronal (réplica del modelo). Al iterar, a cada dispositivo informático solo se le asigna un subconjunto de un lote de muestras de datos y, en función del lote de muestras. Un subconjunto de datos se utiliza para el cálculo directo del modelo de red. Supongamos que el número de muestras de entrenamiento en un lote es N, que se utilizan M dispositivos informáticos para el cálculo paralelo y que a cada dispositivo informático se le asignarán N/M muestras. Una vez completado el cálculo directo, cada dispositivo informático calculará el error de pérdida en función de la muestra local para obtener el gradiente Gi (i es el número de la tarjeta del acelerador) y transmitirá el gradiente Gi local. Todos los dispositivos informáticos deben agregar los valores de gradiente proporcionados por otras tarjetas de aceleración y luego usar el gradiente promedio (ΣNi = 1Gi) ​​/ N para actualizar el modelo y completar el entrenamiento por lotes. La Figura 4 muestra un ejemplo de un sistema de entrenamiento de datos paralelo que consta de dos dispositivos informáticos.

Figura 4 Ejemplo de sistema de entrenamiento paralelo de datos de dos nodos

El sistema de capacitación en paralelo de datos puede mejorar efectivamente el rendimiento general de la capacitación y el tamaño de lote global por segundo (tamaño de lote global por segundo) agregando equipos informáticos. En comparación con el entrenamiento de un solo dispositivo informático, la principal diferencia es que los gradientes en el cálculo inverso deben sincronizarse en todos los dispositivos informáticos para garantizar que el resultado final en cada dispositivo informático sea el promedio de los gradientes de todos los procesos.

Los marcos de redes neuronales comunes tienen implementaciones específicas de paralelismo de datos, que incluyen: TensorFlow DistributedStrategy, PyTorch Distributed, Horovod DistributedOptimizer, etc. Dado que cada operador en un modelo de lenguaje grande basado en la arquitectura Transformer se basa en datos únicos en lugar de datos por lotes, el paralelismo de datos no afectará su lógica de cálculo. En general, el cálculo directo en cada dispositivo de entrenamiento es independiente y no afecta la lógica de cálculo. Implica problemas de sincronización. El entrenamiento en paralelo de datos tiene la tasa de aceleración más alta, pero requiere una copia de seguridad del modelo en cada dispositivo y consume una cantidad relativamente alta de memoria de video.

El código para usar PyTorch DistributedDataParallel para implementar el entrenamiento de múltiples tarjetas aceleradoras en un solo servidor es el siguiente. Primero, construya la clase DistributedSampler para interrumpir aleatoriamente las muestras del conjunto de datos y distribuirlas a diferentes dispositivos informáticos:

clase DistributedSampler(Sampler):
  def __init__(self, conjunto de datos, num_replicas=Ninguno, rango=Ninguno, shuffle=True, semilla=0):
    si num_replicas es Ninguno:
        si no dist.is_available():
            elevar RuntimeError ("Requiere que el paquete distribuido esté disponible")
        num_replicas = dist.get_world_size()
    si el rango es Ninguno:
        si no dist.is_available():
            elevar RuntimeError ("Requiere que el paquete distribuido esté disponible")
        rango = dist.get_rank()
    self.conjunto de datos = conjunto de datos #conjunto de datos
    self.num_replicas = num_replicas #El número de procesos por defecto es world_size (número de GPU)
    self.rank = rango # ¿A qué proceso/GPU pertenece actualmente?
    self.época = 0
    self.num_samples = int(math.ceil(len(self.dataset) * 1.0 / self.num_replicas))
    #Número de muestras por proceso
    self.total_size = self.num_samples * self.num_replicas #El número total de muestras en el conjunto de datos
    self.shuffle = shuffle # Ya sea para mezclar el conjunto de datos
    self.seed = semilla

def __iter__(yo):
# 1. Procesamiento aleatorio: altera el orden del conjunto de datos
    si es auto.shuffle:
        # Ofuscar según la época y la semilla
        g = antorcha.Generador()
        # Aquí self.seed es un valor fijo. Cambiar self.epoch por set_epoch puede cambiar nuestra semilla de inicialización.
        # Esto permite que el orden de mezcla de los conjuntos de datos en cada época sea diferente, de modo que en cada época,
        # Cada GPU obtiene datos diferentes, lo que puede facilitar un mejor entrenamiento.
        g.manual_seed(self.seed + self.epoch)
        índices = torch.randperm(len(self.dataset), generador=g).tolist()
    demás:
        índices = lista (rango (len (self.dataset)))
    # Suplemento de datos
    índices += índices[:(self.total_size - len(índices))]
    afirmar len (índices) == self.total_size
    # asignar datos
    índices = índices[self.rank:self.total_size:self.num_replicas]
    afirmar len(índices) == self.num_samples
    iter de retorno (índices)
def __len__(yo):
    devolver self.num_samples
def set_epoch(self, época):

    self.epoch = época

Utilice DistributedSampler para construir un programa de capacitación completo de muestra main.py de la siguiente manera:

importar análisis de argumentos
importarnos
importar Shuil
tiempo de importación
advertencias de importación
importar numpy como np
advertencias.filterwarnings('ignorar')
importar antorcha
importar torch.nn como nn
importar antorcha.nn.paralelo
importar torch.backends.cudnn como cudnn
importar antorcha.distribuida como dist
importar antorcha.optim
importar antorcha.utils.data
importar torch.utils.data.distributed
desde torch.utils.data.distributed importar DistributedSampler
desde modelos importar DeepLab
desde la importación de conjuntos de datos Paisajes urbanos
analizador = argparse.ArgumentParser (descripción = 'DeepLab')
parser.add_argument('-j', '--workers', predeterminado=4, tipo=int, metavar='N',
ayuda='número de trabajadores de carga de datos (predeterminado: 4)')
parser.add_argument('--épocas', predeterminado=100, tipo=int, metavar='N',
ayuda='número total de épocas a ejecutar')
parser.add_argument('--start-epoch', predeterminado=0, tipo=int, metavar='N',
help='número de época manual (útil en reinicios)')
parser.add_argument('-b', '--tamaño de lote', predeterminado=3, tipo=int,
metavar='N')
parser.add_argument('--local_rank', default=0, type=int, help='rango de nodo para entrenamiento distribuido')
args = analizador.parse_args()
torch.distributed.init_process_group(backend="nccl") #Inicialización
print("Usar GPU: {} para entrenamiento".format(args.local_rank))
# crear modelo
modelo = DeepLab()
torch.cuda.set_device(args.local_rank) #Tarjeta gráfica actual
model = model.cuda() # El modelo se coloca en la tarjeta gráfica
modelo = torch.nn.parallel.DistributedDataParallel(modelo, device_ids=[args.local_rank],
    output_device=args.local_rank, find_unused_parameters=True) # Paralelismo de datos
criterio = nn.CrossEntropyLoss().cuda()
optimizador = torch.optim.SGD(model.parameters(), args.lr,
    impulso=args.momentum, peso_decay=args.weight_decay)
train_dataset = Paisajes urbanos()
train_sampler = DistributedSampler(train_dataset) # Distribuir datos
train_loader = torch.utils.data.DataLoader(train_dataset, lote_size=args.batch_size,
    shuffle=False, num_workers=args.workers, pin_memory=True, sampler=train_sampler)

Inicie el programa anterior a través de la siguiente línea de comando:

CUDA_VISIBLE_DEVICES=0,1 python -m torch.distributed.launch --nproc_per_node=2 main.py

2.2 Paralelismo del modelo

El paralelismo de modelos se utiliza a menudo para resolver el problema de memoria insuficiente en un solo nodo. Tomemos como ejemplo el modelo GPT-3 que contiene 175 mil millones de parámetros. Si cada parámetro en el modelo está representado por un número de punto flotante de 32 bits, el modelo debe ocupar 700 GB (es decir, 175 G × 4 bytes). representado por un número de coma flotante de 16 bits, cada copia de cada modelo requiere 350 GB de memoria. La tarjeta aceleradora H100 lanzada por NVIDIA en marzo de 2022 solo admite 80 GB de memoria de video y no se puede colocar todo el modelo en ella. El paralelismo del modelo se puede dividir en las dos formas siguientes desde la perspectiva de los gráficos computacionales:

(1) Dividir en diferentes dispositivos según las capas del modelo, es decir, paralelismo entre capas o paralelismo entre operadores (paralelismo entre operadores), también llamado paralelismo de canalización (paralelismo de canalización, PP);

(2) Divida los parámetros en la capa de cálculo en diferentes dispositivos, es decir, paralelismo intracapa o paralelismo intraoperador (paralelismo intraoperador), también llamado paralelismo tensorial (paralelismo tensorial, TP).

En la Figura 4.9 se muestra un ejemplo de un sistema de entrenamiento paralelo de modelo de dos nodos. El lado izquierdo es el paralelismo de canalización y las diferentes capas del modelo se dividen en diferentes dispositivos. El lado derecho es el paralelismo tensor y diferentes parámetros en la misma capa; se dividen en diferentes dispositivos en el dispositivo.

Paralelismo de tuberías

Pipeline Parallelism (PP) es una estrategia informática paralela que procesa cada capa del modelo en segmentos y distribuye cada segmento en diferentes dispositivos informáticos, de modo que las etapas anterior y posterior puedan funcionar en una tubería y en lotes. El paralelismo de canalización se aplica generalmente en sistemas paralelos de modelos a gran escala para resolver eficazmente el problema de la memoria insuficiente en un solo dispositivo informático. La Figura 4.6 muestra un sistema de tuberías en paralelo compuesto por cuatro dispositivos informáticos, incluido el cálculo directo y el cálculo inverso. Entre ellos, F1, F2, F3 y F4 representan respectivamente cuatro rutas de avance, que están ubicadas en diferentes dispositivos, mientras que B4, B3, B2 y B1 representan las rutas de retroceso inverso, que también están ubicadas en cuatro dispositivos diferentes. Sin embargo, como se puede ver en la figura, el dispositivo descendente (dispositivo descendente) en el gráfico de cálculo debe permanecer inactivo durante mucho tiempo, esperando que el dispositivo ascendente (dispositivo descendente) complete sus cálculos antes de poder comenzar a calcular el suyo. tareas.

Figura 5 Ejemplo de sistema de entrenamiento paralelo modelo de dos nodos

Esta situación resultó en una reducción significativa en el uso promedio del dispositivo, formando una Burbuja de Paralelismo Modelo, también conocida como Burbuja de Tubería.

Figura 6 Ejemplo de tubería paralela

Las burbujas paralelas generadas por la ingenua estrategia de canalización impiden que el sistema utilice plenamente los recursos informáticos y reducen la eficiencia informática general del sistema. Para reducir las burbujas paralelas, la literatura [131] propuso el método GPipe, que divide aún más el minilote en microlotes más pequeños y utiliza el esquema paralelo de canalización para procesar un microlote a la vez.

Una vez que se completa el cálculo en la etapa actual y se obtienen los resultados, los resultados del microlote se envían al dispositivo posterior y los datos del siguiente microlote comienzan a procesarse al mismo tiempo, lo que puede reducir burbujas paralelas hasta cierto punto. Figura 7Ejemplo paralelo de canalización de políticas GPipe. Como se muestra en la figura, el cálculo directo de F1 se divide en F11, F12, F13 y F14. Una vez completado el cálculo de F11 en el dispositivo informático 1, se iniciará el cálculo de F21 en el dispositivo informático 2 y en el. Al mismo tiempo, F12 se iniciará en paralelo en el cálculo del dispositivo informático 1. En comparación con el método de tubería paralela original, el método de tubería GPipe puede reducir eficazmente las burbujas paralelas.

Figura 7 Ejemplo paralelo de canalización de políticas de GPipe

Aunque la estrategia GPipe puede reducir ciertas burbujas paralelas, el cálculo hacia atrás solo puede comenzar después de que se completen todos los cálculos hacia adelante en un mini lote. Por lo tanto, se seguirán generando muchas burbujas paralelas, reduciendo así la eficiencia paralela del sistema. Megatron-LM[132] propuso una estrategia de canalización 1F1B, que consta de un canal de avance y un canal de retroceso. La estrategia de canalización 1F1B introduce un mecanismo de programación de tareas, que permite a los dispositivos posteriores ejecutar otras tareas paralelas mientras esperan cálculos ascendentes, mejorando así la utilización del dispositivo. 1F1B proporciona dos métodos de programación, no entrelazado y entrelazado, como se muestra en la Figura 8.

El modo de programación no entrelazado 1F1B se puede dividir en tres etapas. La primera es una fase de calentamiento en la que se realizan números variables de cálculos directos en el dispositivo informático. La siguiente fase es la fase de avance-retroceso, donde el dispositivo informático realiza secuencialmente un cálculo hacia adelante y luego un cálculo hacia atrás. La última fase es la fase hacia atrás, donde el dispositivo informático completa el último cálculo hacia atrás. En comparación con la estrategia GPipe, el modo de programación no entrelazado funciona mejor a la hora de ahorrar memoria. Sin embargo, requiere el mismo tiempo que la estrategia GPipe para completar una ronda de cálculos.

El modo de programación entrelazado 1F1B requiere que el número de microlotes sea un múltiplo integral de las etapas de la tubería. Cada dispositivo ya no es el único responsable del cálculo de múltiples capas consecutivas, sino que puede procesar subconjuntos de múltiples capas, llamados nuggets de modelo. Específicamente, en el modelo anterior, el dispositivo 1 podría ser responsable de las capas 1 a 4, el dispositivo 2 de las capas 5 a 8, y así sucesivamente. Sin embargo, en el nuevo modo, el dispositivo 1 puede manejar las capas 1, 2, 9, 10, el dispositivo 2 puede manejar las capas 3, 4, 11, 12, etc. En este modo, cada dispositivo se asigna a varias etapas del proceso. Por ejemplo, el Dispositivo 1 puede estar involucrado en algún subconjunto de tareas en la fase de calentamiento, la fase de cálculo hacia adelante y la fase de cálculo hacia atrás. Cada dispositivo puede realizar tareas informáticas en diferentes etapas en paralelo, aprovechando así mejor el paralelismo de canalización. Este modo no solo funciona bien en términos de consumo de memoria, sino que también mejora la eficiencia computacional, lo que permite que los sistemas paralelos para modelos grandes completen las tareas informáticas de manera más eficiente.


Figura 8 Ejemplo de estrategia paralela de canalización 1F1B  

PyTorch también incluye la función API Pipe para implementar la canalización. Para una implementación específica, consulte la clase "torch.distributed.pipeline.sync.Pipe". Puede utilizar esta API para construir una muestra que contenga dos capas lineales, ubicadas en dos dispositivos informáticos diferentes, de la siguiente manera:

{#
Paso 0. Primero es necesario inicializar el marco RPC.
os.environ['MASTER_ADDR'] = 'localhost'
os.environ['MASTER_PORT'] = '29500'
torch.distributed.rpc.init_rpc('trabajador', rango=0, world_size=1)
# Paso 1: construye un modelo que incluya dos capas lineales
fc1 = nn.Lineal(16, 8).cuda(0)
fc2 = nn.Lineal(8, 4).cuda(1)
# Paso 2: envuelve las dos capas con nn.Sequential
modelo = nn.Sequential(fc1, fc2)
# Paso 3: construir Pipe (torch.distributed.pipeline.sync.Pipe)
modelo = Tubería (modelo, trozos = 8)
# hacer entrenamiento/inferencia
entrada = antorcha.rand(16, 16).cuda(0)
salida_rref = modelo (entrada)
}

paralelismo tensorial

El paralelismo tensorial (TP) necesita resolver dos problemas: cómo dividir los parámetros en diferentes dispositivos de acuerdo con la estructura específica y el tipo de operador del modelo, y cómo garantizar la coherencia matemática después de la división. Los modelos de lenguaje grande se basan en la estructura Transformer. La estructura Transformer se compone principalmente de los siguientes tres operadores: representación incrustada (Embedding), multiplicación de matrices (MatMul) y cálculo de pérdida de entropía cruzada (Cross Entropy Loss).

Estos tres tipos de operadores son bastante diferentes y es necesario diseñar las correspondientes estrategias tensoriales paralelas [130] para dividir los parámetros en diferentes dispositivos. Para el operador de incrustación, si el número total de vocabularios es muy grande, la memoria de video de un solo dispositivo informático no podrá acomodar los parámetros de la capa de incrustación. Por ejemplo, si el número de vocabularios es 64000, la dimensión de representación incrustada es 5120 y el tipo utiliza números de coma flotante de precisión de 32 bits, entonces la memoria de video requerida para toda la capa de parámetros es aproximadamente 64000 × 5120 × 4/1024 /1024 = 1250 MB, y el gradiente inverso es el mismo. Requiere 1250 MB, casi 2,5 GB solo para almacenamiento.

Los parámetros incrustados en la capa de presentación se pueden dividir según la dimensión de la palabra. Cada dispositivo informático solo almacena parte del vector de palabras, y luego el vector de palabras completo se obtiene resumiendo los vectores de palabras parciales en cada dispositivo. La Figura 4.9 muestra un diagrama esquemático de incrustación de un solo nodo y paralelismo tensorial de dos nodos.

En un solo nodo, realice la operación de incrustación, bz es el tamaño del lote (tamaño de lote), el tamaño del parámetro de incrustación es [tamaño_palabra, tamaño_oculto] y se calcula el tensor [bz, tamaño_oculto]. El ejemplo paralelo del tensor de incrustación en la Figura 4.9 divide los parámetros de incrustación en dos bloques a lo largo de la dimensión tamaño_palabra. Cada bloque tiene un tamaño de [tamaño_palabra/2, tamaño_oculto] y se almacena en dos dispositivos respectivamente. Cuando cada nodo consulta su propia lista de palabras, si no se puede encontrar, la representación de la palabra es 0. Después de consultar el dispositivo respectivo, se obtiene el tensor de resultado [bz, oculto_tamaño] Finalmente, a través de la comunicación AllReduce_Sum ¬, sumando entre dispositivos. , obtenemos De los resultados completos, se puede ver que los resultados de salida aquí son consistentes con los resultados ejecutados por un solo dispositivo informático.

Figura 9 Ejemplo paralelo de tensor de operador de incrustación de dos nodos

El paralelismo tensorial de la multiplicación de matrices (MatMul) debería aprovechar al máximo el principio de multiplicación de bloques de matrices. Por ejemplo, para implementar la siguiente multiplicación de matrices Y = X ×A, donde X es la matriz de entrada con dimensión M × N, A es la matriz de parámetros con dimensión N ×K e Y es la matriz de resultado con dimensión M ×K. Si la matriz de parámetros A es muy grande, o incluso excede la capacidad de la memoria de video de una sola tarjeta, entonces la matriz de parámetros A se puede dividir en varias tarjetas y los resultados se pueden recopilar mediante comunicación colectiva para garantizar que el resultado final sea matemáticamente. equivalente a un solo dispositivo informático Resultados del cálculo. Hay dos formas de segmentar la matriz de parámetros A:

(1) La matriz de parámetros A se corta en columnas y la matriz A se corta en columnas: A = [A1, A2]

(2) La matriz de parámetros A se corta en filas y la matriz A se corta en filas:

La Figura 10 muestra un ejemplo de división de la matriz de parámetros por columnas. La matriz de parámetros A coloca A1 y A2 en dos dispositivos informáticos respectivamente. Dos dispositivos informáticos calculan Y1 = X ×A1 e Y2 = X ×A2 respectivamente. Una vez completado el cálculo, varios dispositivos informáticos se comunican entre sí para obtener los resultados del cálculo en otros dispositivos informáticos y los unen para obtener la matriz de resultados final Y. Este resultado es matemáticamente equivalente al resultado del cálculo de un solo dispositivo informático.

Figura 10 Ejemplo de división paralela de tensores de operadores de multiplicación de matrices de dos nodos por columnas

La Figura 11 muestra un ejemplo de cómo dividir la matriz de parámetros en columnas y filas. Para cumplir con las reglas de multiplicación de matrices, la matriz de entrada X debe dividirse por las columnas X = [X1|X2]. Al mismo tiempo, la matriz se divide en bloques y se coloca en dos dispositivos informáticos. Cada dispositivo informático calcula Y1 =X1 ×A1 e Y2 = X2 ×A2 respectivamente. Una vez completado el cálculo, varios dispositivos informáticos se comunican para obtener y reducir los resultados del cálculo en otras tarjetas, y se puede obtener la matriz de resultados final Y. De manera similar, este método de división no solo puede garantizar la equivalencia de cálculo matemático, sino que también resuelve el problema de que un solo dispositivo informático no puede acomodar la memoria de video, y también puede garantizar que un solo dispositivo informático pueda acomodar el parámetro A mediante la división.

La estructura FFN en Transformer contiene dos capas completamente conectadas (FC), es decir, hay dos multiplicaciones de matrices, y estas dos multiplicaciones de matrices adoptan los dos métodos de segmentación anteriores, como se muestra en la Figura 4.12. La matriz de parámetros de la primera capa FC se corta en bloques por columnas y la matriz de parámetros de la segunda capa FC se corta en bloques por filas. De esta manera, la salida de la primera capa FC cumple exactamente con los requisitos de entrada de datos de la segunda capa FC (dividida en columnas), por lo que se puede omitir la operación de comunicación resumida después de la primera capa FC. El paralelismo tensorial del mecanismo de autoatención de múltiples cabezas es similar a FFN. Debido a que tiene múltiples cabezas independientes, es más fácil lograr el paralelismo que FFN. Su método de segmentación matricial se muestra en la Figura 4.13. Para más detalles, consulte [130].

La última capa de la red de clasificación generalmente utiliza los operadores Softmax y Cross_entropy para calcular la pérdida de entropía cruzada (Cross Entropy Loss). Si el número de categorías es muy grande, la memoria de un solo dispositivo informático no podrá almacenar ni calcular la matriz logit. Para este tipo de operador, se puede dividir según la dimensión de categoría y, al mismo tiempo, la pérdida de entropía cruzada global final se puede obtener mediante la comunicación de resultados intermedios.

Figura 11 Ejemplo de división paralela de un tensor de operador de multiplicación de matrices de dos nodos por filas

Figura 12 Diagrama paralelo del tensor de estructura FNN

Lo primero que hay que calcular es el valor de softmax, la fórmula es la siguiente:

Entre ellos, p representa el número de dispositivo de paralelismo tensorial. Después de obtener el resultado del cálculo de Softmax, la etiqueta Target se divide por categoría al mismo tiempo y cada dispositivo recibe parte de la pérdida. Finalmente, se realiza otra comunicación para obtener la pérdida de todas las categorías. Todo el proceso solo requiere tres pequeñas cantidades de comunicación para completar el cálculo de la pérdida de entropía cruzada. PyTorch proporciona una API paralela de nivel tensor detallada, DistributedTensor. También proporciona una API de nivel de modelo de grano grueso para realizar paralelismo tensorial en "nn.Module". Puedes fragmentar un tensor grande con las siguientes líneas de código:

importar antorcha
desde torch.distributed._tensor importar DTensor, DeviceMesh, Shard, distribuir_tensor
# construir una malla de dispositivos con los dispositivos disponibles (multihost o host único)
dispositivo_mesh = DispositivoMesh("cuda", [0, 1, 2, 3])
# si queremos realizar fragmentación por filas
rowwise_placement=[Fragmento(0)]
# si queremos realizar fragmentación según columnas
colwise_placement=[Fragmento(1)]
big_tensor = antorcha.randn(888, 12)
# tensor distribuido devuelto se fragmentará en la dimensión especificada en las ubicaciones
tensor_filas = distribuir_tensor(tensor_grande, malla_dispositivo=malla_dispositivo, ubicaciones=colocación_filas)

Para módulos como "nn.Linear" que ya tienen "torch.Tensor" como parámetro, también se proporciona la API a nivel de módulo "distribute_module" para realizar el paralelismo tensorial a nivel de modelo.

importar antorcha
desde torch.distributed._tensor importar DeviceMesh, Shard, distribuir_tensor, distribuir_module
clase MiMódulo(nn.Módulo):
    def __init__(yo):
        super().__init__()
        self.fc1 = nn.Lineal(8, 8)
        self.fc2 = nn.Lineal(8, 8)
        self.relu = nn.ReLU()
        def adelante(yo, entrada):
            devolver self.relu(self.fc1(entrada) + self.fc2(entrada))
    malla = DeviceMesh(device_type="cuda", malla=[[0, 1], [2, 3]])
    def shard_params(mod_name, mod, malla):
        rowwise_placement = [Fragmento(0)]
        def to_dist_tensor(t): devuelve distribuir_tensor(t, malla, ubicación_filas)
        mod._apply(to_dist_tensor)
    sharded_module = distribuir_module(MyModule(), malla, partición_fn=shard_params)
    def shard_fc(mod_name, mod, malla):
        rowwise_placement = [Fragmento(0)]
        si mod_name == "fc1":
            mod.weight = torch.nn.Parameter(distribute_tensor(mod.weight, mesh, rowwise_placement))
    sharded_module = distribuir_module(MyModule(), malla, partición_fn=shard_fc)

2.3 Paralelismo híbrido

El paralelismo híbrido (HP) es una combinación de múltiples estrategias paralelas, como el paralelismo de datos, el paralelismo de tuberías y el paralelismo tensorial. Al combinar diferentes estrategias paralelas, el paralelismo híbrido puede aprovechar al máximo varias estrategias paralelas para maximizar el rendimiento y la eficiencia informática.

Para modelos de lenguaje grandes con una escala de cientos de miles de millones, generalmente se usa una estrategia de tensor paralelo dentro de cada servidor. Dado que esta estrategia implica una gran cantidad de comunicación de red, es necesario utilizar un ancho de banda de comunicación de alta velocidad entre diferentes dispositivos informáticos dentro del servidor. servidor. A través del paralelismo de tuberías, las diferentes capas del modelo se dividen en múltiples etapas y cada etapa se calcula mediante una máquina diferente. De esta manera, se puede utilizar plenamente la potencia informática de varias máquinas y los resultados de los cálculos y los datos intermedios se pueden transferir mediante comunicación de alta velocidad entre máquinas para mejorar la velocidad y la eficiencia informática general.

Finalmente, la estrategia de datos paralelos se superpone en la capa exterior para aumentar el número de concurrencias y mejorar la velocidad general de entrenamiento. Mediante el paralelismo de datos, los datos de entrenamiento se distribuyen a múltiples grupos de servidores para su procesamiento en paralelo, y cada grupo de servidores procesa diferentes lotes de datos. Esto puede aprovechar al máximo los recursos informáticos de múltiples servidores y aumentar la simultaneidad del entrenamiento, acelerando así la velocidad general del entrenamiento.

BLOOM utiliza el marco Megatron-DeepSpeed[104] para el entrenamiento, que consta principalmente de dos partes: Megatron-LM proporciona capacidades tensoriales paralelas y primitivas de carga de datos DeepSpeed ​​​​proporciona el optimizador ZeRO, el canal de modelos y los componentes de entrenamiento distribuidos convencionales. De esta manera, se puede lograr el paralelismo tridimensional de datos, tensores y canalizaciones. La estructura de computación paralela utilizada en el entrenamiento del modelo BLOOM se muestra en la Figura 14.

El entrenamiento del modelo BLOOM utiliza un clúster de 48 servidores NVIDIA DGX-A100. Cada servidor DGX-A100 contiene 8 GPU NVIDIA A100 de 80 GB, con un total de 384. La estrategia adoptada en el entrenamiento de BLOOM es dividir primero el clúster en grupos de 48 para la paralelización de datos.

A continuación, el modelo completo se divide en 12 etapas para la paralelización de la tubería. El modelo de cada etapa se divide en 4 GPU para paralelismo tensorial. Al mismo tiempo, BLOOM también utiliza ZeRO (Zero Redundancy Optimizer) [134] para reducir aún más la ocupación de la memoria de video del modelo. A través de los cuatro pasos anteriores, se puede lograr una computación paralela eficiente de cientos de GPU.

Figura 14 Estructura de computación paralela utilizada en el entrenamiento del modelo BLOOM

2.4 Optimización de la memoria del dispositivo informático

El entrenamiento actual de modelos de lenguaje grande generalmente utiliza el algoritmo de optimización de Adam, que requiere un impulso de primer orden (Momentum) y un impulso de segundo orden (Variance), además del gradiente de cada parámetro. Aunque el algoritmo de optimización de Adam es generalmente mejor y más estable que el algoritmo SGD, consume mucha más memoria en el dispositivo informático.

Para reducir el uso de memoria, la mayoría de los sistemas han adoptado el método Mixed Precision Training, es decir, hay valores en formatos FP16 (coma flotante de 16 bits) o BF16 (Bfloat16) y FP32 (coma flotante de 32 bits). . FP32, FP16 y BF16 se representan como se muestra en la Figura 4.15. En FP32, el bit 31 es el bit de signo, los bits 30 a 23 se utilizan para representar el exponente y los bits 22 a 0 se utilizan para representar la mantisa. En FP16, el bit 15 es el bit de signo, los bits 14 a 10 se utilizan para representar el exponente y los bits 9 a 9 se utilizan para representar la mantisa. En BF16, el bit 15 es el bit de signo, los bits 14 a 7 se utilizan para representar el exponente y los bits 6 a 0 se utilizan para representar la mantisa. Dado que el rango de valores de FP16 es mucho más pequeño que el de FP32, pueden ocurrir fácilmente desbordamientos y subdesbordamientos durante el proceso de cálculo. En comparación con FP16, BF16 cambia la precisión por un rango de valores más amplio. Sin embargo, debido a la menor precisión de FP16 y BF16 en comparación con FP32, pueden ocurrir problemas de desaparición de gradiente e inestabilidad del modelo durante el proceso de entrenamiento.

Por lo tanto, es necesario utilizar algunas tecnologías para resolver estos problemas, como el escalado de pérdida dinámica (Dynamic Loss Scaling) y el optimizador de precisión mixta (Mixed Precision Optimizer). El proceso de optimización de precisión mixta se muestra en la Figura 4.16. El estado del optimizador Adam incluye una copia de seguridad de los parámetros del modelo guardados en FP32, y el impulso de primer orden y el impulso de segundo orden también se almacenan en formato FP32. Suponiendo que el número de parámetros del modelo es Φ, y que los parámetros y gradientes del modelo se almacenan en formato FP16, se requiere un total de 2Φ + 2Φ + (4Φ + 4Φ + 4Φ) = 16Φ bytes de almacenamiento.

Entre ellos, el estatus de Adam representa el 75%. Antes de la retropropagación de escala de pérdida dinámica, el cambio de pérdida (dLoss) se aumenta manualmente 2K veces, por lo que el gradiente de la función de activación obtenido durante la retropropagación no se desbordará, el gradiente de peso se reduce 2K veces y se restablece a los valores normales. Por ejemplo, para un modelo que contiene 7.500 millones de parámetros, si se utiliza el formato FP16, solo se requieren 15 GB de memoria del dispositivo informático, pero el estado del modelo en realidad consume 120 GB durante la fase de entrenamiento.

Además del estado del modelo, la memoria ocupada por la tarjeta de computadora también tiene estados residuales (Estados residuales), incluidos valores de activación (Activación), varios búferes temporales (Buffers) y fragmentos de memoria de video inutilizables (Fragmentación), etc. Dado que el valor de activación puede utilizar puntos de control para reducir en gran medida la huella de memoria del valor de activación, cómo reducir el estado del modelo, especialmente el estado del optimizador Adam, es la clave para resolver el problema de la huella de memoria.

Figura 16 Proceso de optimización de precisión mixta

Lo anterior es mi breve introducción a los conceptos básicos de los sistemas distribuidos de aprendizaje automático, la arquitectura de clústeres de capacitación distribuida y las estrategias paralelas de capacitación distribuida. DeepSpeed ​​​​es un ejemplo de cómo entrenar un modelo de lenguaje grande en un clúster que continuaré presentando. Te lo enviamos en el próximo artículo. Bienvenido a que te guste. Presta atención y apoyo, tu apoyo es la fuerza impulsora de mi creación.

Contenido de referencia:

(1) Colección 丨 Intercambio de 30 grandes conjuntos de datos relacionados con el entrenamiento de modelos de lenguaje: Zhihu https://zhuanlan.zhihu.com/p/612243919.

(2) Cuatro métodos de procesamiento comunes para datos de entrenamiento de modelos de lenguaje grandes: Zhihu https://zhuanlan.zhihu.com/p/673045395.

(3) "Modelo de lenguaje a gran escala: de la teoría a la práctica" Zhang Qi et al —Beijing: Electronic Industry Press.

(4) Revisión de modelos de lenguaje grandes: Universidad Renmin de China http://ai.ruc.edu.cn/research/science/20230605100.html.

Haga clic para seguir y conocer las nuevas tecnologías de Huawei Cloud lo antes posible ~

 

Un programador nacido en los años 90 desarrolló un software de portabilidad de vídeo y ganó más de 7 millones en menos de un año. ¡El final fue muy duro! Los estudiantes de secundaria crean su propio lenguaje de programación de código abierto como una ceremonia de mayoría de edad: comentarios agudos de los internautas: debido al fraude desenfrenado, confiando en RustDesk, el servicio doméstico Taobao (taobao.com) suspendió los servicios domésticos y reinició el trabajo de optimización de la versión web Java 17 es la versión Java LTS más utilizada. Cuota de mercado de Windows 10. Alcanzando el 70%, Windows 11 continúa disminuyendo. Open Source Daily | Google apoya a Hongmeng para hacerse cargo de los teléfonos Android de código abierto respaldados por Docker; Electric cierra la plataforma abierta Apple lanza el chip M4 Google elimina el kernel universal de Android (ACK) Soporte para la arquitectura RISC-V Yunfeng renunció a Alibaba y planea producir juegos independientes para plataformas Windows en el futuro
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/11104017
Recomendado
Clasificación