Artículo

Menor latencia y mayor rendimiento con la implementación de Multi-Node DeepSeek

Ballena resplandeciente, haciendo referencia a DeepSeek

En la mayoría de los sistemas, la latencia y el rendimiento a menudo son objetivos conflictivos que requieren compromisos durante el diseño y la implementación. Por ejemplo, en modelos de lenguaje grandes y densos, aumentar el tamaño del lote puede mejorar el rendimiento, pero también aumenta la latencia; incrementar el paralelismo tensorial dentro de una sola máquina puede reducir la latencia, pero disminuye el número de réplicas, lo que lleva a un menor rendimiento.

Los modelos de Mezcla de Expertos (MoE) como DeepSeek-V3/R1 han demostrado recientemente capacidades de modelo sobresalientes y eficiencia operativa. Por ejemplo, el modelo DeepSeek-V3/R1 tiene 671 mil millones de parámetros en total, pero cada token solo utiliza 37 mil millones de parámetros durante la inferencia. Esta arquitectura de modelo presenta tanto desafíos como oportunidades para los sistemas de inferencia.

Este artículo demuestra que, contrariamente a los sistemas convencionales, los modelos MoE como DeepSeek-V3/R1 pueden lograr simultáneamente mayor rendimiento y menor latencia al utilizar más GPUs en despliegues multinodos en la mayoría de los escenarios.


Arquitecturas de Despliegue

Debido al gran número de pequeños expertos que tiene el modelo, los despliegues deben extenderse a través de múltiples dispositivos. Consideramos tanto despliegues de un solo nodo en un solo nodo con 8xH200 GPUs como despliegues multinodo en 8xH100 GPUs.

Ambas arquitecturas de despliegue aprovechan el Paralelismo de Datos, orquestado a través de nuestro planificador de solicitudes interno. La implementación del paralelismo de datos implica el lanzamiento de múltiples instancias del motor de inferencia, cada una operando independientemente para servir y mantener solicitudes. El planificador de solicitudes interactúa con el motor a través de GRPC y es responsable de distribuir las solicitudes de manera uniforme, además de facilitar la reutilización de KV, enviando solicitudes con prefijos parcialmente coincidentes a los servidores que contienen la caché. Las instancias del motor no se extienden a múltiples nodos. Opcionalmente pueden utilizar paralelismo tensorial para dividir la atención entre múltiples dispositivos. Las instancias están interconectadas a través de NVLink en el caso de un solo nodo o InfiniBand para el caso multinodo, despachando y recopilando expertos.

La configuración de despliegue de un solo nodo ofrece una latencia superior con tamaños de lote pequeños; sin embargo, el rendimiento se degrada rápidamente bajo condiciones de carga incrementada.

Para implementar el motor de servicio, lanzamos un pod por nodo alojando múltiples instancias del motor. PyTorch es responsable de configurar la comunicación distribuida y negociar la inicialización de NVSHMEM. Para la comunicación, confiamos en núcleos CUDA personalizados descritos en un artículo de blog anterior. La implementación de los dos despliegues es prácticamente idéntica, con el modelo eligiendo los núcleos correctos para usar según la infraestructura que implemente el paralelismo de expertos.


Técnicas de Paralelización

Antes de adentrarnos en nuestras comparaciones de rendimiento, es esencial comprender las estrategias clave de paralelización que hacen posible el despliegue de modelos MoE masivos como DeepSeek-V3/R1.

Paralelismo Tensorial

En la inferencia de LLM, el Paralelismo Tensorial (TP) se utiliza típicamente para reducir el uso de memoria y los cálculos por GPU, reduciendo así la latencia. Normalmente, podemos dividir Proyecciones Lineales en Capas de Atención y MLP a lo largo de las dimensiones de fila o columna, y dividir las operaciones de Atención a lo largo de la dimensión de la cabeza de atención.

Con TP, la arquitectura Llama-3 no tiene cálculos duplicados para operaciones de Proyección Lineal y Atención entre GPUs, lo que es un método de división ideal. Sin embargo, en los modelos DeepSeek-V3/R1, TP no puede lograr esto.

