Verificando Kernels NKI
do AWS Neuron com ESBMC
Uma prova de conceito reproduzível pela Cyber-Reasoning Consultancy (CRC) mostrando que kernels do Neuron Kernel Interface (NKI), a API de kernel em nível de Python para os NeuronCores AWS Trainium e Inferentia, podem ser verificados estaticamente pelo frontend Python do ESBMC, sem nunca tocar em hardware Neuron. Fontes, harness e instruções de execução estão publicados em lucasccordeiro/AWS-Neuron. Ao longo do caminho, a PoC reportou dois novos bugs de divisão por zero em kernels NKI upstream que a equipe AWS Neuron confirmou e corrigiu.
19
Kernels NKI portados e verificados pelo ESBMC ao longo da PoC AWS-Neuron
~26 min
Tempo de relógio de ponta a ponta da varredura de verificação em duas fases (96 execuções)
11 / 13
Alvos de forma simbólica que carregam certificados de completude por k-induction
2
Novos bugs de divisão por zero no nki-samples reportados pela PoC e corrigidos upstream pela AWS
Contexto
O NKI é a API de kernel em nível de Python que a AWS expõe para escrever kernels de
tensor de alto desempenho nos NeuronCores Trainium e Inferentia. Kernels NKI parecem
Python comum, mas estão sujeitos a restrições de forma, dtype e partição específicas do
hardware, por exemplo, a dimensão de partição PMAX é fixada em 128, e a unidade de
matmul tem limites de free-dimension stationary/moving separados
(GEMM_STATIONARY_FMAX = 128,
GEMM_MOVING_FMAX = 512).
Violar qualquer uma dessas restrições produz um erro em nível de hardware doloroso de
diagnosticar em tempo de execução.
A pergunta que quisemos responder é simples: essas restrições podem ser verificadas formal e exaustivamente, antes da implantação, em um laptop de desenvolvedor e sem um NeuronCore? Se sim, autores de NKI ganham uma rede de segurança rápida e determinística que complementa os testes em dispositivo em vez de competir com eles.
Abordagem
Escrevemos uma única biblioteca
stubs.py
de ~865 linhas modelando formas de tiles, dtypes e restrições de hardware do NKI, de
modo que kernels NKI upstream pudessem rodar sem alterações sobre os stubs. Os kernels
portados são fiéis byte a byte às fontes upstream quanto à indexação; nenhuma
reescrita de código-fonte é necessária. O harness está fixado ao
aws-neuron/nki-samples
no snapshot do commit a87aaa44,
cobrindo 11 arquivos-fonte (6 tutoriais e 5 kernels da comunidade) e 19 funções de
kernel.
A verificação se divide em duas fases. A Fase 1 verifica formas e
limites por meio das asserções de contrato em stubs.py:
limites de dimensão de partição, fatiamento dentro dos limites, igualdade de forma de
DMA / elementwise / matmul e limites de hardware da unidade de matmul. A
Fase 2 ativa o
--overflow-check
do ESBMC (com detecção padrão de divisão por zero) para capturar CWE-190 (overflow de
inteiro com sinal) e CWE-369 (divisão por zero) na aritmética de índices do lado do host
que envolve os kernels. Ambas as fases usam o ESBMC 8.3.0 ou posterior com o solver SMT
Bitwuzla padrão.
Para alvos de forma simbólica, onde as dimensões de entrada são não-determinísticas,
usamos k-induction para obter certificados de completude: 11 de 13 alvos simbólicos
estabelecem que o limite de --unwind
escolhido é suficiente para cobrir todo estado alcançável, de modo que o veredito é
exaustivo, não meramente limitado. As duas exceções (os alvos simbólicos Mamba-v3 e
attention-forward-v3) estouraram o tempo limite sob k-induction e permanecem
heurísticas; reportamos isso abertamente no repositório.
Resultados
A varredura em duas fases completa em ~26 minutos de ponta a ponta em um laptop comum (Fase 1: 58 execuções em ~14 min; Fase 2: 38 execuções em ~11 min), com uma taxa de aprovação de 100% frente aos vereditos esperados. Alvos de forma concreta terminam em 1–3 segundos cada; alvos simbólicos em ~5–90 segundos.
Bug real upstream redescoberto em ~2 segundos. O kernel
matmul_hoist_load
que a
PR #74
do aws-neuron/nki-samples corrigiu, antes da correção,
lhsT_tiles
era alocado com free-dim TILE_N (=512)
onde deveria ser TILE_M (=128),
está fixado em nosso harness como alvo de regressão. O ESBMC reporta a divergência de
forma em ~2 s em um laptop, sem um dispositivo Neuron, demonstrando que a técnica
captura bugs da classe que já chegou a código NKI real.
(Esta é uma reprodução retroativa de uma issue upstream já corrigida, não uma
descoberta nova.)
Novo bug de divisão por zero reportado e corrigido upstream. A
verificação CWE-369 da Fase 2 dispara um ZeroDivisionError
em tempo de JIT-trace em
interpolate_bilinear_2x_fwd
e interpolate_trilinear_2x_fwd
quando chunk_size == 1,
encontrado sem depender de nenhuma pré-condição de tempo de port. Reportamos como
nki-samples issue #125;
a AWS adotou as pré-condições propostas
(chunk_size >= 2,
dim >= chunk_size em chunks)
e integrou a correção na
PR #126.
Segundo bug de divisão por zero reportado e corrigido upstream. A
varredura multi-propriedade da Fase 2 também revelou um
ZeroDivisionError
em tensor_avgpool_kernel
quando pool_size == 0.
Reportamos como
nki-samples issue #127;
a AWS adicionou a guarda proposta
assert pool_size >= 1
upstream no commit
bb513ac.
~20 issues do frontend Python do ESBMC reportadas e resolvidas upstream
ao longo da PoC, cada issue emparelhada com sua PR de merge no
RETROSPECTIVE.md do repositório.
Efeito líquido: os kernels portados agora são fiéis byte a byte à fonte NKI upstream
quanto à indexação, e uma classe de lacunas do frontend (contornos de
named-local-binding, shims de source-rewrite) foi aposentada no próprio ESBMC.
O que isso significa
A verificação de formas e limites do NKI é tratável por verificação limitada de modelos com completude por k-induction, em velocidades de laptop de desenvolvedor, sem hardware no loop. A mesma técnica se estende a defeitos de overflow de inteiro e divisão por zero no glue do lado do host em torno dos kernels. Para equipes que escrevem ou revisam código NKI, isso transforma uma classe de falhas em nível de hardware em gates de CI em tempo de compilação, e o custo de adoção é uma biblioteca de stubs mais alguns minutos por kernel.
Referências
- lucasccordeiro/AWS-Neuron, repositório público da PoC (harness, stubs, kernels portados, varredura de verificação em duas fases, retrospectiva). github.com/lucasccordeiro/AWS-Neuron
-
aws-neuron/nki-samples, kernels de exemplo NKI upstream (fixados no commit
a87aaa44na PoC). github.com/aws-neuron/nki-samples - aws-neuron/nki-samples PR #74, correção da dimensão de alocação SBUF de matmul (redescoberta retroativamente pela PoC). github.com/aws-neuron/nki-samples/pull/74
-
aws-neuron/nki-samples issue #125 → PR #126, divisão por zero em
interpolate_{bi,tri}linear_2x_fwdemchunk_size == 1, reportada pela PoC e corrigida upstream. github.com/aws-neuron/nki-samples/pull/126 -
aws-neuron/nki-samples issue #127 → commit
bb513ac, divisão por zero emtensor_avgpool_kernelempool_size == 0, reportada pela PoC e corrigida upstream. github.com/aws-neuron/nki-samples/commit/bb513ac - ESBMC, verificador limitado de modelos open-source, com o frontend Python usado nesta PoC. github.com/esbmc/esbmc
Nota. Esta página descreve uma prova de conceito independente e
reproduzível publicada pelo fundador da CRC e criador e desenvolvedor líder do ESBMC,
Prof. Lucas Cordeiro (University of Manchester). A CRC Ltd não mantém parceria comercial
com a AWS ou a equipe AWS Neuron, e a PoC não foi encomendada pela AWS. As duas novas
correções de divisão por zero (nki-samples PR #126 e commit
bb513ac) passaram pelo rastreador de issues público
do projeto. O harness é open source; todos os resultados, incluindo a redescoberta
retroativa da nki-samples PR #74 e os limites da cobertura de forma simbólica, são
reproduzíveis a partir do repositório público.