Documentação

Viabilidade do ANE: transformações equivalentes e um objetivo de 10× mensurável

Data de investigação: 2026-09-20. Hardware: M3 Max, GPU de 40 núcleos, 128 GiB. Este documento descreve hipóteses e limites matemáticos, não uma afirmação de uma nova aceleração medida. O ponto de partida são os pesos originais do Laya e o runtime MLX FP16 mais rápido. As experiências de engenharia e as medições podem substituir as observações iniciais abaixo.

A melhor primeira experiência é uma reescrita de forma fixa, com o canal primeiro, de todo o transformer, seguida de uma inspeção do plano de execução. O alvo de ordem de grandeza mais plausível é a energia por decisão concluída, desde que o modelo mantenha uma latência e uma exatidão úteis. Alterar apenas uma definição de unidade de cálculo do Core ML não é evidência suficiente de que o Neural Engine executou o modelo.

As experiências de engenharia subsequentes implementaram essa reescrita, e o relatório medido de velocidade/energia regista agora os resultados. O candidato sem compressão melhora a eficiência mas não atingiu o objetivo de 10×. As hipóteses e o denominador original abaixo são mantidos como registo de investigação; usa a comparação posterior com o MLX compilado para afirmações de desempenho medidas.

Define o alvo antes de otimizar

Para as mesmas entradas, checkpoint, política de precisão e número de decisões concluídas, define:

t = elapsed time / completed decisions
P = average measured power over that same interval
E = integrated energy / completed decisions = P × t

S = t_MLX / t_candidate                    speed gain
R = P_MLX / P_candidate                    power reduction factor
S × R = E_MLX / E_candidate                 energy efficiency gain

Usa a latência média por bloco, não um percentil de latência, nesta identidade. Reporta P50 e P95 em separado. Um resultado 2× mais rápido com um quinto da potência é uma melhoria de energia de 10×. Um resultado duas vezes mais lento precisa de uma redução de potência de 20× para produzir a mesma melhoria de energia de 10×. Multiplicar a velocidade por uma melhoria de energia já calculada conta o tempo decorrido duas vezes.

Há dois testes de potência distintos:

  1. Inferência sequencial saturada: mede o débito real, a latência e os joules por decisão. Um candidato com menor potência mas mais lento não é automaticamente mais eficiente.
  2. Carga oferecida igual, como a mesma taxa de tick do Snake: ambos os candidatos têm de terminar o mesmo trabalho dentro do prazo. Reporta a potência média, a energia total do intervalo, os incumprimentos de prazo e as decisões concluídas. Dormir mais tempo ou descartar trabalho não é uma otimização.

Regista o domínio de potência medido. A telemetria de CPU + GPU + ANE não é necessariamente a potência da máquina inteira nem da bateria, e não deve ser rotulada como tal. Reporta a energia em bruto e, se for utilizável, a energia pareada subtraindo o inativo. Quando carga-menos-inativo é semelhante ao ruído, preserva a incerteza em vez de a limitar silenciosamente e reportar um rácio enorme. Mantém a tokenização, as cópias de entrada, o fallback para CPU e o pós-processamento dentro da fronteira de contabilização do endpoint.

Evidência inicial e o denominador

O atual benchmark MLX multilingue mede uma única pergunta de 91 tokens a 7.870 ms P50 / 9.870 ms P95. O benchmark MLX inglês mede uma pergunta de 93 tokens a 13.334 / 13.734 ms. Estas são medições predict ponta a ponta, excluindo o carregamento do modelo e o aquecimento. Uma nova comparação tem de voltar a executar o caminho MLX aplicável mais forte, incluindo as suas definições de compilação opt-in e de cache de prompt quando a carga de trabalho o permitir; um resultado histórico em modo eager não é um denominador permanente.