Los modelos DeepSeek-V3/R1 utilizan Atención Multi-Latente (MLA). Una Capa MLA primero usa una Proyección Lineal kv_a_proj para calcular el vector latente, luego usa otra Proyección Lineal kv_b_proj para transformarlo en el espacio de cada cabeza de atención. Dado que todas las cabezas de atención comparten el mismo vector latente, TP no puede dividir el vector latente, por lo que todas las Rango TP necesitan replicar los parámetros y cálculos de kv_a_proj y kv_b_proj. De manera similar, dado que MLA almacena el vector latente en la Caché KV, cada Rango TP almacena una copia idéntica de la Caché KV.

A pesar de alguna duplicación en MLA, el Paralelismo Tensorial todavía ofrece una reducción parcial en las demandas de cálculo, haciéndolo valioso para escenarios que requieren altas velocidades de salida.

Paralelismo de Expertos

Los modelos DeepSeek-V3/R1 reemplazan las Capas MLP con Capas MoE. Una Capa MoE tiene 256 expertos enrutados y un experto compartido. Cada token se envía a 8 diferentes expertos enrutados para el cálculo, y los resultados se suman ponderadamente. Cada token también se calcula en el experto compartido, y el resultado se añade al resultado de los expertos enrutados.

El Paralelismo de Expertos (EP) sirve como enfoque típico de segmentación para Capas MoE, con cada GPU gestionando 256 / EP expertos enrutados mientras mantiene una copia del experto compartido. En comparación con TP, la ventaja de EP es que puede distribuir el cálculo entre más GPUs, reduciendo el cómputo y el uso de memoria por GPU.

Antes de realizar el cálculo de expertos, todas las GPUs necesitan realizar una comunicación AllToAll para enviar tokens a las GPUs donde se encuentran los expertos correspondientes; después del cálculo de expertos, se necesita otra comunicación AllToAll para recopilar resultados de cálculos de varias GPUs y realizar la suma ponderada. Implementamos una versión optimizada de estos dos Núcleos de comunicación AllToAll, Dispatch y Combine, usando NVSHMEM. En nuestro anterior artículo de blog, detallamos la implementación, y nuestros núcleos se han liberado en GitHub.

Paralelismo de Datos

Con EP, podemos distribuir el cálculo MoE entre 128 o incluso más GPUs. Sin embargo, el cálculo MLA no se puede particionar con EP. En este punto, podemos presentar el Paralelismo de Datos (DP). Cada Grupo DP tiene una copia completa de la Capa MLA. Cada Grupo DP acepta diferentes entradas y realiza el cálculo de la Capa MLA independientemente.

La DP de la capa MLA y TP se pueden combinar, con un Grupo DP dividiéndose en múltiples Rango TP. EP de la capa MoE se puede combinar con DP/TP de la Capa MLA. EP = DP * TP. Por ejemplo, en 16 máquinas, EP128 DP32 TP4 significa distribuir expertos enrutados entre 128 GPUs, con cada 4 GPUs formando un Grupo DP, para un total de 32 Grupos DP independientes.


Un Solo Nodo vs Multinodo

Los 671 mil millones de parámetros de DeepSeek superan la capacidad de memoria de una sola máquina H100 de 8 GPUs (80 GB * 8), pero una sola máquina H200 de 8 GPUs puede acomodar completamente todo el modelo (141 GB * 8). Usando la configuración EP8 DP8 TP1, el modelo utiliza aproximadamente 100 GB de memoria por GPU, dejando aproximadamente 40 GB para la Caché KV y otros resultados intermedios. Un token ocupa 70,272 bytes de Caché KV. Suponiendo que cada solicitud tiene 5,000 tokens, cada GPU puede acomodar aproximadamente 100 solicitudes.

