Estás en una entrevista para Ingeniero de ML en Google. Entrevistador: Necesitamos entrenar un LLM con 1.000 GPUs. ¿Cómo te asegurarías de que todas las GPUs compartan lo que aprenden? Tú: Utiliza un servidor central de parámetros para agregar y redistribuir los pesos. Entrevista terminada. Esto es lo que te perdiste:
Un cuello de botella importante en tiempo de ejecución en el entrenamiento de varias GPU se produce durante la sincronización de GPU. Por ejemplo, en el entrenamiento de varias GPU a través del paralelismo de datos: - El mismo modelo se distribuye a diferentes GPU. - Cada GPU procesa un subconjunto diferente de todo el conjunto de datos. Compruébalo 👇
Esto provoca diferentes gradientes entre distintos dispositivos. Así que, antes de actualizar los parámetros del modelo en cada dispositivo GPU, debemos comunicar los gradientes a todos los demás dispositivos para sincronizarlos. ¡Vamos a entender dos estrategias comunes a continuación!
Algoritmo 1) All-reduce Una forma obvia es enviar los gradientes de un dispositivo a todos los demás para sincronizarlos. Pero esto utiliza un gran ancho de banda. Si cada GPU tiene "N" elementos y hay "G" GPUs, se produce una transferencia total de elementos G*(G-1)*N 👇
Podemos optimizar esto transfiriendo todos los elementos a una GPU, calculando el valor final y enviándolo de vuelta a todas las demás GPUs. Esto supone una mejora significativa. Pero ahora una sola GPU debe recibir, calcular y comunicar los gradientes, así que esto no escala.
Algoritmo 2) Reducción en anillo Fase #1) Reducir la cuota Primero, los gradientes se dividen en segmentos G en cada GPU (G = número total de GPUs). Mira esto 👇
En una iteración, cada GPU envía un segmento a la siguiente GPU: - GPU1 envía a₁ a GPU2, donde se agrega a b₁ - GPU2 envía b₂ a GPU3, donde se agrega a c₂ - GPU3 envía c₃ a GPU4, donde se agrega a d₃ - GPU4 envía d₄ a GPU1, donde se agrega a a₄ Compruébalo 👇
Este proceso se repite: - GPU1 envía (d₄+a₄) a GPU2, donde se añade a b₄. - GPU2 envía (a₁+b₁) a GPU3, donde se añade a c₁. - GPU3 envía (b₂+c₂) a GPU4, donde se añade a d₂. - GPU4 envía (c₃+d₃) a GPU1, donde se suma a a₃. Mira esto 👇
En la iteración final, los siguientes segmentos se transfieren a la siguiente GPU. Esto lleva a un estado en el que cada GPU tiene un segmento completo, y podemos transferir esos segmentos completos a todas las demás GPUs. Mira esto 👇
Fase #2) Solo compartir Ahora que cada GPU tiene un segmento completo, podemos transferir estos segmentos completos a todas las demás GPUs. El proceso se lleva a cabo de forma similar a lo que mencionamos antes, así que no entraremos en detalles completos. La Iteración 1 se muestra a continuación👇
A continuación, realizamos las iteraciones 2 y 3. Estas se llevan a cabo de forma similar a lo que aprendimos en la Fase 1. Mira esto 👇
¡Y ahí lo tienes! Los pesos de los modelos entre GPUs se han sincronizado. Aunque el total de elementos transferidos sigue siendo el mismo que en el enfoque de "maestro de GPU única", este enfoque en anillo es mucho más escalable ya que no carga toda la carga sobre una sola GPU. Mira esto 👇
Por defecto, los modelos de deep learning solo utilizan una GPU para entrenar, incluso si hay varias GPUs disponibles. Una forma ideal de entrenar modelos es distribuir la carga de entrenamiento entre múltiples GPUs. El gráfico muestra cuatro estrategias para el entrenamiento👇 multi-GPU
364.81K