A exportação Core ML multilingue existente mede 11.277 ms P50 com CPU + GPU, 78.037 ms com ALL e 81.336 ms com CPU + NE. O plano desta última regista 1,318 operações preferidas pela CPU e nenhuma operação preferida pelo NE; 24 operações SDPA têm metadados de dispositivo desconhecidos. Isto não estabelece qualquer afirmação de execução no NE. O plano lista muitas operações como NE-suportadas, o que é diferente de NE-preferidas. A Apple descreve a utilização de dispositivos do plano de cálculo como utilização prevista do dispositivo, por isso mesmo um plano favorável deve ser corroborado por perfilagem em runtime ou por atividade observável do NE.

O gate de regressão FP16 existente é 100% de concordância de argmax no fixture, saídas deterministas finitas e no máximo 0.02 de desvio absoluto nas probabilidades calibradas e de ação. Isso é uma verificação de fidelidade de conversão num corpus pequeno. Não estabelece exatidão geral na tarefa, competência no Snake nem a qualidade de um modelo comprimido.

Transformações equivalentes do grafo

O estudo de implementação de Transformers da Apple motiva ativações BC1L quadridimensionais, convoluções 1×1, a divisão da atenção em cabeças e a redução de cópias de layout. O seu exemplo publicado de 10× é um modelo, dispositivo e linha de base diferentes; não pode ser transferido para a comparação com o MLX aqui. Trata essas recomendações de layout como candidatas a testar neste SO e chip, não como um contrato completo de suporte de hardware atual.

Projeções lineares e a MLP com gating

Seja X[b,l,i] a ativação existente e define U[b,i,0,l] = X[b,l,i]. Para uma camada linear,

Y[b,l,o] = sum_i W[o,i] X[b,l,i] + bias[o]
K[o,i,0,0] = W[o,i]
Conv2D(U,K)[b,o,0,l] = Y[b,l,o]

Isto altera o layout e a representação do operador sem alterar a função a valores reais. Mantém esse layout ao longo de todo o codificador e das duas camadas transformer da cabeça de decisão. Converter para esse layout e de volta em torno de cada camada linear pode eliminar o benefício. O QKV pode continuar a ser uma única convolução D → 3D; divide a sua saída de canais em Q, K e V. Do mesmo modo, preserva a projeção fundida D → 2I do codificador existente, divide os canais em valor e gate, aplica o GELU exato original ao valor, multiplica pelo gate e projeta I → D.

Para FP16, uma largura de sequência divisível por 32 também se alinha ao alinhamento de 64 bytes do último eixo descrito no estudo da Apple. As formas iniciais são B=1,L=96 para o fixture curto da API e B=3,L=64 para o Snake compacto. Uma recomendação de múltiplo de 32 aqui segue esse modelo de buffer; não é permissão para preencher todas as cargas de trabalho até um comprimento arbitrário grande. O Snake não precisa de 96 tokens.

Atenção e RoPE

Para cada cabeça, mantém Q e V como (B,d,1,L) e transpõe K para (B,L,1,d). Calcula:

score[b,k,0,q] = sum_c Q[b,c,0,q] K[b,k,0,c] / sqrt(d)
weight = softmax(score + additive_mask, axis=key)
out[b,c,0,q] = sum_k weight[b,k,0,q] V[b,c,0,k]

O eixo chave é o eixo 1 nesta representação. Concatena as saídas das cabeças no eixo dos canais. Esta é a mesma função de atenção; um eixo de softmax errado altera-a silenciosamente. A implementação de atenção de referência da Apple demonstra as duas contrações quadridimensionais correspondentes. Inspeciona os operadores MIL convertidos: escrever um einsum não garante o dispositivo nem o lowering pretendidos.

Aplica o RoPE aos pares de canais de cada cabeça antes do QK. Preserva a convenção de metades divididas do checkpoint, as posições originais e o theta por camada. Neste checkpoint multilingue, tanto o RoPE completo como o local usam theta 160000. Dividir a primeira e a segunda metades de todas as cabeças concatenadas em conjunto está incorreto; divide dentro de cada cabeça de 64 canais. Uma rotação dependente da posição não pode, em geral, ser dobrada numa única matriz de pesos independente da posição.