Queríamos entender las diferencias de rendimiento entre despliegues de un solo nodo y multinodo bajo diferentes configuraciones. Usamos una máquina H200 para el despliegue de un solo nodo y hasta 16 máquinas H100 para despliegues multinodo. Para cada entorno de despliegue, usamos combinaciones de TP 1, 2, 4, 8, y tamaños de lote por GPU de 1, 2, 4, 8, 16, 32, 64, 128. Suponemos que cada solicitud tenía una longitud de Caché KV de 5,000 tokens. También supusimos que la Predicción Multitoken (MTP) predice 1 token adicional (es decir, la longitud de consulta de cada solicitud es 2), y asumimos conservadoramente una tasa de aceptación del 60%. La figura a continuación muestra el rendimiento y la velocidad de salida para diferentes configuraciones.

El eje horizontal representa la velocidad de salida por solicitud en tokens/s. El eje vertical utiliza una escala logarítmica para mostrar el rendimiento por máquina en tokens/s. Marcamos el Frente de Pareto para cada configuración EP con diferentes líneas de colores.

En escenarios con requisitos de velocidad de salida extremadamente alta, usar EP8 DP1 TP8 de un solo nodo con un tamaño de lote de 1 puede lograr una velocidad de salida superior a 100 tokens/s, pero el rendimiento es extremadamente bajo, equivalente a la velocidad de salida. En este escenario, todo el lote tiene solo 2 tokens, que pueden enviarse a un máximo de 2*8=16 expertos, activando un total de al menos 57 mil millones de parámetros.

En el rango de velocidad de salida de 80-40 tokens/s, a medida que aumenta el rendimiento, la velocidad de salida disminuye significativamente. En contraste, EP128 tiene un rendimiento aproximadamente 5 veces mayor que el despliegue de un solo nodo a la misma velocidad de salida.

Este fenómeno se puede explicar examinando cómo se comportan los despliegues de un solo nodo: aumentar el tamaño del lote está directamente relacionado con un aumento en los expertos activados. Cuando el tamaño del lote es 1, el número promedio de expertos activados por GPU es 2 * 8 / 8 = 2. Cuando el lote es lo suficientemente grande, se activan todos los expertos, lo que significa que cada GPU activa 256 / 8 = 32 expertos. Activar más expertos significa que la GPU necesita leer más parámetros de la memoria, aumentando significativamente la presión del ancho de banda de la memoria. Dado que la fase de decodificación de los modelos de lenguaje grandes ya tiene un cuello de botella en el ancho de banda de la memoria en lugar del rendimiento de cálculo, aumentar el tamaño del lote en el despliegue de un solo nodo reduce significativamente la velocidad de salida.

La comparación de las cuatro configuraciones de despliegue multinodo (EP16, EP32, EP64 y EP128) revela que valores EP más altos desplazan el Frente de Pareto hacia mejoras simultáneas en rendimiento y velocidad de salida.

Usar un número EP más alto significa que a cada GPU se le asignan menos expertos. Por ejemplo, EP128 significa que cada GPU es responsable de 256 / 128 = 2 expertos, por lo que la presión del ancho de banda de la memoria se reduce significativamente. En otras palabras, al usar un número EP más grande, efectivamente ganamos más ancho de banda de memoria. Cuando el tamaño del lote por GPU es menor que 64, aumentar el tamaño del lote no afecta significativamente la velocidad de cálculo de expertos porque aumentar el número de entradas no aumenta significativamente la presión del ancho de banda de la memoria. Por lo tanto, observamos que al usar EP128, aumentar el tamaño del lote no afecta significativamente la velocidad de salida.

Curiosamente, en tamaños de lote más grandes (64 solicitudes por GPU), observamos un nuevo fenómeno: el rendimiento del despliegue de un solo nodo es ligeramente más alto que el despliegue multinodo. Parte de la razón es que NVLink intranodo tiene un ancho de banda más alto que InfiniBand internodo. Otra parte se debe a limitaciones en nuestra implementación. Analizaremos este fenómeno en más detalle más adelante.

Debido a las limitaciones de capacidad de memoria, la configuración EP8 DP8 TP1 no puede alcanzar un tamaño de lote de 128 por GPU, por lo que el despliegue multinodo sigue siendo una mejor opción en escenarios que buscan un mayor rendimiento.


Solapamiento de Cálculo y Comunicación

