Menor latência e maior vazão com implantação multi-nó DeepSeek
A implantação de várias GPUs aumenta o desempenho do modelo MoE em velocidade e escala simultaneamente
Na maioria dos sistemas, a latência e a vazão costumam ser objetivos conflitantes que exigem concessões durante o projeto e a implantação. Por exemplo, em modelos de linguagem grandes e densos, o aumento do tamanho do lote pode melhorar a vazão, mas também aumenta a latência; o aumento do paralelismo de tensores em uma única máquina pode reduzir a latência, mas diminui o número de réplicas, levando a uma menor vazão.
Modelos Mixture of Experts (MoE) como o DeepSeek-V3/R1 demonstraram recentemente excelentes capacidades de modelo e eficiência operacional. Por exemplo, o modelo DeepSeek-V3/R1 possui 671B parâmetros no total, mas cada token usa apenas 37B parâmetros durante a inferência. Essa arquitetura de modelo apresenta desafios e oportunidades para sistemas de inferência.
Este artigo demonstra que, ao contrário dos sistemas convencionais, modelos MoE como o DeepSeek-V3/R1 podem atingir simultaneamente maior vazão e menor latência ao utilizar mais GPUs em implantações multi-nó na maioria dos cenários.
Arquiteturas de Implantação
Devido ao grande número de pequenos especialistas que o modelo possui, as implantações devem ser distribuídas por vários dispositivos. Consideramos implantações em nó único em um único nó com GPUs 8xH200 e implantações multi-nó em GPUs 8xH100.
Ambas as arquiteturas de implantação aproveitam o paralelismo de dados, orquestrado por nosso agendador de solicitações interno. A implementação do paralelismo de dados envolve a inicialização de várias instâncias de mecanismo de inferência, cada uma operando de forma independente para atender e manter solicitações. O agendador de solicitações, que interage com o mecanismo por meio de GRPC, é responsável por distribuir as solicitações o mais uniformemente possível, além de facilitar a reutilização de KV, enviando solicitações com prefixo correspondente parcial para os servidores que contêm o cache. As instâncias do mecanismo não abrangem vários nós. Elas podem opcionalmente usar o paralelismo de tensores para fragmentar a atenção em vários dispositivos. As instâncias são interconectadas via NVLink no caso de nó único ou InfiniBand para o caso multi-nó, despachando e coletando especialistas.
A configuração de implantação de nó único oferece latência superior com tamanhos de lote pequenos; no entanto, o desempenho degrada rapidamente em condições de carga aumentada.
Para implantar o mecanismo de atendimento, lançamos um pod por nó hospedando várias instâncias de mecanismo. O PyTorch é responsável por configurar a comunicação distribuída e negociar a inicialização do NVSHMEM. Para comunicação, contamos com kernels CUDA personalizados descritos em uma postagem de blog anterior. A implementação das duas implantações é praticamente idêntica, com o modelo escolhendo os kernels corretos para usar com base no tecido que implementa o paralelismo de especialistas.
Técnicas de paralelização
Antes de mergulhar em nossas comparações de desempenho, é essencial entender as principais estratégias de paralelização que tornam possível a implantação de modelos MoE massivos como o DeepSeek-V3/R1.
Paralelismo de Tensores
Na inferência de LLM, o paralelismo de tensores (TP) é normalmente usado para reduzir o uso de memória e a computação por GPU, reduzindo assim a latência. Geralmente, podemos fragmentar projeções Linear em camadas de atenção e MLP ao longo das dimensões de linha ou coluna, e fragmentar operações de atenção ao longo da dimensão da cabeça de atenção.
Com o TP, a arquitetura Llama-3 não tem computação duplicada para operações de projeção Linear e atenção entre GPUs, o que é um método de fragmentação ideal. No entanto, nos modelos DeepSeek-V3/R1, o TP não pode alcançar isso.
Os modelos DeepSeek-V3/R1 usam Multi-Latent Attention (MLA). Uma camada MLA primeiro usa uma projeção Linear kv_a_proj para calcular o vetor latente, depois usa outra projeção Linear kv_b_proj para transformá-lo no Espaço de cada cabeça de atenção. Como todas as cabeças de atenção compartilham o mesmo vetor latente, o TP não pode fragmentar o vetor latente, de modo que todas as classificações TP precisam replicar os parâmetros e a computação de kv_a_proj e kv_b_proj. Da mesma forma, como o MLA armazena o vetor latente no cache KV, cada classificação TP armazena uma cópia idêntica do cache KV.
Apesar de alguma duplicação no MLA, o paralelismo de tensores ainda fornece redução parcial nas demandas de computação, tornando-o valioso para cenários que exigem altas velocidades de saída.
Paralelismo de Especialistas
Os modelos DeepSeek-V3/R1 substituem as camadas MLP por camadas MoE. Uma camada MoE tem 256 especialistas roteados e um especialista compartilhado. Cada token é despachado para 8 especialistas roteados diferentes para computação, e os resultados são somados com pesos. Cada token também é computado no especialista compartilhado, e o resultado é adicionado ao resultado dos especialistas roteados.
O paralelismo de especialistas (EP) serve como a abordagem de fragmentação típica para camadas MoE, com cada GPU gerenciando 256 / EP especialistas roteados, mantendo uma cópia do especialista compartilhado. Comparado ao TP, a vantagem do EP é que ele pode distribuir a computação por mais GPUs, reduzindo a computação e o uso de memória por GPU.
Antes de realizar a computação de especialistas, todas as GPUs precisam realizar uma comunicação AllToAll para despachar tokens para as GPUs onde os especialistas correspondentes estão localizados; após a computação de especialistas, outra comunicação AllToAll é necessária para coletar os resultados da computação de várias GPUs e realizar a soma ponderada. Implementamos uma versão otimizada desses dois kernels de comunicação AllToAll, Dispatch e Combine, usando o NVSHMEM. Em nossa postagem de blog anterior, detalhamos a implementação, e nossos kernels foram abertos no GitHub.
Paralelismo de Dados
Com o EP, podemos distribuir a computação MoE por 128 ou até mais GPUs. No entanto, a computação MLA não pode ser particionada com EP. Nesse ponto, podemos introduzir o paralelismo de dados (DP). Cada grupo DP tem uma cópia completa da camada MLA. Cada grupo DP aceita entradas diferentes e realiza a computação da camada MLA de forma independente.
O DP e o TP da camada MLA podem ser combinados, com um grupo DP sendo dividido em várias classificações TP. O EP da camada MoE pode ser combinado com o DP/TP da camada MLA. EP = DP * TP. Por exemplo, em 16 máquinas, EP128 DP32 TP4 significa distribuir especialistas roteados em 128 GPUs, com cada 4 GPUs formando um grupo DP, para um total de 32 grupos DP independentes.
Nó único vs Multi-nó
Os 671B parâmetros da DeepSeek excedem a capacidade de memória de uma única máquina H100 de 8 GPUs (80 GB * 8), mas uma única máquina H200 de 8 GPUs pode acomodar totalmente o modelo inteiro (141 GB * 8). Usando a configuração EP8 DP8 TP1, o modelo usa cerca de 100 GB de memória por GPU, deixando aproximadamente 40 GB para o cache KV e outros resultados intermediários. Um token ocupa 70.272 bytes de cache KV. Assumindo que cada solicitação tenha 5.000 tokens, cada GPU pode acomodar aproximadamente 100 solicitações.
Queríamos entender as diferenças de desempenho entre implantações de nó único e multi-nó sob diferentes configurações. Usamos uma máquina H200 para implantação de nó único e até 16 máquinas H100 para implantações multi-nó. Para cada ambiente de implantação, usamos combinações de TP 1, 2, 4, 8 e tamanhos de lote por GPU de 1, 2, 4, 8, 16, 32, 64, 128. Assumimos que cada solicitação tinha um comprimento de cache KV de 5.000 tokens. Também assumimos que a predição multi-token (MTP) prevê 1 token adicional (ou seja, o comprimento da consulta de cada solicitação é 2) e assumimos conservadoramente uma taxa de aceitação de 60%. A figura abaixo mostra a vazão e a velocidade de saída para diferentes configurações.
O eixo horizontal representa a velocidade de saída por solicitação em tokens/s. O eixo vertical usa uma escala logarítmica para mostrar a vazão por máquina em tokens/s. Marcamos a fronteira de Pareto para cada configuração de EP com linhas de cores diferentes.
Em cenários com requisitos de velocidade de saída extremamente altos, o uso de EP8 DP1 TP8 de nó único com um tamanho de lote de 1 pode atingir uma velocidade de saída superior a 100 tokens/s, mas a vazão é extremamente baixa, equivalente à velocidade de saída. Nesse cenário, todo o lote possui apenas 2 tokens, que podem ser despachados para no máximo 2*8=16 especialistas, ativando um total de no máximo 57B parâmetros.
Na faixa de velocidade de saída de 80-40 tokens/s, à medida que a vazão aumenta, a velocidade de saída diminui significativamente. Em contraste, o EP128 tem uma vazão cerca de 5 vezes maior do que a implantação de nó único na mesma velocidade de saída.
Esse fenômeno pode ser explicado examinando como as implantações de nó único se comportam: o aumento do tamanho do lote se correlaciona diretamente com um aumento nos especialistas ativados. Quando o tamanho do lote é 1, o número médio de especialistas ativados por GPU é 2 * 8 / 8 = 2. Quando o lote é grande o suficiente, todos os especialistas são ativados, o que significa que cada GPU ativa 256 / 8 = 32 especialistas. Ativar mais especialistas significa que a GPU precisa ler mais parâmetros da memória, aumentando significativamente a pressão da largura de banda da memória. Como a fase de decodificação de grandes modelos de linguagem já é limitada pela largura de banda da memória e não pelo desempenho de computação, o aumento do tamanho do lote na implantação de nó único reduz significativamente a velocidade de saída.
A comparação das quatro configurações de implantação multi-nó (EP16, EP32, EP64 e EP128) revela que valores de EP mais altos deslocam a fronteira de Pareto em direção a melhorias simultâneas na vazão e na velocidade de saída.
O uso de um número de EP maior significa que cada GPU recebe menos especialistas. Por exemplo, EP128 significa que cada GPU é responsável por 256 / 128 = 2 especialistas, de modo que a pressão da largura de banda da memória é significativamente reduzida. Em outras palavras, ao usar um número de EP maior, ganhamos efetivamente mais largura de banda de memória. Quando o tamanho do lote por GPU é inferior a 64, o aumento do tamanho do lote não afeta significativamente a velocidade da computação de especialistas porque o aumento do número de entradas não aumenta significativamente a pressão da largura de banda da memória. Portanto, observamos que, ao usar o EP128, o aumento do tamanho do lote não afeta a velocidade de saída de forma tão significativa.
Curiosamente, em tamanhos de lote maiores (64 solicitações por GPU), observamos um novo fenômeno: a vazão da implantação de nó único é ligeiramente superior à da implantação multi-nó. Parte do motivo é que o NVLink intra-nó tem largura de banda maior que o InfiniBand inter-nó. Outra parte se deve a limitações em nossa implementação. Analisaremos esse fenômeno com mais detalhes posteriormente.
Devido a limitações de capacidade de memória, a configuração EP8 DP8 TP1 não pode atingir um tamanho de lote de 128 por GPU, portanto, a implantação multi-nó ainda é uma escolha melhor em cenários que buscam maior vazão.
Sobreposição de Computação e Comunicação
Conforme apresentado brevemente acima sobre o paralelismo de especialistas, as GPUs ficam ociosas durante a comunicação da camada MoE. Para reduzir o desperdício e diminuir a latência, precisamos encontrar tarefas de computação independentes de dados para preencher esse tempo ocioso.
A parte superior da figura acima mostra o fluxo de computação de uma camada. A computação MoE depende do Dispatch, e a computação da próxima camada depende do resultado do Combine.
Colocamos o especialista compartilhado em cada GPU. Dessa forma, a computação do especialista compartilhado não requer comunicação AllToAll. Portanto, podemos realizar a computação do especialista compartilhado imediatamente após o Dispatch Send e, em seguida, aguardar a conclusão do Dispatch Recv. Chamamos esse esquema de sobreposição de "Dispatch Overlap".
O Dispatch Overlap oferece implementação direta e ampla aplicabilidade. Essa técnica oculta o tempo de computação do especialista compartilhado em todos os tamanhos de EP e tamanhos de lote.
Para aumentar ainda mais a sobreposição de computação e comunicação, usamos o microbatching mencionado no relatório técnico da DeepSeek para quebrar a dependência de dados. Conforme mostrado na parte inferior da figura, dividimos a computação de uma camada Transformer em 5 estágios:
Estágio 1: InputNorm, QKVProj, AppendKV, BMM
Estágio 2: BMM, Attn, OProj, PostNorm, Gate
Estágio 3: Dispatch Send, Especialista Compartilhado
Estágio 4: Dispatch Recv, MoE, Combine Send
Estágio 5: Combine Recv
Nas primeiras 3 camadas Dense Transformer, usamos o lote inteiro. Nas 58 camadas MoE Transformer seguintes, dividimos o lote uniformemente em dois micro lotes. Os dois micro lotes executam alternadamente, deslocados por 3 estágios. Como não há dependência de dados entre esses dois micro lotes, podemos alternar para a computação de outro micro lote após o Dispatch Send e após o Combine Send.
Detalhamento de Latência
Em seguida, comparamos os efeitos da sobreposição por meio de um experimento, bem como as diferenças de desempenho entre a implantação de nó único EP8 e a implantação multi-nó EP128. Para facilitar a comparação, usamos GPUs H100 para o experimento a seguir. Usamos TP1, um tamanho de lote de 128 por GPU, um comprimento de consulta de 2 por solicitação e um comprimento de cache KV de 5000.
A figura acima mostra o tempo total gasto em uma camada MoE Transformer e a proporção de latência de diferentes tipos de kernels. Exceto por Dispatch, Combine e GroupGEMM, o tempo de execução de outros kernels deve ser igual nas séries EP8, EP128 NoOverlap e EP128 DispatchOverlap porque o tamanho do lote é o mesmo.
Sobreposição
Vamos primeiro comparar os efeitos dos três métodos de sobreposição. O NoOverlap levou 2667µs no total, o DispatchOverlap levou 2651µs, economizando 16µs ou apenas 0,6%. O MicroBatch mostrou uma melhoria muito significativa, levando 1896µs, uma aceleração de 29%. O tempo de Dispatch e Combine foi significativamente reduzido. O Dispatch diminuiu de 593µs para 367µs, e o Combine de 1012µs para 237µs.
Observe que para kernels de computação, dividir um lote de tamanho 128 em dois lotes de tamanho 64 aumenta o tempo total de execução. Portanto, embora o tempo gasto em comunicação tenha sido reduzido em 1001µs, o tempo total foi reduzido apenas em 771µs. Explicaremos o motivo usando o modelo Roofline na seção a seguir.
Por esse motivo, o microbatching nem sempre melhora o desempenho.
A figura acima mostra a melhoria de desempenho do Microbatch em comparação com o DispatchOverlap para tamanhos de lote de 4 a 128. Quando o tamanho do lote é menor que 32, o Microbatch diminui o desempenho em 5%-40%. Quando o tamanho do lote é maior ou igual a 32, o Microbatch pode melhorar o desempenho em 10%-35%.
EP8 vs EP128
Vamos retornar à figura anterior e comparar o EP8 e o EP128 Microbatch. O EP8 levou 1802µs no total, ligeiramente menos que os 1896µs do EP128. Além do aumento do tempo de execução do kernel trazido pelo Microbatch mencionado acima, as principais diferenças estão no GroupGEMM usado para a computação MoE e nos dois kernels de comunicação, Dispatch e Combine.
O GroupGEMM do EP8 levou 555µs, enquanto o GroupGEMM do EP128 levou 270µs, reduzindo pela metade. Esta é a principal vantagem da implantação multi-nó.
Infelizmente, o tempo gasto em comunicação aumentou em 213µs, o que compensou em grande parte a vantagem do GroupGEMM. Em testes de desempenho separados de nossos kernels de comunicação, descobrimos que eles só conseguem atingir metade da largura de banda do InfiniBand. Continuaremos a otimizar nossos kernels de comunicação.
Outro kernel que fica significativamente atrasado é o GEMM. O Microbatch aumentou o GEMM em 95µs. Analisaremos o GEMM com mais profundidade na seção Roofline abaixo. Acreditamos que a implementação atual do GEMM ainda não alcançou o desempenho ideal.
Roofline
O modelo Roofline é uma boa ferramenta para analisar o desempenho do kernel. Seu eixo horizontal é a intensidade aritmética, a razão entre FLOP e bytes de I/O de memória. O valor do eixo horizontal pode ser calculado diretamente a partir da semântica do kernel. O eixo vertical representa o desempenho alcançado, calculado dividindo FLOP pela latência do benchmark.
O limite superior teórico do desempenho do kernel é determinado diretamente pelas especificações da GPU. O pico de desempenho FP8 do H100 é 1979 TFLOP/s, representado como uma linha horizontal no modelo Roofline. A largura de banda de memória do H100 é 3,35 TB/s, representada como a inclinação de uma linha que passa pela origem. As duas linhas fornecem os limites de desempenho para kernels limitados por computação e limitados por memória, respectivamente.
Abaixo, discutimos o desempenho dos kernels GroupGEMM e GEMM.
GroupGEMM
O kernel GroupGEMM no MoE realiza a seguinte computação: Existem g grupos no total, o i-ésimo grupo tem m_i tokens, realizando uma multiplicação de matrizes de [m_i, k] x [k, n] -> [m_i, n]. No teste de desempenho, assumimos que o número de tokens em cada grupo é o mesmo, denotado como m_i = m. Então a contagem de FLOP para GroupGEMM é 2 * g * m * k * n, e os bytes de I/O de memória são g * (m * k + n * k + m * n).
No modelo DeepSeek-V3/R1, existem 256 especialistas, e cada token é despachado para 8 especialistas para computação. Assumindo um tamanho de lote de 128, comprimento de consulta de 2, usando a configuração EP128 DP128, o número médio de tokens recebidos por cada especialista (ou seja, m) é 128 * 2 * 8 * 128 / 256 = 1024. Da mesma forma, podemos calcular m para outras configurações e tamanhos de lote.
Usamos a implementação GroupGEMM do DeepGEMM para testes de desempenho. Os pontos de teste cobriram combinações de configurações EP8, EP16, EP32, EP64, EP128 com TP1 e tamanhos de lote 1-128.
A figura acima mostra o modelo Roofline para GroupGEMM sob diferentes configurações de EP. Diferentes EP correspondem a diferentes números de grupos. A figura ilustra linhas de desempenho quase sobrepostas, indicando que o desempenho do GroupGEMM é predominantemente determinado pelo número total de tokens (representado como g * m).
As estrelas marcam os pontos de dados correspondentes a um tamanho de lote de 128 por GPU para cada configuração de EP. Comparando esses pontos de dados com estrela, podemos ver que à medida que o EP aumenta (e o DP aumenta de forma síncrona), o número de tokens por especialista m também aumenta. No EP8, m=128, enquanto no EP128, m=2048.
À medida que m aumenta, a intensidade aritmética também aumenta. Na maioria das configurações, o GroupGEMM é limitado pela largura de banda da memória, portanto, aumentar m melhora o desempenho.
GEMM
O kernel GEMM corresponde a projeções Linear no modelo, como projeção Q/K/V/O. Para uma multiplicação de matrizes de [m, k] x [k, n] -> [m, n], a contagem de FLOP é 2 * m * k * n e os bytes de I/O de memória são m * k + n * k + m * n. Também podemos testar a latência para tamanhos de lote 1-128.
A figura acima mostra o modelo Roofline para GEMM sob diferentes configurações de EP. Podemos ver que o desempenho do GEMM é limitado pela largura de banda da memória. À medida que o tamanho do lote aumenta, a intensidade aritmética também aumenta, melhorando assim o desempenho.
Microbatch
Ao usar o microbatching, dividimos o lote uniformemente em duas partes. A partir das duas figuras acima, podemos ver que quando m se torna m/2, a eficiência da multiplicação de matrizes diminui. Portanto, executar duas multiplicações de matrizes de tamanho m/2 leva mais tempo do que executar uma multiplicação de matrizes de tamanho m.
Predição Multi-Token
Ao longo deste artigo, assumimos o uso de predição multi-token (MTP) para decodificação especulativa. O MTP altera o comprimento da consulta por solicitação de 1 para 2. Para a multiplicação de matrizes, isso é equivalente a alterar m para m * 2, aumentando assim a eficiência da multiplicação de matrizes. Por outro lado, se desenharmos o modelo Roofline para o MLA, descobriríamos que o aumento do comprimento da consulta aumenta significativamente a eficiência do kernel MLA.
Portanto, o uso de MTP desempenha um papel importante na eficiência do modelo.
Implementação e otimizações
Nesta seção, apresentaremos alguns detalhes de implementação e otimização para o nosso modelo DeepSeek-V3/R1.
Quantização
O DeepSeek-V3/R1 foi treinado nativamente em FP8 usando um esquema de quantização por bloco, com pesos quantizados estaticamente e ativações quantizadas dinamicamente. Em vez de calcular um fator de escala por canal ou por matriz estaticamente, os fatores de escala são calculados em vetores de 128 elementos para ativações e blocos de 128x128 elementos para matrizes, limitando a degradação da precisão devido à quantização.
Na Perplexity, contamos com uma mistura de kernels CUDA e Triton para dar suporte à inferência, sendo o CUDA usado para os kernels mais sensíveis ao desempenho e modificados com pouca frequência (como atenção e GEMM), com o Triton implementando uma ampla gama de kernels de ativação, normalização e utilidade. O Triton nos permitiu adaptar rapidamente os kernels ao esquema de quantização de bloco.
Para camadas lineares e MoE, misturamos os kernels Deep GEMM com nossos próprios kernels Triton GEMM, pois percebemos que para certas dimensões de matriz e baixos tamanhos de lote, o Split-K oferece menor latência. Se a camada não quantizada realizar uma multiplicação (M, K) x (K, N), ela precisará de um fator de escala (M x ceil_div(K, 128)) x (ceil_div(K, 128), ceil_div(N, 128)) para a quantização de bloco. Para a quantização de bloco, os fatores de escala para ativações são calculados dinamicamente, em vez de serem pré-calibrados. Como os fatores de escala de ativação são agregados apenas ao longo da dimensão K e não ao longo da dimensão M, os kernels exigem apenas pequenas alterações para dar suporte ao esquema.
A função de ativação SiLU usada pelo DeepSeek-V3/R1 exigiu alterações substanciais para dar suporte a gráficos CUDA, quantização de bloco e contagens de tokens roteadas dinamicamente. A quantização de bloco pode ser problemática, pois introduz reduções horizontais, no entanto, o kernel já dividiu as ativações ao longo de sua dimensão oculta em blocos de 1024 elementos. Dentro de um bloco, o tensor a ser quantizado foi dividido ainda mais em blocos de 128 para calcular o maior valor absoluto, com o Triton gerando reduções máximas de cross-warp eficientes, adicionando sobrecarga mínima.
Para dar suporte ao roteamento MoE sob gráficos CUDA, os kernels devem estar cientes das informações de roteamento que indicam o número de tokens por especialista, em vez de agendar o trabalho com base no tamanho dos buffers que foram alocados para conter o limite superior das contagens de tokens. Não podemos dividir o problema com base nas dimensões do tensor de entrada, então iniciamos um número fixo de kernels persistentes que leem as informações de roteamento para determinar quantos tokens são preenchidos e dividimos o trabalho de processar as ativações entre eles dinamicamente.
Já enviamos upstream alguns de nossos kernels para o projeto FlashInfer e, no futuro, abriremos mais de nosso código.
Camada MLA
Usamos o FlashInfer para a computação MLA. O FlashInfer oferece suporte a configurações de tabela de páginas flexíveis e desempenho extremamente alto.
Fundimos q_a_proj e kv_a_proj em um único qkv_a_proj. A latência diminuiu de 15,4 µs + 14,8 µs = 30,2 µs para 16,7 µs.
Decomposição kv_b_proj em duas matrizes, k_b_proj e v_b_proj. Escrevemos um kernel BMM quantizado por bloco FP8 para computações relacionadas a essas duas matrizes.
Gráfico Cuda
O gráfico Cuda pode reduzir significativamente a sobrecarga de inicialização do kernel, o que é crucial para o desempenho. Criamos um gráfico Cuda para cada tamanho de lote.
Antes de desenvolver nosso kernel AllToAll, usamos torch.all_to_all_single() para a comunicação AllToAll. Esta operação exige que todas as GPUs usem o mesmo tamanho de lote. No entanto, diferentes grupos DP podem executar tamanhos de lote diferentes.
Para garantir que all_to_all_single() seja compatível com diferentes grupos DP usando diferentes tamanhos de lote, usamos primeiro uma operação allreduce() antes de cada execução de modelo para obter o tamanho máximo de lote entre todos os grupos DP. Em seguida, fizemos com que todos os grupos DP usassem esse tamanho de lote para executar.
Embora essa abordagem garanta que possamos usar o gráfico Cuda, ela tem três desvantagens. Primeiro, ela requer uma operação allreduce() adicional. Segundo, grupos DP com tamanhos de lote menores são forçados a preencher com padding. Terceiro, ela torna nosso código de implementação complexo.
Após implementar nosso próprio kernel AllToAll, não exigimos mais que todas as GPUs usem o mesmo tamanho de lote. Portanto, não precisamos mais realizar operações allreduce() adicionais ou preencher tamanhos de lote.
Roteador MoE
O roteador MoE é implementado em Triton, contando com uma ordenação modificada derivada da biblioteca padrão que também rastreia os índices dos elementos ordenados. A implementação é compartilhada em todos os modelos MoE, pois o roteamento Mixtral é um caso especial das rotas DeepSeek em que o grupo Top-K é o mesmo que o grupo de todos os especialistas. Os kernels esparsos consomem os índices e pontuações do Top-K diretamente, enquanto os esquemas de despacho/combinação densos que dependem de all-to-all exigem que as informações de roteamento sejam agregadas por especialista em vez de por token.
Trabalho Futuro
Em trabalhos futuros, planejamos otimizar ainda mais o desempenho do modelo DeepSeek.
A próxima otimização mais importante é a desagregação de pré-preenchimento. A fase de pré-preenchimento e a fase de decodificação do modelo DeepSeek-V3/R1 têm características computacionais muito diferentes. Ambas podem usar diferentes estratégias de otimização e esquemas de implantação.
Para a camada MLA, na fase de decodificação, usamos a absorção de matrizes para reduzir a contagem de FLOP da computação MLA. Na fase de pré-preenchimento, projetar primeiro o vetor latente no Espaço K/V e, em seguida, computar no formato de atenção multi-head (MHA) funcionaria melhor.
Se o pré-preenchimento e a decodificação forem executados na mesma GPU, para reduzir o impacto do pré-preenchimento na velocidade de saída da decodificação, normalmente usamos o pré-preenchimento em blocos para dividir a consulta em vários blocos para pré-preenchimento. Como o cache KV armazena o vetor latente, torna-se difícil converter o MLA no formato MHA.
Para a camada MoE, na fase de decodificação, usamos EP e DP o maiores possível para aumentar o número de tokens de entrada por especialista, melhorando assim o desempenho do GroupGEMM. Na fase de pré-preenchimento, como o número de tokens já é grande o suficiente, o GroupGEMM já é limitado pela computação. Portanto, para o pré-preenchimento, podemos usar EP e DP menores.
Se o pré-preenchimento e a decodificação forem executados na mesma GPU, desde que qualquer grupo DP esteja realizando o pré-preenchimento, a latência das camadas MoE em todas as GPUs aumentará, afetando significativamente a velocidade de saída da decodificação.
Além da desagregação de pré-preenchimento, também planejamos otimizar os seguintes aspectos:
Desempenho AllToAll: Nosso kernel AllToAll atualmente só consegue atingir 1/3 da largura de banda do InfiniBand. Continuaremos a otimizar este kernel.
Decodificação especulativa estilo EAGLE: nos dados acima, assumimos o uso de decodificação especulativa para prever 1 token. O EAGLE pode usar uma estrutura de árvore para prever múltiplos tokens, melhorando o comprimento de aceitação, o que pode aumentar significativamente a velocidade de saída.
Kernel GEMM: No modelo Roofline mostrado anteriormente, podemos ver que a eficiência do kernel GEMM ainda está longe do limite teórico. Continuaremos a otimizar este kernel.
GB200 NVL72: Na mais recente solução GB200 NVL72 da NVIDIA, 72 GPUs Blackwell são interconectadas via NVLink de alta velocidade. Para modelos de arquitetura MoE, esta é uma grande oportunidade e desafio.
Conclusão
A implantação multi-nó de modelos DeepSeek MoE alcança o que normalmente é impossível com LLMs densos: melhorar simultaneamente a vazão e a latência. Ao distribuir especialistas por mais GPUs, reduzimos a pressão da largura de banda da memória por dispositivo, permitindo um processamento mais rápido e maior vazão do sistema. Nossos experimentos mostram que as configurações EP128 alcançam até 5x mais vazão em velocidades de saída equivalentes em comparação com implantações de nó único.
Técnicas de sobreposição de computação e comunicação, como micro-batching, reduzem significativamente a sobrecarga de comunicação multi-nó, com nossa implementação mostrando até 40% de aceleração. Nossos kernels de comunicação AllToAll personalizados e implementações de kernel otimizadas permitiram a implantação eficiente do modelo de parâmetros 671B.
À medida que as arquiteturas MoE ganham popularidade por sua capacidade, essas estratégias de implantação fornecem insights valiosos para dimensionar esses modelos de forma eficiente.
Referências
Visão Geral do Sistema de Inferência DeepSeek-V3/R1
EAGLE: Amostragem Especulativa Requer Repensar a Incerteza de Recursos
Citação
@online{perplexity2025LowerLatencyAndHigherThroughputWithMultiNodeDeepseekDeployment,
author = {{Perplexity} and Lequn Chen and Nandor Licker and Erin McKnight},
title = {{Lower latency and higher throughput with multi-node DeepSeek deployment}},
date = {2025-04-18},
url = {https://perplexity.coolkeypoint.com/hub/blog/lower-latency-and-higher-throughput-with-multi-node-deepseek-deployment}
}