Comunicação eficiente e portátil de mixture-of-experts
Uma visão geral da comunicação portátil Mixture-of-Experts (MoE), com foco na otimização do paralelismo de GPU e na redução da latência em modelos de IA em larga escala
Apresentamos uma biblioteca de alto desempenho, portátil e de código aberto para comunicação Mixture-of-Experts (MoE) que atinge um desempenho 10 vezes mais rápido em comparação com as primitivas padrão de comunicação All-to-All.
Nossa implementação apresenta várias inovações técnicas importantes que oferecem eficiência superior na comunicação de MoE:
Comunicação iniciada por GPU (IBGDA): Suporta comunicação direta de GPU para placa de rede (NIC), reduzindo significativamente a latência ao evitar o envolvimento da CPU
Sobreposição de comunicação e computação: A arquitetura de kernel dividida com estágios separados de envio e recebimento permite que a computação prossiga simultaneamente com as transferências de rede
O melhor desempenho em nó único: Latência 2,5 vezes menor do que a implementação mais rápida anterior em configurações de nó único
Desempenho multi-nó eficiente e portátil: Nossa implementação atinge velocidades até 10 vezes mais rápidas do que a comunicação padrão all-to-all. Embora seja aproximadamente 2 vezes mais lenta do que implementações altamente especializadas, nossa abordagem oferece melhor portabilidade entre versões do NVSHMEM e ambientes de rede (NVLink, CX-7 e EFA)
A biblioteca é totalmente de código aberto e está disponível em https://github.com/ppl-ai/pplx-kernels.
Neste artigo, exploramos os desafios do paralelismo de especialistas em modelos MoE de grande escala e descrevemos nossa abordagem para o despacho e combinação eficientes de tokens em ambientes de GPU distribuídos.
Introdução
Os modelos Mixture-of-Experts (MoE), como o DeepSeek R1 e o Mixtral 8x7B, aprimoram os modelos densos ao limitar o número de pesos que são ativados para cada token. Em vez de alcançar altas contagens de parâmetros aumentando o número de camadas ou o tamanho das camadas lineares no Perceptron Multicamadas (MLP) de cada camada de decodificação, os modelos MoE substituem o MLP tradicional por vários especialistas e um roteador. Por exemplo, dos 671B parâmetros do DeepSeek R1, apenas 37B são multiplicados por um determinado token durante a inferência. Isso reduz drasticamente a quantidade de computação necessária para decodificar um token e melhora a latência em comparação com um modelo denso.
Os modelos MoE apresentam alguns desafios adicionais para a inferência, em comparação com os modelos densos. Embora os próprios especialistas sejam pequenas camadas MLP, cada camada de decodificação inclui um roteador que decide para quais especialistas um token é despachado, sendo cada token despachado para vários especialistas. O roteador é tipicamente uma pequena camada linear que produz uma distribuição de probabilidade. Geralmente, os especialistas com as pontuações top-K são escolhidos e a ativação final é calculada como uma média ponderada, somando as saídas dos especialistas multiplicadas por um peso derivado da distribuição de probabilidade do roteador.
Para minimizar a latência em sistemas MoE distribuídos, o paralelismo pode ser explorado em vários dispositivos, mas isso introduz desafios de comunicação. Modelos como o Mixtral 8x7B ou o Llama-70B cabem em 8 dispositivos em um único nó, beneficiando-se de interconexões NVLink rápidas e de baixa latência (até 900 Gbps). No entanto, modelos maiores exigem a fragmentação de especialistas em vários nós usando InfiniBand (com pico de 400 Gbps), o que introduz desafios adicionais de latência.
Neste artigo, exploramos o problema do paralelismo de especialistas, descrevendo nossa implementação de kernels de GPU que despacham eficientemente tokens para dispositivos que possuem os especialistas atribuídos e os coletam de volta calculando a soma ponderada das saídas dos especialistas. Embora existam implementações agressivamente otimizadas voltadas para hardware de rede específico, apresentamos uma implementação altamente portátil que se baseia em um conjunto mínimo de primitivas do NVSHMEM, mas que oferece um desempenho 10 vezes mais rápido do que a comunicação padrão all-to-all. Nossa implementação atinge desempenho de última geração em configurações de nó único, mantendo excelente portabilidade em vários ambientes de rede.
Fragmentação e paralelismo
Para uma inferência eficiente, os pesos de um modelo devem ser mantidos na memória do dispositivo, deixando também espaço suficiente para ativações, caches KV e outros buffers necessários para a passagem direta (forward pass) pelo modelo. Os modelos mais capazes excedem a capacidade até das GPUs mais capazes, portanto, a inferência deve ser distribuída entre vários dispositivos, que podem armazenar coletivamente os pesos do modelo. Com base nos esquemas de fragmentação de pesos, diferentes esquemas de comunicação e computação devem ser usados para descarregar a computação e sincronizar os dispositivos.
O paralelismo de especialistas (Expert Parallelism - EP), ilustrado na primeira figura, paraleliza apenas a computação de especialistas. Diferentes especialistas são atribuídos a diferentes dispositivos, que contêm seus pesos. Após o roteamento, os tokens são enviados para o dispositivo correspondente, com os resultados sendo coletados e acumulados posteriormente. A complexidade do roteamento depende do grau de paralelismo nas outras partes do modelo: a replicação de outras camadas pode eliminar completamente a necessidade de roteamento, pois cada classificação pode selecionar os tokens de uma tabela de roteamento replicada localmente. No entanto, se apenas uma das classificações executar o roteamento, uma transmissão (broadcast) será necessária para despachar tokens, índices e pesos para seus respectivos especialistas. Finalmente, um all-gather ou uma transmissão all-to-all sincroniza os tokens de saída com qualquer classificação que continue a execução do modelo. Tal implementação é relativamente simples, pois o torch já expõe as primitivas necessárias, embora alguns benefícios possam ser obtidos fundindo a acumulação com a operação de coleta (gather) que reúne os tokens dos especialistas.
O paralelismo exclusivo para especialistas não escala de forma ideal, pois os nós em um cluster podem ficar ociosos enquanto o modelo está executando camadas não relacionadas a especialistas, como atenção, normalização (norm) e amostragem (sampling). No entanto, a computação dessas camadas, primariamente a atenção, também pode se beneficiar do paralelismo de tensores (Tensor Parallelism - TP). A maioria dos modelos depende de atenção multi-head, o que significa que as cabeças de atenção e suas projeções Q, K e V correspondentes também podem ser fragmentadas entre dispositivos, replicando ou coletando as fatias entre várias camadas. Se a atenção for distribuída por todos os dispositivos, um all-gather poderá sincronizar as ativações, permitindo que o roteamento seja replicado, exigindo primitivas de sincronização semelhantes ao caso de paralelismo de especialistas para uma implementação eficiente. No entanto, há limites para o paralelismo nesse nível, pois a redução do número de cabeças de atenção abaixo de um determinado limite produzirá retornos decrescentes.
Para utilizar melhor todos os dispositivos e suportar um grau muito alto de paralelismo de especialistas, de até 128 ou 256 GPUs, é necessário o paralelismo de dados (Data Parallelism - DP). Sob esse esquema, os dispositivos entre os quais um modelo é dividido são agrupados para lidar com solicitações simultaneamente, computando a atenção e mantendo caches KV fragmentados em seu grupo local. Várias instâncias desses grupos paralelos colaboram na avaliação de especialistas, cada uma hospedando um subconjunto diferente dos pesos dos especialistas. Com base no número de cabeças de atenção, um grupo normalmente pode abranger até o tamanho de um nó inteiro, já que a comunicação intra-nó é mais rápida. Por exemplo, na figura acima, uma classificação DP atende independentemente a duas solicitações, A e B, lidando com atenção, normalização e qualquer outra contabilidade para as solicitações. A outra classificação DP processa uma solicitação distinta C. No entanto, o primeiro nó hospeda metade dos especialistas, enquanto o outro nó hospeda a outra metade, portanto, após o roteamento, os tokens de A e B podem ser enviados para o segundo nó e vice-versa. Isso leva a um problema de comunicação esparsa: cada dispositivo pode enviar um número diferente de tokens para qualquer outro destino. As primitivas existentes do torch, principalmente o all_to_all, não são particularmente adequadas, pois podem exigir alguma forma de preenchimento (padding) ou sincronização de GPU para CPU e transmissão de metadados. Para implementar a comunicação de forma eficaz, são necessários kernels personalizados para processar as informações de roteamento e iniciar a comunicação a partir dos dispositivos sem a intervenção da CPU. Após o roteamento, um kernel de despacho deve enviar tokens para as classificações para as quais foram roteados, enquanto no lado da combinação as ativações pertencentes às solicitações no grupo DP atual devem ser coletadas. Além disso, o trabalho deve ser balanceado dentro de um grupo DP que pode ter vários dispositivos, a fim de minimizar a transmissão e replicar corretamente os tokens em todas as classificações para as camadas subsequentes.
NVSHMEM
O NVSHMEM é uma implementação do OpenSHMEM específica da NVIDIA, que fornece facilidades de comunicação portáteis entre dispositivos que abstraem a complexidade do hardware subjacente. A API pode expressar leituras e gravações de dispositivo para dispositivo, que são mapeadas para as primitivas de camadas de transporte individuais. O NVLink e o RDMA são suportados, concedendo um grau de portabilidade e permitindo que os kernels do NVSHMEM operem dentro de um nó ou em um cluster de vários nós. Em nossos kernels, usamos gravações de memória remota e operações de sinalização para transferir dados e sincronizar os dispositivos participantes.
As operações do NVSHMEM são construídas em torno do conceito de memória simétrica: elas operam em buffers que foram alocados em todos os dispositivos participantes da comunicação entre dispositivos. Um dispositivo local pode usar um endereço derivado em seu próprio buffer local junto com o índice da classificação de destino para especificar o destino de uma operação. A figura abaixo ilustra esse conceito: ambas as GPUs alocam buffers simétricos do mesmo tamanho, retendo ponteiros src para eles. A primeira classificação deseja enviar 3 inteiros para a segunda, colocando-os no início do buffer: nvshmem_int_put_nbi deriva o endereço inicial do buffer local, especificando o dispositivo de destino. A segunda classificação deriva um deslocamento (offset) de seu próprio buffer, enviando um elemento para o primeiro dispositivo, deslocando por um. Embora os endereços de destino devam ser sempre buffers simétricos alocados usando nvshmem_alloc, os buffers de origem podem ser regiões arbitrárias da memória do dispositivo, desde que sejam pré-registrados no NVSHMEM.
Embora o NVSHMEM forneça uma ampla gama de primitivas, nossos kernels dependem de apenas 3 funções, construindo toda a sincronização e delimitação (fencing) sobre elas.
nvshmemx_putmem_signal_nbi_warp: Transfere um bloco de dados de um dispositivo para outro, definindo também um sinalizador (flag) no dispositivo remoto. A operação define (NVSHMEM_SIGNAL_SET) ou incrementa (NVSHMEM_SIGNAL_ADD) um local de 64 bits. O sinalizador é atualizado após a transferência de todo o bloco de memória. Se o dispositivo remoto observar uma alteração no sinalizador, ele poderá acessar com segurança o buffer em sua própria memória. Esta função é útil para unir (coalescing) a transferência de dados e a sincronização.
O nvshmemx_signal_op opera em um único local de memória, tipicamente um sinalizador de 64 bits, definindo-o ou incrementando-o atomicamente. É útil para enviar metadados e sincronizar dispositivos.
O nvshmem_uint64_wait_until é usado na extremidade receptora de um sinal, para sondar (poll) um sinalizador até que o remoto o atualize.
Garantir qualquer forma de ordenação entre operações por meio de nvshmem_quiet ou nvshmem_fence é custoso, portanto, nossa implementação dos kernels evita o uso de quaisquer outras primitivas do NVSHMEM e minimiza quaisquer dependências além de pares individuais de envio e recebimento. Ao enviar dados, sempre usamos a versão não bloqueante (non-blocking) de funções, sem esperar que os dados sejam enviados para fora da classificação local. Outra sincronização implícita em todo o grupo de kernels garante que esses buffers não sejam sobrescritos destrutivamente enquanto as placas de rede (NICs) precisarem de acesso a eles.
O NVSHMEM usa GPUDirect RDMA para que a placa de rede (NIC) possa ler e gravar diretamente na memória da GPU para troca de dados sem envolver as CPUs. Além disso, nas placas de rede ConnectX, o NVSHMEM suporta comunicação iniciada por GPU (também conhecida como InfiniBand GPUDirect Async ou IBGDA), o que permite que a GPU envie operações de RDMA diretamente para a placa de rede e sonde a fila de conclusão da placa de rede diretamente. Em plataformas que não suportam comunicação iniciada por GPU, o NVSHMEM gera um tópico "proxy" na CPU host para iniciar a comunicação e sondar a conclusão em nome da GPU. O programa NVSHMEM é portátil, independentemente de a comunicação iniciada por GPU ser suportada ou não. No entanto, a comunicação iniciada por GPU reduz significativamente a latência porque ignora completamente o desvio para a CPU.
Kernels portáteis
Implementamos a comunicação MoE por meio de um par de kernels de despacho e combinação. Os kernels de despacho são responsáveis por ler tokens e informações de roteamento em cada classificação, despachando-os para os especialistas apropriados. Os kernels de combinação coletam as ativações produzidas pelos especialistas e as enviam de volta para suas classificações de origem, ao mesmo tempo em que calculam a média ponderada dos especialistas selecionados com base nos pesos calculados pelo roteador. Os kernels são divididos em um componente de envio e um de recebimento, para permitir que as transferências de dados sejam sobrepostas à computação. Os kernels de envio não são bloqueantes e não são síncronos: eles simplesmente despacham todas as gravações para os remotos. Por outro lado, os kernels de combinação apenas leem da memória, esperando até que todos os dados necessários tenham sido transferidos. Após despachar o trabalho para as placas de rede, enquanto os dados são transferidos assincronizadamente pela rede, as GPUs podem realizar outro trabalho útil localmente, como aplicar especialistas compartilhados ou computar a atenção.
Cada par de kernels possui seus próprios buffers de memória simétrica, com cada classificação alocando armazenamento privado para receber dados de todas as outras classificações. O número máximo de tokens que podem ser despachados de um grupo DP é fixo em todas as classificações, o que também define o limite superior que cada classificação pode receber para cada especialista local de cada classificação DP. Isso permite que as classificações remetentes derivem um endereço exclusivo no destino para gravar, sem exigir nenhuma sincronização entre elas. Após o recebimento dos dados, os kernels reorganizam os tokens para estruturá-los na memória no formato ideal exigido pelos kernels receptores. Embora os buffers tenham uma dimensão considerável, eles são reutilizados em todas as camadas sequenciais de um modelo.
A única forma de sincronização global, conforme ilustrado na figura acima, é implementada no kernel de recebimento de combinação (combine-receive). Uma vez que os dados são despachados do envio, uma classificação retorna e continua a execução quando recebe todos os tokens necessários das outras classificações e entra nos kernels de envio de combinação assim que eles são processados. A barreira no combine-receive garante que nenhuma classificação possa avançar e iniciar o despacho de envio enquanto qualquer outra classificação ainda estiver aguardando para receber dados, causando potencialmente uma sobreposição destrutiva. A sincronização é feita no kernel de combinação por simplicidade; como otimização, a mesma barreira poderia ser implementada entre os kernels de recebimento de despacho e de envio de combinação, reduzindo ainda mais a latência ao dar às placas de rede mais tempo para finalizar as transferências enquanto a GPU está executando outros kernels.
Ambos os kernels são divididos em todas as SMs disponíveis dos dispositivos: enquanto os kernels de envio de despacho e de recebimento de combinação devem ser paralelizados em uma contagem máxima de tokens por classificação (max_m), os kernels de recebimento de despacho e de envio de combinação devem lidar com essa quantidade de tokens de cada classificação e especialista local, para um máximo de max_m * (num_experts // EP) * (EP // TP).
Despacho
O kernel de despacho é responsável por despachar tokens e fatores de escala de bloco para os pares que hospedam os especialistas para os quais os tokens foram roteados. O lado do remetente baseia-se na especialização de warp para paralelizar duas tarefas: agregar informações de roteamento para determinar quantos tokens são enviados de cada classificação e empacotar os tokens em mensagens a serem despachadas para o remoto. O lado do receptor primeiro aguarda o recebimento de todas as contagens de tokens, depois lê e desempacota as cargas úteis (payloads) da memória compartilhada para os tensores que serão passados para os kernels Grouped GEMM a jusante. Ele também armazena informações em buffers compartilhados com os kernels de combinação, para indicar para onde cada token deve ser enviado de volta. Essas informações são necessárias, pois o kernel receptor reorganiza os tokens em buffers contíguos em uma ordem não determinística.
Na parte do remetente, um único warp de 32 tópicos em cada bloco é responsável por ler as informações de roteamento e contar o número de tokens que cada especialista de destino deve receber desta classificação, enviando a contagem mais um usando nvshmem_signal_op. A contagem é incrementada em um, pois a transição de zero para não zero na extremidade remota significa o recebimento das contagens de uma classificação de origem. Em paralelo, os warps restantes cooperam para copiar tokens na memória simétrica em todos os blocos em paralelo, empacotando ativações, fatores de escala e seu índice na classificação local em um bloco contíguo. O índice é necessário pelo remetente de combinação para determinar o endereço onde o token será gravado. Em seguida, após garantir que todos os dados tenham sido copiados por meio de uma barreira em todos os grupos de warp, os warps novamente operam de forma independente, cada um enviando o mesmo buffer para um especialista diferente em paralelo. Os tokens são enviados usando nvshmemx_putmem_signal_nbi_warp, que também aumenta atomicamente a contagem de tokens enviados da classificação local no dispositivo remoto. Dentro de um grupo DP, como cada classificação possui uma réplica do token a ser enviado, o despacho é balanceado uniformemente, com cada dispositivo enviando um subconjunto dos tokens.
Na extremidade de recebimento, todos os kernels primeiro se sincronizam com as classificações remetentes, aguardando o envio das contagens totais de tokens. Posteriormente, todos aguardam que as contagens de tokens enviados incrementadas atomicamente se estabilizem nas contagens totais, indicando que todas as cargas úteis das classificações de origem também foram enviadas, graças à semântica da chamada putmem. Os kernels fazem a sondagem das contagens usando nvshmem_uint64_wait_until, paralelizando a operação em todos os blocos e tópicos. Posteriormente, uma barreira entre blocos garante que nenhum bloco leia os buffers, a menos que todos os dados tenham sido recebidos corretamente. Distribuídos entre os blocos e sincronizados por meio de um contador incrementado atomicamente, os tokens são copiados da memória simétrica para buffers contíguos regulares que se tornam as entradas para os kernels a jusante que implementam os especialistas. A classificação de origem, o índice do especialista e o índice do token são armazenados separadamente, identificando exatamente o local onde o kernel de combinação deve enviar as ativações. Mesmo que os tokens de um grupo DP sejam enviados de dispositivos diferentes, eles são agrupados para serem passados para o especialista correspondente.
Combinação
Os kernels de combinação são divididos novamente em metades de envio e recebimento: os remetentes cópiam as ativações de 16 bits não quantizadas para os dispositivos remotos, com os kernels receptores aguardando o envio dos dados e calculando a média ponderada de todas as contribuições dos especialistas localmente. Além disso, eles também agem como uma barreira para sincronizar a sequência de despacho e combinação: cada classificação define um sinalizador em cada par na entrada para os kernels de envio, e os kernels receptores não têm permissão para retornar a menos que observem o sinalizador sendo definido. A latência de sincronização é mínima, pois se sobrepõe à comunicação e à computação reais.
No lado do remetente, os kernels percorrem a lista de tokens atribuídos a todos os especialistas locais em paralelo, gravando-os em um buffer no dispositivo de destino. O dispositivo de destino, o índice do especialista e o índice do token são lidos dos buffers por token preenchidos pelos kernels de dispersão (scatter) após o recebimento dos tokens. Cada remetente possui sua própria região de memória privada por especialista para gravar, conforme indicado na figura acima, evitando a necessidade de sincronização. Semelhante ao despacho, a combinação incrementa atomicamente os contadores por token no dispositivo de destino para indicar o recebimento dos dados: quando o contador corresponde ao número de especialistas para os quais um token foi despachado, o conteúdo do token pode ser acessado.
No kernel receptor, a lista de tokens é percorrida em paralelo em vários blocos, aguardando a chegada de seus conteúdos ao consultar o sinalizador definido pela operação de sinalização. Após a chegada, as cargas úteis são lidas dos buffers privados, com a tabela de roteamento indicando qual buffer ler e qual peso atribuir a cada especialista. Os resultados são então gravados em tensores alocados externamente, com o kernel terminando a execução assim que todos os dispositivos passam pela barreira. Em um grupo DP, todas as classificações recebem uma cópia de cada ativação de especialista para calcular suas próprias réplicas.
Benchmarks
Avaliamos nossos kernels em um cluster de 128 GPUs distribuídas em 16 nós conectados via InfiniBand e placas de rede CX-7. Testamos tanto o GPUDirect Async (IBGDA) quanto a Conexão Confiável (RC) com um proxy de CPU. Nós os comparamos com a implementação altamente otimizada do DeepSeek, bem como com as primitivas densas fornecidas pelo PyTorch (por meio do NCCL) ou do NVSHMEM.
Embora na operação densa all-to-all do NVSHMEM o desempenho do IBRC e do IBGDA seja semelhante (6378 µs vs 6180 µs), o IBGDA é significativamente mais rápido com os kernels esparsos. Somando o despacho e a combinação (Dispatch e Combine), o IBGDA usa 902 µs, enquanto o IBRC leva 3223 µs - uma melhoria de 3,6 vezes na latência. Embora o all-to-all seja limitado pela largura de banda, os kernels esparsos transmitem ordens de grandeza a menos de dados, sendo limitados pela latência. Ao acionar transferências de rede diretamente de uma GPU, sem exigir um proxy de CPU para coordenar a GPU e a placa de rede, a latência de ponta a ponta é significativamente reduzida.
Embora nossos kernels portáteis sejam cerca de 2 vezes mais lentos do que os kernels altamente otimizados do DeepSeek, eles melhoram a latência em 10 vezes em comparação com os kernels densos (902 µs vs 9944 µs).
Além disso, a divisão em componentes de remetente e receptor também permite que parte da latência seja ocultada, ao contrário das primitivas da biblioteca.
Em nó único (EP8), o NVSHMEM utiliza o NVLINK para transporte, oferecendo menor latência e maior rendimento (throughput) do que a rede entre nós. Nossos kernels portáteis são cerca de 2,5 vezes mais rápidos que o DeepEP em nó único (186 µs vs 481 µs).
Melhorias futuras
Os kernels descritos aqui superam as primitivas integradas de estruturas de ML e oferecem desempenho decente sem superespecialização para transportes específicos entre dispositivos, como NVLink ou InfiniBand. Além das oportunidades já mencionadas, ganhos adicionais de desempenho podem ser obtidos substituindo as primitivas de comunicação por versões mais especializadas. Por exemplo, no NVLink, o uso de memória simétrica pode ser substituído por buffers compartilhados entre os dispositivos, eliminando alguma cópia e permitindo esquemas de sincronização mais refinados, em tokens individuais em vez de lotes de tokens. No InfiniBand, uma implementação pode acessar os pares de filas subjacentes diretamente, eliminando a necessidade de transferir as contagens de tokens esperados e enviados e descarregando tokens das filas para os buffers de saída à medida que chegam. No entanto, tais implementações têm o custo da portabilidade, enquanto nossa implementação permite que clusters com configurações específicas sejam avaliados antes de comprometer o esforço de desenvolvimento para otimizar para um hardware específico.
Conclusão
Apresentamos uma biblioteca portátil e de alto desempenho para comunicação MoE que atinge um desempenho 10 vezes mais rápido em comparação com a comunicação padrão all-to-all, mantendo a compatibilidade entre diversas configurações de hardware. Em implantações de nó único com NVLink, nossa solução demonstra uma latência 2,5 vezes menor do que as implementações anteriores.
Nossa abordagem equilibra desempenho com portabilidade por meio de inovações importantes, incluindo suporte a comunicação iniciada por GPU, uma arquitetura de kernel dividida que permite a sobreposição de computação e comunicação, e despacho eficiente de tokens usando primitivas mínimas do NVSHMEM. Embora seja aproximadamente 2 vezes mais lenta do que implementações altamente especializadas em configurações multi-nó, nossa biblioteca oferece flexibilidade superior em vários ambientes de rede (NVLink, CX-7 e EFA).
À medida que os modelos MoE continuam a escalar, estratégias de comunicação eficientes como a nossa se tornarão cada vez mais importantes para a implantação prática. Nossa implementação totalmente de código aberto está disponível em https://github.com/ppl-ai/pplx-kernels.
Referências
Relatório Técnico do DeepSeek-V3
Citação
@online{perplexity2025EfficientAndPortableMixtureOfExpertsCommunication,
author = {{Perplexity} and Nandor Licker and Lequn Chen and Phi Hoang},
title = {{Efficient and portable mixture-of-experts communication}},
date = {2025-04-02},
url = {https://www.perplexity.ai/hub/blog/efficient-and-portable-mixture-of-experts-communication}
}