Como se mencionó brevemente anteriormente sobre el Paralelismo de Expertos, las GPUs están inactivas durante la comunicación Layer MoE. Para reducir el desperdicio y disminuir la latencia, necesitamos encontrar tareas de cálculo independientes de los datos para llenar este tiempo inactivo.

La parte superior de la figura anterior muestra el flujo de cálculo de una capa. El cálculo del MoE depende de Dispatch, y el cálculo de la siguiente capa depende del resultado de Combine.

Colocamos el experto compartido en cada GPU. De esta manera, el cálculo del experto compartido no requiere comunicación AllToAll. Por lo tanto, podemos realizar el cálculo del experto compartido inmediatamente después de Dispatch Send, luego esperar a que Dispatch Recv se complete. Llamamos a este esquema de solapamiento "Solapamiento de Dispatch".

El Solapamiento de Dispatch ofrece una implementación sencilla y una amplia aplicabilidad. Esta técnica oculta el tiempo de cálculo del experto compartido en todos los tamaños de EP y tamaños de lote.

Para aumentar aún más el solapamiento de cálculo y comunicación, utilizamos micro lotes mencionados en el informe técnico de DeepSeek para romper la dependencia de datos. Como se muestra en la parte inferior de la figura, dividimos el cálculo de una Capa Transformadora en 5 etapas:

  • Etapa 1: InputNorm, QKVProj, AppendKV, BMM

  • Etapa 2: BMM, Attn, OProj, PostNorm, Gate

  • Etapa 3: Dispatch Send, Experto Compartido

  • Etapa 4: Dispatch Recv, MoE, Combine Send

  • Etapa 5: Combine Recv

En las primeras 3 Capas Transformadoras Densas, usamos todo el lote. En las siguientes 58 Capas Transformadoras MoE, dividimos uniformemente el lote en dos micro lotes. Los dos micro lotes se ejecutan alternativamente, desplazándose por 3 etapas. Dado que no hay dependencia de datos entre estos dos micro lotes, podemos cambiar al cálculo de otro micro lote después de Dispatch Send y después de Combine Send.


Desglose de Latencia

A continuación, comparamos los efectos de la superposición a través de un experimento, así como comparamos las diferencias de rendimiento entre el despliegue de un solo nodo EP8 y el despliegue multinodo EP128. Para facilitar la comparación, utilizamos GPUs H100 para el siguiente experimento. Usamos TP1, un tamaño de lote de 128 por GPU, una longitud de consulta de 2 por solicitud y una longitud de Caché KV de 5000.

La figura anterior muestra el tiempo total empleado en una Capa Transformadora MoE y la proporción de latencia de diferentes tipos de núcleos. Excepto por Dispatch, Combine y GroupGEMM, el tiempo de ejecución de otros núcleos debería ser igual en las series EP8, EP128 NoOverlap y EP128 DispatchOverlap porque el tamaño del lote es el mismo.

Superposición

Primero comparemos los efectos de los tres métodos de superposición. NoOverlap tomó 2667µs en total, DispatchOverlap tomó 2651µs, ahorrando 16µs o solo el 0,6%. MicroBatch mostró una mejora muy significativa, tomando 1896µs, una mejora del 29%. Tanto el tiempo de Dispatch como el de Combine se redujeron significativamente. Dispatch disminuyó de 593µs a 367µs, y Combine de 1012µs a 237µs.

Tenga en cuenta que para los núcleos de cálculo, dividir un lote de tamaño 128 en dos lotes de tamaño 64 aumenta el tiempo total de ejecución. Por lo tanto, aunque el tiempo empleado en la comunicación se redujo en 1001µs, el tiempo total solo se redujo en 771µs. Explicaremos la razón usando el modelo Roofline en la sección siguiente.

Por esta razón, el micro lote no siempre mejora el rendimiento.

La figura anterior muestra la mejora del rendimiento de Microbatch en comparación con DispatchOverlap para tamaños de lote de 4 a 128. Cuando el tamaño del lote es menor de 32, el micro lote disminuye el rendimiento en un 5%-40%. Cuando el tamaño del lote es mayor o igual a 32, el micro lote puede mejorar el rendimiento en un 10%-35%.