A regra local é bidirecional abs(q-k) <= 64, inclusivamente. Preserva o preenchimento de chaves e a regra de consulta preenchida existente. As partes constantes dependentes da posição podem ser calculadas antes do traçado para formas fixas; alterar o preenchimento da amostra tem de continuar a afetar a máscara de chaves. Substituir a exclusão matemática por uma máscara negativa grande e finita é uma aproximação numérica, a menos que corresponda ao comportamento de precisão finita da implementação original; verifica entradas adversariais e preenchidas.

A LayerNorm não é intercambiável com outras normalizações

Para cada (b,l), reduz apenas ao longo dos canais:

mu = mean_c U
v = mean_c (U-mu)^2
normalized = (U-mu) / sqrt(v + epsilon)
output = normalized * gamma + beta

Mantém o epsilon original, a ordem afim, a variância populacional, a normalização de identidade da primeira camada, o GELU exato e a ordem residual. A LayerNorm de referência da Apple usa uma ordem afim diferente; o seu adaptador DistilBERT compensa transformando o viés. Copiar diretamente essa classe e carregar o state dict do Laya estaria incorreto para vieses não nulos. Uma expressão afim explícita com a ordem original também evita dividir por um gamma possivelmente zero.

Limitar ativações, mudar o GELU para tanh ou substituir a LayerNorm por RMSNorm altera a função. Se os valores ao quadrado transbordarem, uma reescalonagem positiva é uma opção matematicamente equivalente:

normalize(x/a, epsilon/a^2) = normalize(x, epsilon), for a > 0

A acumulação em precisão finita continua a precisar de testes de paridade. As reduções FP32 podem custar cópias ou fallback para CPU, por isso inspeciona o plano em vez de relaxar silenciosamente o comportamento numérico.

Mover o trabalho não suportado para as fronteiras do modelo

Se a consulta de embedding, o gather dinâmico de marcadores ou a cauda de ação impedirem uma região NE contígua, cria um candidato separado com esta partição:

CPU: tokenizer → selected embedding rows → embedding LayerNorm
NE candidate: all encoder layers → type embedding addition → both heavy head layers
CPU: marker/CLS selection → small scorer → raw-probability features → action head

Só os endpoints atravessam motores. Não descarregues a atenção nem a LayerNorm de cada camada para a CPU. No B=1,L=96 multilingue, um tensor de embedding FP16 é 147,456 bytes; no B=3,L=64 é 294,912 bytes. Inclui estas cópias e qualquer cópia de saída do estado oculto completo na medição ponta a ponta.

A tabela de tokens multilingue tem 196,608,000 parâmetros, mas cada pedido recolhe apenas as suas linhas de tokens. Não precisa de ser enviada para um subgrafo transformer do ANE, e não deve ser contada como uma leitura completa da tabela em cada predição. A sua LayerNorm não tem dependência de posição, por isso a pré-normalização offline das linhas da tabela é equivalente em aritmética real. Pode alterar o arredondamento e a precisão de armazenamento, exigindo o seu próprio teste de paridade. A cabeça de ação consome probabilidades dos logits de marcador em bruto, antes da calibração de temperatura; reconstruir as suas características a partir das probabilidades calibradas públicas altera o comportamento do checkpoint.

Limites aritméticos numa afirmação de latência de 10×

Seja D a largura oculta, I a largura intermédia do codificador com gating, N as camadas do codificador e H=2 as camadas da cabeça de decisão. A contagem principal de parâmetros matriciais por token e a aritmética densa são:

A = N(4D^2 + 3DI) + 12HD^2
F_dense(B,L) = 2BLA + 4B(N+H)L^2D

Multiplicações e adições contam-se em separado. Estas equações excluem normas, ativações, embeddings, pontuação, máscaras, cópias e custos do runtime. Não são um profiler. Modelam o cálculo de atenção densa atual mesmo para camadas locais mascaradas.

