Capítulos · 01
Apple Neural Engine (ANE): Visión general y restricciones de hardware
Parte de la ANE Knowledge Base. Fuentes: artículos de Apple ML Research "Deploying Transformers on the Apple Neural Engine" (junio de 2022) y "Deploying Attention-Based Vision Transformers to Apple Neural Engine" (2024).
1. ¿Qué es el ANE?#
El Apple Neural Engine es el acelerador de redes neuronales dedicado de Apple (NPU), integrado en los SoC de Apple Silicon. Es hardware especializado y de bajo consumo energético, diseñado para ejecutar inferencia de ML con poca potencia, liberando a la CPU y la GPU para otras cargas de trabajo.
Historia y disponibilidad#
| Generación | Chip | Dispositivo | Cómputo |
|---|---|---|---|
| 1.ª | A11 Bionic (2017) | iPhone X | 0.6 TFlops (FP16) |
| 5.ª | A15 Bionic (2021) | iPhone 13 Pro | 15.8 TFlops (FP16) — ~26× la primera generación |
- iPhone: ANE presente desde el A11; la especificación de dispositivo de Apple para transformers optimizados apunta a A14 y posteriores.
- iPad: ANE disponible a partir del chip A12.
- Mac: ANE disponible a partir del chip M1 (y toda la serie M posterior).
Cómo se accede a él#
No existe una API pública directa para el ANE. Los modelos llegan a él a través de Core ML:
- Se convierte un modelo (por ejemplo, un modelo de PyTorch trazado) con
coremltoolsa un.mlpackage(ML Program). - En el momento de la carga, Core ML construye un plan de ejecución híbrido que "seamlessly blends CPU, GPU, and ANE (if available)" — cada op puede despacharse a distintas unidades de cómputo.
ct.ComputeUnit.ALL(predeterminado) permite a Core ML usar todas las unidades de cómputo, incluido el ANE. Que una op se ejecute realmente en el ANE depende de si la op y su disposición de tensores (tensor layout) son compatibles con el ANE.- Los informes de rendimiento de Xcode (pestaña Performance sobre un
.mlpackage) muestran el despacho por op a cada unidad de cómputo y la latencia medida en un dispositivo real — esta es la verdad de referencia para "¿mi modelo está realmente en el ANE?".
Implicación: conseguir que un modelo se ejecute es fácil; conseguir que todas (o la mayoría) de sus ops se mapeen sobre el ANE es de lo que tratan los principios de optimización de esta base de conocimiento. Una sola op incompatible en medio del grafo puede forzar costosos fallbacks a CPU/GPU y copias de memoria entre unidades de cómputo.
2. Características de hardware que impulsan cada optimización#
Estos son los hechos del ANE de los que derivan todos los principios de optimización de transformers (ver doc 02):
2.1 Formato de datos preferido: 4D, channels-first#
"The most conducive data format for the ANE (hardware and software stack) is 4D and channels-first" — es decir, (B, C, 1, S) para secuencias (llamado BC1S en el código de Apple) o (N, C, H, W) para imágenes. Por eso los transformers optimizados para el ANE reemplazan nn.Linear (que quiere (B, S, C)) por un nn.Conv2d 1×1 (que quiere (B, C, H, W)).
2.2 El último eje no está empaquetado: alineación a 64 bytes#
La restricción definitoria del búfer del ANE:
"The last axis of an ANE buffer is not packed; it must be contiguous and aligned to 64 bytes."
Cada 64 bytes de la última dimensión se procesan en un lote; si la última dimensión contiene menos de 64 bytes de datos, se rellena hasta 64 bytes (padding). Consecuencias:
- Si el último eje es un singleton (tamaño 1), un tensor FP16 recibe un padding de 32× (64× en precisión de 8 bits) — es decir, 32×/64× el coste de memoria y hasta 32× más lento el procesamiento efectivo.
- Ejemplo concreto del artículo de visión: una ventana de atención de 7×7 en disposición NCHW deja solo 7 elementos FP16 (14 bytes) en la última dimensión → 50 bytes de padding por fila.
- Por lo tanto: coloca al final una dimensión grande, idealmente múltiplo de 64 bytes. Para modelos de secuencias esa es la longitud de secuencia S; para el particionamiento en ventanas de los modelos de visión es la dimensión de canales (de ahí NHWC en ese caso — ver doc 04).
2.3 FP16 por defecto#
El ANE computa en precisión media (float16). Implicaciones prácticas:
- Las constantes numéricas ajustadas para FP32 pueden fallar. Ejemplo: el epsilon de LayerNorm de DistilBERT de
1e-12sufre underflow en FP16; el port de Apple usa1e-7(references/ml-ane-transformers/ane_transformers/huggingface/distilbert.py). - Las máscaras de atención aditivas deberían usar
-1e4(no-infni-1e9) para que varias máscaras puedan sumarse sin salirse del rango de FP16. - Se puede usar el clamping opcional de la entrada (
clip_magenLayerNormANE) para reducir el riesgo de overflow.
2.4 Rango máximo de tensor: 5D#
"ANE supports a maximum of 5D tensors." Las ops que naturalmente usan tensores 6D (por ejemplo, window partition/reverse en vision transformers de estilo Swin/MOAT, con forma (N, C, Nh, Nw, Hw, Ww)) deben reexpresarse como una cadena de reshapes/permutes de ≤5D (particionamiento "relay" — ver doc 04).
2.5 Los reshapes y transposes pueden disparar copias de memoria#
"Reshape and transpose operations are likely to trigger memory copies unless specifically handled." Las copias de memoria son puro overhead, por lo que el código optimizado para el ANE:
- evita
reshape/transposesiempre que sea posible, - cuando es inevitable, paga el coste una sola vez (por ejemplo, un único transpose del tensor de claves antes del matmul QK; un solo transpose NHWC antes de todo el particionamiento en ventanas en lugar de uno por ventana),
- prefiere formulaciones con
einsumcuyas disposiciones de operandos se mapean directamente al batched-matmul del hardware sin reordenamiento intermedio.
2.6 Residencia en la caché L2 y utilización multicore#
El ANE es un motor multicore con una caché L2. Los tensores intermedios grandes (por ejemplo, una proyección QKV multi-head completa o una matriz de atención gigantesca) se desbordan de la caché y serializan el trabajo. Fragmentar (chunking) los tensores grandes en piezas por cabeza:
- aumenta la probabilidad de que cada pieza permanezca residente en L2,
- permite al compilador de Core ML paralelizar las piezas entre los cores del ANE.
Esta es también la razón por la que el split softmax (softmax aplicado por cabeza de atención sobre tensores más pequeños) es mucho más rápido que un único softmax enorme.
2.7 Regímenes limitados por cómputo vs. limitados por ancho de banda#
Para cargas de trabajo pequeñas, el ANE suele estar limitado por el ancho de banda, no por el cómputo: "large parameter tensors are being fetched from memory, only to be applied on too few inputs before the next parameter tensor is fetched."
Evidencia observada: la latencia de DistilBERT se mantiene aproximadamente constante para longitudes de secuencia 32 → 64 → 128 (batch 1) aunque el cómputo de atención se cuadruplica. Remedios:
- Aumentar el tamaño del batch (cargas de trabajo de inferencia por lotes) — más aritmética por cada fetch de parámetros.
- Reducir los parámetros mediante cuantización o poda — menos datos que traer de memoria.
3. Lista rápida de comprobación de restricciones#
Úsala como comprobación previa (pre-flight) al apuntar al ANE. (En 2026 Apple publicó su propia versión oficial y ampliada de esta lista como una agent skill — ver doc 13 para las adiciones: convención K@Q, máscaras -40000, reglas de stride, conjunto de dtypes fp16/int8/int16, y más).
| # | Restricción | Qué hacer |
|---|---|---|
| 1 | Preferido 4D channels-first | Usar (B, C, 1, S) / NCHW; cambiar nn.Linear → nn.Conv2d 1×1 |
| 2 | Último eje contiguo + alineado a 64 bytes | Mantener al final una dimensión grande (longitud de secuencia, o canales ≥ múltiplo de 32); nunca un singleton |
| 3 | Cómputo FP16 | Auditar epsilons (≥ ~1e-7), valores de máscara (−1e4), vigilar el overflow |
| 4 | Máximo tensores 5D | Descomponer ops 6D en reshapes escalonados de ≤5D |
| 5 | Reshape/transpose → copias de memoria | Minimizar; agruparlos; usar einsum con disposiciones amigables para el hardware |
| 6 | L2 caché + multicore | Fragmentar tensores grandes (QKV por cabeza, split softmax) |
| 7 | Limitado por ancho de banda con batch/seq pequeños | Batch más grande, o cuantizar/podar pesos |
| 8 | Sin API directa; despacho híbrido | Convertir vía coremltools (mlprogram); verificar el despacho en los informes de rendimiento de Xcode |
| 9 | Algunas ops van mejor en CPU | Por ejemplo, las búsquedas de embeddings — unas pocas ops en CPU son correctas y esperables |
4. Adónde ir después#
- 02 — Principios de optimización de Transformers: los cuatro principios, con el código de referencia real de PyTorch.
- 03 — Caso de estudio: DistilBERT de Hugging Face: aplicar los principios a un modelo de terceros existente.
- 04 — Vision Transformers en el ANE: window attention, particionamiento relay 5D, NHWC, diseño de position embeddings.
- 05 — Flujo de trabajo de despliegue: PyTorch → Core ML → profiling en Xcode, de principio a fin.