EP8 vs EP128

Volvamos a la figura anterior y comparemos EP8 y EP128 Microbatch. EP8 tardó 1802µs en total, ligeramente menos que los 1896µs de EP128. Además del aumento del tiempo de ejecución del núcleo llevado por el micro lote mencionado anteriormente, las principales diferencias están en GroupGEMM utilizado para el cálculo MoE, y los dos núcleos de comunicación, Dispatch y Combine.

El GroupGEMM de EP8 tomó 555µs, mientras que el GroupGEMM de EP128 tomó 270µs, reduciéndose a la mitad. Esta es la ventaja principal del despliegue multinodo.

Lamentablemente, el tiempo empleado en la comunicación aumentó en 213µs, lo que compensó en gran medida la ventaja de GroupGEMM. En pruebas de rendimiento separadas de nuestros núcleos de comunicación, encontramos que solo pueden alcanzar la mitad del ancho de banda de Infiniband. Continuaremos optimizando nuestros núcleos de comunicación.

Otro núcleo que se queda atrás significativamente es GEMM. El micro lote aumentó GEMM en 95µs. Analizaremos GEMM con más profundidad en la sección Roofline a continuación. Creemos que la implementación actual de GEMM aún no ha alcanzado el rendimiento óptimo.

Roofline

El Modelo Roofline es una buena herramienta para analizar el rendimiento de los núcleos. Su eje horizontal es la Intensidad Aritmética, la proporción de FLOP a bytes de E/S de memoria. El valor del eje horizontal se puede calcular directamente a partir de la semántica del núcleo. El eje vertical representa el rendimiento alcanzado, calculado dividiendo FLOP por la latencia de referencia.

El límite teórico superior del rendimiento del núcleo está determinado directamente por las especificaciones de la GPU. El rendimiento máximo FP8 del H100 es de 1979 TFLOP/s, representado como una línea horizontal en el modelo Roofline. El ancho de banda de la memoria del H100 es de 3.35 TB/s, representado como la pendiente de una línea que pasa por el origen. Las dos líneas dan los límites de rendimiento para núcleos limitados por el cálculo y limitados por la memoria, respectivamente.

A continuación, discutimos el rendimiento de los núcleos GroupGEMM y GEMM.

GroupGEMM

El núcleo GroupGEMM en MoE realiza el siguiente cálculo: Hay g grupos en total, el i-ésimo grupo tiene m_i tokens, realizando una multiplicación de matrices de [m_i, k] x [k, n] -> [m_i, n]. En pruebas de rendimiento, asumimos que el número de tokens en cada grupo es el mismo, denotado como m_i = m. Entonces, la cuenta de FLOP para GroupGEMM es 2 * g * m * k * n, y los bytes de E/S de memoria son g * (m * k + n * k + m * n).

En el modelo DeepSeek-V3/R1, hay 256 expertos, y cada token se envía a 8 expertos para el cálculo. Suponiendo un tamaño de lote de 128, longitud de consulta de 2, usando la configuración EP128 DP128, el número promedio de tokens recibidos por cada experto (es decir, m) es 128 * 2 * 8 * 128 / 256 = 1024. De manera similar, podemos calcular m para otras configuraciones y tamaños de lote.

Utilizamos la implementación GroupGEMM de DeepGEMM para pruebas de rendimiento. Los puntos de prueba cubrieron combinaciones de configuraciones EP8, EP16, EP32, EP64, EP128 con TP1 y tamaños de lote de 1 a 128.

La figura anterior muestra el modelo Roofline para GroupGEMM bajo diferentes configuraciones EP. Diferentes EP corresponden a diferentes números de grupos. La figura ilustra líneas de rendimiento casi superpuestas, indicando que el rendimiento de GroupGEMM está predominantemente determinado por el conteo total de tokens (representado como g * m).

Las estrellas marcan los puntos de datos correspondientes a un tamaño de lote de 128 por GPU para cada configuración EP. Comparando estos puntos de datos marcados con estrellas, podemos ver que a medida que aumenta EP (y DP aumenta sincrónicamente), también aumenta el número de tokens por experto m. En EP8, m=128, mientras que en EP128, m=2048.