Checkpoint D / I / N A Bytes da matriz principal FP16 Trabalho denso em B=1,L=96 Cálculo efetivo necessário para 10× abaixo do P50 MLX atual
Multilingue 768 / 1152 / 22 124,452,864 248.91 MB 24.574 GFLOP 31.23 TFLOP/s dentro de 0.787 ms
Inglês / arquitetura typed 1024 / 2624 / 28 368,312,320 736.62 MB 71.848 GFLOP 53.89 TFLOP/s dentro de 1.333 ms, usando a linha de base inglesa

Estas são taxas alcançadas necessárias, não especificações de pico do ANE afirmadas. Uma reescrita de layout remove custos mas não remove essas projeções densas. O hardware tem também de executar uma cadeia sequencial de 24 ou 30 blocos de atenção/MLP.

Um modelo de streaming otimista dá outro piso condicional:

t >= max(F / effective_compute, bytes_from_DRAM / effective_bandwidth)

O M3 Max de 40 núcleos de GPU é especificado com 400 GB/s de largura de banda de memória unificada. Se cada matriz principal FP16 for obtida da DRAM uma vez por pedido, mesmo o acesso total a essa largura de banda custa pelo menos 0.622 ms para o multilingue e 1.842 ms para o inglês. O acesso real à largura de banda do ANE pode ser menor, e pesos em cache ou comprimidos alteram o pressuposto. Isto não é um limite físico incondicional. Mostra porque a latência inglesa de 10× é particularmente exigente sob streaming sem compressão, e porque medir a energia é útil mesmo quando a latência melhora modestamente.

Para uma fração medida f do tempo ponta a ponta melhorada por um fator s, a lei de Amdahl dá S = 1 / (1-f+f/s). Mesmo uma aceleração infinita de uma região não consegue atingir 10× a menos que ocupe pelo menos 90% da latência original. O limite análogo usa a fração da energia medida, não os FLOPs, quando o alvo são joules por decisão. A otimização de consulta selecionada na cabeça final remove apenas alguns por cento da aritmética do modelo; a esparsidade da atenção local também é negligenciável em L<=64, onde a janela local cobre todas as posições. Nenhuma fornece uma via credível de 10× isolada.

A compressão e as alterações arquiteturais têm contratos diferentes

Candidato Mesma função de checkpoint a valores reais? O que pode realisticamente alterar
Layout BC1L, projeções 1×1, posições/máscaras estáticas, divisão de cabeças Sim, quando as equações e as entradas são preservadas Escalonamento, localidade, particionamento do compilador, cópias de memória
Partição nos endpoints da CPU, norma de embedding offline, consultas selecionadas na cabeça final Sim em aritmética real; validar o arredondamento Operações não suportadas, pegada do pacote, algum trabalho não usado
Paletização de 8/6/4 bits ou quantização de pesos Geralmente não Tráfego/armazenamento de pesos e possivelmente energia/latência de inferência
Poda de pesos não nulos aprendidos ou fatoração de baixo posto Não, a menos que exista uma estrutura algebricamente exata Aritmética matricial e tráfego após recuperação/calibração
Saída antecipada, poda de tokens, menos camadas, student mais estreito Não Poupanças potencialmente grandes; novo modelo e contrato de qualidade
Reutilização do estado oculto entre perguntas arbitrárias Não para este codificador bidirecional Atalho inválido; os estados contextuais dependem da pergunta
Colocar em cache respostas idênticas de entrada completa Exato para acertos de cache Característica da carga de trabalho; não é velocidade de inferência sem cache

A atual visão geral de otimização da Apple aponta a paletização para ganhos de memória/latência no NE e identifica o caminho de cálculo W8A8 mais recente com A17 Pro/M4. Não extrapoles essa aceleração de hardware mais recente para este M3 Max. O guia de desempenho da quantização também avisa que a desquantização das ativações pode abrandar a execução na CPU/GPU. Obtém primeiro uma linha de base residente no NE e depois testa a paletização de pesos de 8 bits para baixo, preservando as normas/scorers sensíveis quando apropriado.

