E aí, dev! Vamos falar de servir MoE em escala
Se você já tentou rodar um modelo Mixture-of-Experts (MoE) de ponta em aceleradores especializados, sabe a dor: não dá pra resolver na base do chute. O Qwen 3.5-397B-A17B é o exemplo perfeito. Ele tem 397B parâmetros totais (uns 400 GB de peso), mas ativa só 17B por token — uma taxa de ativação de 4.3%. Essa esparsidade é o pulo do gato: você tem a inteligência de um modelo de 400B pelo custo de servir um de ~20B.
Mas essa promessa só se paga se a engenharia de sistemas estiver afiada. O sharding tensor-parallel ingênuo quebra na hora quando o modelo tem exatamente 2 KV heads nas camadas GQA e 512 experts no stack MoE. Não dá pra fatiar 2 heads em 8 devices. Replicar desperdiça HBM. E num chip com 192 GB de HBM (contra 288 GB no Blackwell GB300 — uns 50% a menos), desperdiçar HBM é morte.
A solução não é um kernel mágico. É uma metodologia modular e agnóstica a modelo — um playbook de blocos reutilizáveis (Batched RPA, Grouped GEMMs, unpermutation no SparseCore) que você porta pra novas arquiteturas com quase zero atrito. Bora ver como isso foi aplicado no Qwen 3.5 rodando em Ironwood (TPU v7x), entregando ~3.1x no decode e ~4.7x no prefill na faixa de 512 de concorrência.
O relatório técnico completo tá aqui.
![]()
As restrições arquiteturais que quebram o sharding ingênuo
O layout híbrido do Qwen 3.5 não é um stack Transformer uniforme. São 60 camadas organizadas em 15 blocos repetidos, cada um numa proporção 3:1 de atenção linear Gated DeltaNet (GDN) para atenção GQA padrão:
- GDN linear attention (75% das camadas): 64 V-heads, 16 QK-heads, head dim 128. Mantém uma matriz de estado recorrente de tamanho constante por head, atualizada via regra delta. Escala O(S) em vez de O(S²).
- GQA (25% das camadas): 32 query heads, exatamente 2 KV heads, head dim 256, RoPE dim 64. Comprime o KV cache, mas impõe restrições brutais de sharding.
- MoE FFN: 512 experts pequenos, dim intermediária 1024, roteamento
top_k=10mais 1 shared expert sempre ativo.
Por que TP=8 falha
Com só 2 KV heads, um tensor-parallel de tamanho 8 força sharding fracionário (2/8 = 0.25 heads por device) — fisicamente impossível. Replicar as heads em 8 cores duplica o KV cache em cada device, limitando a concorrência real a ~200 em vez dos 512 planejados.
A solução: DP de atenção + EP de experts
O time co-projetou um esquema de 8-way Attention Data Parallelism (DP=8) + 8-way Expert Parallelism (EP=8):
# Topologia conceitual de sharding para Qwen 3.5 em mesh TPU de 8 devices
# Comentário: atenção em DP, MoE em EP no mesh de 8 chips
sharding = {
"gdn_layers": "replicated", # Todas as 2 KV heads por device
"gqa_layers": "replicated", # Consistência local do KV cache
"moe_experts": "expert_parallel", # 512 experts / 8 devices = 64 por chip
}
# Roteamento cross-device: All-Gather dos metadados, Reduce-Scatter das saídas
# Comentário: metadados de roteamento via All-Gather, saída dos experts via Reduce-Scatter
Os pesos de atenção são replicados nos 8 devices (cada core vê as 2 KV heads completas), eliminando comunicação intra-atenção. Os 512 experts roteados são distribuídos igualmente (64 por device), evitando a duplicação dos 400 GB de pesos.
Três coletivas viram duas
No EP ingênuo, preparar o MoE local exigia três All-Gathers: índices de expert, pesos topk e hidden states. Como índices (int) e pesos (float) têm shape idêntico [1024, 10], foram empilhados, bitcast e empacotados num blob de 32-bit — um All-Gather em vez de dois. Latência de metadados de roteamento cortada pela metade.

Kernels Pallas, co-design com SparseCore e o roofline
Com a topologia certa, os ganhos restantes vieram de kernels hand-scheduled que furam o caminho padrão do XLA.
Três otimizações de alto impacto
| Otimização | Técnica | Impacto medido |
|---|---|---|
| RPA com indexação grossa | KV page size 16 → 256 (--block-size=256) | Latência de decode em C=512: 428µs → 283µs (33.8% mais rápido) |
| Unpermutation no SparseCore | Offload de unpermutation + redução local pro SparseCore | Leituras HBM 20→10, escritas 15→5 |
| Fusão GDN + conv causal 1D | Sliding window em registradores VPU | Eliminou 6 round-trips redundantes na HBM |
Fusão em nível de registrador no caminho GDN
A atualização recorrente do GDN era compilada como op independente, forçando as saídas da convolução a ir e voltar da HBM. O time fundiu a conv causal 1D (K=4) e a atualização de estado GDN num único bloco, cacheando estados históricos direto nos registradores da VPU. Também migraram as variáveis de estado do SSM de Float32 para BFloat16, dobrando o throughput vetorial da VPU sem comprometer a convergência numérica.
Validação por roofline
Em concorrência 64 com layout 8K/1K, o throughput empírico ficou muito próximo dos limites teóricos do roofline — ou seja, os kernels estão empurrando o hardware perto dos limites físicos. Sob alta concorrência, matrizes de gating e roteamento são sensíveis a erros de acumulação em baixa precisão, então uma Camada de Verificação Numérica audita continuamente os blocos de escala FP8, confirmando zero desvio do caminho de referência em Float32.

Limitações, avisos e próximos passos
O que esse playbook não resolve
- HBM é o teto rígido. Os 192 GB por chip do TPU v7 são ~50% menores que os 288 GB do Blackwell GB300. Nenhuma fusão de kernel recupera essa diferença.
- Novidades específicas de modelo ainda custam tempo. O playbook reduz atrito, mas as camadas GDN e o
top_k=10do Qwen 3.5 exigiram kernels Pallas sob medida. - Correção numérica precisa ser re-verificada por modelo. Acumulação FP8 é sensível ao modelo. O que funciona aqui pode não transferir limpo.
Roadmap restante
Duas trilhas abertas: (1) fundir o kernel de seleção top_k direto na VPU, eliminando o gargalo de serialização TensorCore→VPU; e (2) reduzir mais o overhead de coletivas cross-device com pipelining em nível de chunk.
Se você vai construir em cima disso
Comece pela topologia de sharding antes de mexer em kernel. Acertar DP+EP vale mais que qualquer micro-otimização. Depois faça profiling agressivo — gargalos se escondem em coletivas, não só em matmuls.