A medida que m aumenta, la Intensidad Aritmética también aumenta. En la mayoría de configuraciones, GroupGEMM está limitado por el ancho de banda de la memoria, por lo que aumentar m mejora el rendimiento.

GEMM

El núcleo GEMM corresponde a Proyecciones Lineales en el modelo, como las Proyecciones Q/K/V/O. Para una multiplicación de matrices de [m, k] x [k, n] -> [m, n], la cuenta FLOP es 2 * m * k * n, y los bytes de E/S de memoria son m * k + n * k + m * n. También podemos probar la latencia para tamaños de lote de 1 a 128.

La figura anterior muestra el modelo Roofline para GEMM bajo diferentes configuraciones EP. Podemos ver que el rendimiento de GEMM está limitado por el ancho de banda de la memoria. A medida que aumenta el tamaño del lote, la Intensidad Aritmética también aumenta, mejorando así el rendimiento.

Microbatch

Cuando se usa el micro lote, dividimos el lote uniformemente en dos partes. De las dos figuras anteriores, podemos ver que cuando m se convierte en m/2, la eficiencia de la multiplicación de matrices disminuye. Por lo tanto, ejecutar dos multiplicaciones de matrices de tamaño m/2 lleva más tiempo que ejecutar una multiplicación de matrices de tamaño m.

Predicción Multitoken

A lo largo de este artículo, hemos asumido el uso de la Predicción Multitoken (MTP) para la decodificación especulativa. MTP cambia la longitud de la consulta por solicitud de 1 a 2. Para la multiplicación de matrices, esto es equivalente a cambiar m a m * 2, aumentando así la eficiencia de la multiplicación de matrices. Por otro lado, si dibujáramos el modelo Roofline para MLA, encontraríamos que aumentar la longitud de la consulta aumenta significativamente la eficiencia del núcleo MLA.

Por lo tanto, el uso de MTP juega un papel importante en la eficiencia del modelo.

Implementación y Optimizaciones

En esta sección, presentaremos algunos detalles de implementación y optimización para nuestro modelo DeepSeek-V3/R1.

Cuantización

DeepSeek-V3/R1 se entrenó nativamente en FP8 usando un esquema de cuantización por bloque, con pesos cuantizados estáticamente y activaciones cuantizadas sobre la marcha. En lugar de calcular un factor de escala por canal o por matriz de manera estática, los factores de escala se calculan a través de vectores de 128 elementos para activaciones y bloques de elementos de 128x128 para matrices, limitando la degradación de precisión debido a la cuantización.

En Perplexity, confiamos en una mezcla de núcleos CUDA y Triton para admitir la inferencia, siendo CUDA utilizado para los núcleos más sensibles al rendimiento y menos frecuentemente modificados (como atención y GEMM), con Triton implementando una amplia gama de núcleos de activación, normalización y utilidad. Triton nos permitió adaptar rápidamente los núcleos al esquema de cuantización por bloques.

Para capas lineales y MoE, mezclamos los núcleos Deep GEMM con nuestros propios núcleos Triton GEMM, ya que hemos observado que para ciertas dimensiones de matrices y tamaños de lotes pequeños, Split-K ofrece menor latencia. Si la capa no cuantizada realiza una multiplicación (M, K) x (K, N), necesita (M x ceil_div(K, 128)) x (ceil_div(K, 128), ceil_div(N, 128)) factor de escala para la cuantización en bloques. Para la cuantización en bloques, los factores de escala para activaciones se calculan sobre la marcha, en lugar de ser precalibrados. Dado que los factores de escala de activación se agregan solo a lo largo de la dimensión K y no a lo largo de la dimensión M, los núcleos requieren solo ligeras alteraciones para admitir el esquema.