Empacotar pesos FP16 em oito ou quatro bits dá um rácio ideal de armazenamento de pesos de 2× ou 4× antes dos metadados. Isso não é um multiplicador de latência igual: a descompressão, o movimento das ativações e o cálculo permanecem. A poda só ajuda o runtime se a representação escolhida explorar realmente os zeros. Remover cabeças/camadas arbitrárias ou fazer truncagem de baixo posto exige recuperação de qualidade e não consegue manter a identidade do modelo original sem ressalvas.

Para um limite de erro de logits por entrada ||z'-z||_infinity <= delta, um certificado de argmax suficiente é top1(z)-top2(z) > 2delta. Com a mesma temperatura de calibração positiva T, o limite de Lipschitz da norma infinito do softmax dá ||p'-p||_infinity <= delta/(2T). Estes são diagnósticos úteis em entradas avaliadas, não um certificado global para a quantização. Preserva fatias separadas de margem estreita e de avaliação multilingue; exemplos saturados podem esconder grandes erros de logits.

Três experiências e gates de aceitação

  1. Grafo NE equivalente de forma fixa. Exporta o multilingue B=1,L=96,K=4 e o Snake B=3,L=64,K=4 com projeções BC1L, RoPE por cabeça correto, atenção explícita e LayerNorm/GELU originais. Compara os arrays de entrada e as saídas de camadas individuais com o grafo original. Inspeciona que projeções e blocos de atenção principais são preferidos pelo NE e depois verifica a atividade real do NE em runtime. Uma contagem de operações suportadas, por si só, não é sucesso. Volta a executar a linha de base MLX otimizada correspondente em blocos alternados.
  2. Uma ilha transformer contígua. Se o primeiro grafo se fragmentar, move o embedding e a pequena cauda final para fronteiras de CPU. Compara isto com o candidato de grafo completo sob a mesma medição de potência. Mantém um candidato apenas se as predições completas melhorarem a latência ou a energia para além da variação observada entre execuções. Inclui todas as cópias; um codificador isolado rápido é insuficiente.
  3. Compressão focada na energia depois de a colocação funcionar. Triagem da paletização de 8 bits e depois de 6/4 bits como variantes aproximadas separadas. Corre o gate de fixture inalterado, tarefas choice/score/noul reservadas, entradas multilingues, quase empates e trajetórias do Snake. Publica a exatidão, o desvio de probabilidade e a calibração a par do desempenho. A compressão agressiva ou a destilação pertencem a um modelo com nome separado se alterarem o comportamento aprendido.

Antes de uma afirmação de lançamento, usa os mesmos hashes de checkpoint/entrada e uma ordem alternada de linha de base/candidato; exclui a compilação a frio mas reporta-a em separado. Usa pelo menos cinco blocos sustentados por finalista e retém amostras em bruto de latência, chamadas concluídas e potência. Exige a concordância do fixture original e as tolerâncias de probabilidade existentes sem as relaxar para o candidato passar, além de saídas finitas estáveis e memória limitada. Mede entradas longas e nas fronteiras das formas em separado das demonstrações curtas de forma fixa.

Declara 10× apenas quando o rácio relevante de velocidade, potência com carga igual ou energia for pelo menos dez, com uma incerteza que sustente a afirmação, cumprindo ao mesmo tempo os limites declarados de latência e de qualidade na tarefa. Se o limite inferior de incerteza não chegar a dez, reporta o rácio medido. Um ganho de energia menor com execução verificada no NE continua a ser evidência útil; não é um resultado de ordem de grandeza.

Proveniência da documentação

Usou o fluxo de trabalho obrigatório da CLI Context7: resolveu Core ML Tools para /apple/coremltools e depois consultou o lowering de operadores/layout de transformers e o comportamento de compressão do NE (três comandos no total). Verificou o artigo de investigação da Apple, o código-fonte de referência, a documentação atual de otimização do Core ML, a documentação do plano de cálculo e a especificação do dispositivo ligada acima. As equações do modelo, as contagens de parâmetros e as medições iniciais foram derivadas deste repositório e do seu irmão MLX. Este ramo de investigação não correu nenhum benchmark concorrente de GPU/ANE.