La función de activación SiLU utilizada por DeepSeek-V3/R1 requería cambios sustanciales para admitir gráficos CUDA, cuantización por bloques y cuentas de tokens enrutados dinámicamente. La cuantización por bloques puede ser problemática ya que introduce reducciones horizontales, sin embargo, el núcleo ya dividía activaciones a lo largo de su dimensión oculta en bloques de 1024 elementos. Dentro de un bloque, el tensor a cuantizar se dividía además en bloques de 128 para calcular el valor absoluto más grande, con Triton generando eficientes reducciones máximas entre warps, agregando una sobrecarga mínima.

Para admitir el enrutamiento MoE bajo gráficos CUDA, los núcleos deben estar al tanto de la información de enrutamiento que indica el número de tokens por experto, en lugar de programar el trabajo basado en el tamaño de los búferes que estaban asignados para mantener el límite superior de los conteos de tokens. No podemos dividir el problema en función de las dimensiones del tensor de entrada, por lo que lanzamos un número fijo de núcleos persistentes que leen la información de enrutamiento para determinar cuántos tokens se están poblando y dividir el trabajo de procesar las activaciones entre ellos dinámicamente.

Ya hemos hecho upstream de algunos de nuestros núcleos al proyecto FlashInfer y en el futuro estaremos liberando más de nuestro código.

Capa MLA

Usamos FlashInfer para el cálculo MLA. FlashInfer admite configuraciones de Tabla de Páginas flexibles y un rendimiento extremadamente alto.

Fusionamos q_a_proj y kv_a_proj en un solo qkv_a_proj. La latencia disminuyó de 15.4 µs + 14.8 µs = 30.2 µs a 16.7 µs.

Descomponemos kv_b_proj en dos matrices, k_b_proj y v_b_proj. Escribimos un núcleo FP8 Block Quantized BMM para cálculos relacionados con estas dos matrices.

Gráfico Cuda

El Gráfico Cuda puede reducir significativamente la sobrecarga de lanzamiento de núcleos, lo cual es crucial para el rendimiento. Creamos un Gráfico Cuda para cada tamaño de lote.

Antes de desarrollar nuestro Núcleo AllToAll, usábamos torch.all_to_all_single() para la comunicación AllToAll. Esta operación requiere que todas las GPUs utilicen el mismo tamaño de lote. Sin embargo, diferentes Grupos DP pueden ejecutar diferentes tamaños de lote.

Para asegurar que all_to_all_single() sea compatible con diferentes Grupos DP usando diferentes tamaños de lote, primero utilizamos una operación allreduce() antes de cada ejecución del modelo para obtener el tamaño de lote máximo entre todos los Grupos DP. Luego hicimos que todos los Grupos DP usaran este tamaño de lote para correr.

Aunque este enfoque asegura que podamos usar el Gráfico Cuda, tiene tres desventajas. Primero, requiere una operación allreduce() adicional. Segundo, los Grupos DP con tamaños de lote más pequeños se ven obligados a rellenar. Tercero, hace que nuestro código de implementación sea complejo.

Después de implementar nuestro propio Núcleo AllToAll, ya no requerimos que todas las GPUs usen el mismo tamaño de lote. Por lo tanto, ya no necesitamos realizar operaciones allreduce() adicionales ni rellenar tamaños de lote.

Enrutador MoE

El enrutador MoE está implementado en Triton, confiando en una clasificación modificada derivada de la biblioteca estándar que también lleva un registro de los índices de los elementos ordenados. La implementación se comparte entre todos los modelos MoE, ya que el enrutamiento Mixtral es un caso especial de las rutas DeepSeek donde el grupo Top-K es el mismo que el grupo de todos los expertos. Los núcleos dispersos consumen directamente los índices y puntajes Top-K, mientras que los esquemas de despacho/combinación densos que dependen de all-to-all requieren que la información de enrutamiento se agregue por experto en lugar de una base por token.

Trabajo Futuro

En trabajos futuros, planeamos optimizar aún más el rendimiento del modelo DeepSeek.

La próxima optimización más importante es la Desagregación de Prellenado. Las fases de Prellenado y Decodificación del modelo DeepSeek-V3/R1 tienen características computacionales muy diferentes. Ambas pueden usar diferentes estrategias de optimización y esquemas de despliegue.

Para la Capa MLA, en la fase de Decodificación, usamos Absorción de Matrices para reducir la cuenta de FLOP del cálculo MLA. En la fase de Prellenado, primero proyectar el vector latente en el espacio K/V y luego calcular en forma de Atención Multi-Cabezal (MHA) tendría un mejor rendimiento.

Si Prellenado y Decodificación se ejecutan en la misma GPU, para reducir el impacto de Prellenado en la velocidad de salida de Decodificación, típicamente usamos prellenado segmentado para dividir la consulta en múltiples segmentos para Prellenado. Dado que la Caché KV almacena el vector latente, es difícil convertir MLA en forma MHA.

Para la Capa MoE, en la fase de Decodificación, usamos el EP y DP más grandes posibles para aumentar el número de tokens de entrada por experto, mejorando así el rendimiento de GroupGEMM. En la fase de Prellenado, debido a que el número de tokens ya es lo suficientemente grande, GroupGEMM ya está limitado por el cómputo. Por lo tanto, para Prellenado, podemos usar EP y DP más pequeños.

Si Prellenado y Decodificación se ejecutan en la misma GPU, siempre que cualquier Grupo DP esté realizando Prellenado, la latencia de Capas MoE en todas las GPUs aumentará, afectando significativamente la velocidad de salida de Decodificación.

Además de la Desagregación de Prellenado, también planeamos optimizar los siguientes aspectos:

  • Rendimiento AllToAll: Nuestro núcleo AllToAll actualmente solo puede alcanzar 1/3 del ancho de banda de Infiniband. Continuaremos optimizando este núcleo.

  • Decodificación especulativa estilo EAGLE: En los datos anteriores, asumimos el uso de decodificación especulativa para predecir 1 token. EAGLE puede usar una estructura de árbol para predecir múltiples tokens, mejorando la longitud de aceptación, lo que puede aumentar significativamente la velocidad de salida.

  • Núcleo GEMM: En el Modelo Roofline mostrado anteriormente, encontramos que la eficiencia del núcleo GEMM aún está lejos del límite teórico. Continuaremos optimizando este núcleo.

  • GB200 NVL72: En la última solución GB200 NVL72 de NVIDIA, 72 GPUs Blackwell están interconectadas a través de NVLink de alta velocidad. Para modelos de arquitectura MoE, esto es una gran oportunidad y desafío.

Conclusión

El despliegue multinodo de modelos DeepSeek MoE logra lo que típicamente es imposible con LLMs densos: mejorar simultáneamente tanto el rendimiento como la latencia. Al distribuir expertos entre más GPUs, reducimos la presión del ancho de banda de memoria por dispositivo, permitiendo un procesamiento más rápido y un mayor rendimiento del sistema. Nuestros experimentos muestran configuraciones EP128 logrando hasta 5x mayor rendimiento a velocidades de salida equivalentes en comparación con despliegues de un solo nodo.

Técnicas de solapamiento de cálculo-comunicación como micro lotes reducen significativamente la sobrecarga de comunicación multinodo, con nuestra implementación mostrando hasta un 40% de aumento de velocidad. Nuestros núcleos de comunicación AllToAll personalizados e implementaciones optimizadas de núcleos han permitido el despliegue eficiente del modelo de 671 mil millones de parámetros.

A medida que las arquitecturas MoE ganan popularidad por sus capacidades, estas estrategias de despliegue proporcionan valiosos conocimientos para escalar tales modelos eficientemente.

Referencias

¿Interesado en dar forma al futuro de nuestra plataforma API? Estamos contratando.

Únete a nuestra comunidad de desarrolladores para estar al tanto de nuevos lanzamientos, características y actualizaciones.

¿Interesado en dar forma al futuro de nuestra plataforma API? Estamos contratando.

Únete a nuestra comunidad de desarrolladores para estar al tanto de nuevos lanzamientos, características y actualizaciones.

¿Interesado en dar forma al futuro de nuestra plataforma API? Estamos contratando.

Únete a nuestra comunidad de desarrolladores para estar al tanto de nuevos lanzamientos, características y actualizaciones.