Inferencia en dispositivo con Core ML: los patrones que realmente llegan a producción
Core ML es el motor de inferencia en dispositivo que viene con cada dispositivo Apple moderno. El framework despacha al Neural Engine cuando está disponible, al GPU cuando no, y a la CPU como último recurso, eligiendo la ruta más rápida automáticamente según el modelo y el hardware1. El resultado en un iPhone reciente es inferencia con latencia de submilisegundos a decenas bajas de milisegundos para la mayoría de tamaños de modelos en producción, gratis por llamada, sin viaje de red y sin exposición de datos a terceros.
La reputación del framework como “tubería oscura” está desactualizada. Core ML ahora impulsa el LLM en dispositivo de Apple Intelligence, la búsqueda semántica de la app Fotos, el reconocimiento de escenas de la app Cámara y la mayoría de apps de terceros que llevan ML local. Los patrones que hacen que un despliegue de Core ML realmente llegue a producción, en lugar de funcionar-solo-en-mi-Mac, son un conjunto reducido: conversión de modelos, sugerencias de despacho, presupuesto de latencia y cuantización. El post recorre cada uno frente a la documentación de Apple.
TL;DR
- Core ML ejecuta archivos
.mlpackagey.mlmodelen el Neural Engine, GPU y CPU de Apple Silicon. El despacho es automático pero puede sugerirse medianteMLModelConfiguration.computeUnits2. - La conversión de modelos ocurre a través de
coremltools(PyTorch, TensorFlow, ONNX → Core ML). La conversión es una tarea de tooling, no de runtime; una vez convertido y empaquetado el modelo, la app lo carga y lo ejecuta. - La arquitectura de memoria unificada de Apple Silicon significa que los pesos del modelo no se copian entre CPU, GPU y NE; la misma memoria respalda los tres3. Este detalle arquitectónico es lo que hace posible la inferencia con latencia de submilisegundos.
- La cuantización (INT8, INT4 en versiones recientes de Core ML) reduce el tamaño del modelo y acelera la inferencia en el Neural Engine, con un costo medible en precisión que depende del modelo.
- La conexión con flujos de trabajo de agentes: Foundation Models (el LLM en dispositivo de Apple Intelligence) viene como un modelo Core ML detrás de una API Swift de alto nivel; aplican los mismos patrones de despacho y cuantización.
El modelo mental: tres rutas de cómputo, una memoria
Apple Silicon (Macs serie M e iPhones serie A desde el A12 Bionic en adelante) trae tres objetivos de inferencia:
Neural Engine. Un acelerador especializado para multiplicación de matrices a baja precisión. El más rápido para las operaciones de las que dependen los modelos de ML modernos (convoluciones, atención, embeddings). Menor consumo de energía. Limitado a tipos específicos de operaciones y formas de tensor; las operaciones no soportadas se delegan al GPU o CPU por capa.
GPU. Cómputo paralelo de propósito general a través de Metal. Más lento que el Neural Engine para trabajo con forma de ML pero más rápido que la CPU. Maneja operaciones que el Neural Engine no soporta.
CPU. El recurso de respaldo. Lenta para inferencia de ML, pero siempre disponible, siempre soporta cada operación, y predecible.
La arquitectura de memoria unificada significa que la misma RAM física respalda las tres3. Los pesos de un modelo, cargados una sola vez, no se copian cuando el despacho cambia entre objetivos. Este hecho arquitectónico es lo que convierte el despacho multiobjetivo de un costo de copia por capa en una decisión de planificación por capa.
MLModelConfiguration.computeUnits controla el despacho:
let config = MLModelConfiguration()
config.computeUnits = .all // default: NE, GPU, CPU
// Other options:
// .cpuAndGPU
// .cpuAndNeuralEngine
// .cpuOnly
let model = try MyModel(configuration: config)
.all es el predeterminado y la elección correcta para casi cualquier app. El framework elige la ruta más rápida por operación, y la decisión por operación es más rápida que cualquier heurística que el desarrollador pudiera escribir. La razón poco frecuente para anularlo es forzar .cpuOnly para pruebas de paridad (un modelo se comporta de forma distinta en distintas rutas y la prueba quiere la ruta determinista) o forzar .cpuAndGPU para liberar el Neural Engine para otra tarea concurrente.
Conversión de modelos: la tarea de tooling
La mayoría de modelos de ML se entrenan en PyTorch, TensorFlow o directamente a través de Create ML de Apple. Core ML acepta archivos .mlpackage, el formato moderno introducido en Xcode 13 que reemplaza al antiguo .mlmodel4. La conversión ocurre a través de coremltools, el paquete Python de código abierto de Apple5.
Una conversión típica de PyTorch a Core ML sigue tres pasos:
- Cargar el modelo PyTorch entrenado y ponerlo en modo de inferencia.
- Trazar el modelo con un tensor de entrada de ejemplo que coincida con la forma de entrada de producción.
- Convertir el modelo trazado con
coremltoolscontra una versión de iOS objetivo de despliegue.
import torch
import coremltools as ct
model = MyTrainedModel()
model.load_state_dict(torch.load("weights.pth"))
example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)
mlmodel = ct.convert(
traced_model,
inputs=[ct.ImageType(name="image", shape=example_input.shape)],
minimum_deployment_target=ct.target.iOS18,
compute_units=ct.ComputeUnit.ALL,
)
mlmodel.save("MyModel.mlpackage")
La conversión sucede una sola vez, en un entorno de desarrollo, contra una versión de iOS objetivo de despliegue (minimum_deployment_target). La salida .mlpackage es lo que se incorpora al proyecto Xcode. La app en runtime no ejecuta coremltools.
Dos trampas prácticas en la conversión. Primero, las entradas de forma dinámica necesitan un manejo explícito a través de ct.RangeDim porque el predeterminado de forma estática de Core ML produce errores poco útiles cuando la app de producción alimenta tamaños de entrada variables. Segundo, las operaciones personalizadas en PyTorch que no tienen un equivalente en Core ML necesitan o bien una capa personalizada de Core ML (código Swift que ejecuta la operación faltante) o un cambio en la arquitectura del modelo para eliminar la operación antes de la conversión. Ambas están bien documentadas5.
Presupuestos de latencia que realmente aplican
Tres presupuestos de latencia importan para apps en producción:
16 ms (UI en vivo a 60 fps). Un filtro de cámara en tiempo real, una escena AR que se actualiza por fotograma, un analizador de audio en vivo. El presupuesto incluye todo: preprocesamiento de imagen, inferencia del modelo, postprocesamiento, actualización de UI. Los modelos que caben suelen ser pequeños (clase MobileNetV3, menos de 100M parámetros) y se ejecutan en el Neural Engine.
100 ms (UI interactiva). Un usuario realiza una acción y espera el resultado: tocar para identificar, dibujar para reconocer, dictar para transcribir. El presupuesto es más permisivo y soporta modelos más grandes. Modelos de lenguaje de menos de 1B parámetros, transformers de visión pequeños y la mayoría de clasificadores de grado de producción caben cómodamente.
1 s+ (segundo plano o por lotes). Indexado de fototeca, análisis de documentos, calentamiento de modelo al arrancar la app. Los modelos más grandes funcionan, pero la expectativa del usuario debe establecerse con un indicador de progreso. El LLM en dispositivo de Foundation Models vive aquí para las operaciones de ventana de contexto más grande.
Los presupuestos son orientativos, no límites duros. La jugada correcta es medir en un dispositivo objetivo usando os_signpost o la plantilla de Core ML de Instruments6 en lugar de confiar en números teóricos de otra máquina.
Cuantización: cuando más pequeño es más rápido
Core ML soporta varios niveles de cuantización7:
- Float32 (precisión completa). El predeterminado de entrenamiento. El más grande, el más preciso, el más lento.
- Float16. Precisión media. Más pequeño y más rápido en GPU y NE; la pérdida de precisión suele ser despreciable para modelos bien condicionados.
- INT8. Cuantización entera de 8 bits con calibración. Aproximadamente 4x más pequeño que Float32, frecuentemente 2-4x más rápido en NE. La pérdida de precisión varía; para modelos de visión, una pérdida de precisión top-1 menor al 1% es alcanzable con entrenamiento consciente de la cuantización.
- INT4 e inferiores. Cuantización agresiva que las versiones recientes de Core ML soportan para arquitecturas específicas de modelos (LLMs, modelos grandes de visión). La pérdida significativa de precisión es la contrapartida; la técnica funciona mejor cuando se combina con entrenamiento consciente de la cuantización específico del modelo.
La configuración de cuantización lineal a través de coremltools.optimize.coreml.linear_quantize_weights acepta una configuración global de operación que selecciona el modo de cuantización (linear_symmetric o linear) y un umbral de tamaño de peso por debajo del cual los pesos permanecen en precisión completa. La conversión se ejecuta sobre un .mlpackage existente y produce un nuevo paquete cuantizado; ambos pueden enviarse lado a lado en el bundle, con la app eligiendo cuál cargar según la clase de dispositivo.
La decisión de cuantización es por modelo: un clasificador pequeño puede no beneficiarse porque su cómputo ya es barato; un modelo de lenguaje grande se beneficia enormemente porque su cómputo está dominado por multiplicaciones de matrices sobre los pesos cuantizados. El enfoque correcto es cuantizar, medir la precisión sobre un conjunto de prueba apartado y enviar a producción si el impacto en precisión es aceptable para el caso de uso.
Modelos preentrenados de Apple que puedes integrar directamente
Apple distribuye varios modelos Core ML preentrenados a través de la página Core ML Models8. Categorías que vale la pena conocer:
- Clasificación de imágenes: MobileNetV2, ResNet50, variantes de SqueezeNet, todos empaquetados y listos para incorporar a un
VNCoreMLRequestdel framework Vision. - Detección de objetos: YOLOv3, MNIST, variantes de CenterNet.
- Estimación de pose: PoseNet para pose corporal (una alternativa de referencia al
VNDetectHumanBodyPoseRequestde Vision). - Segmentación semántica: DeepLabV3 para segmentación de imágenes.
- Reconocimiento de texto: Alternativas de OCR basadas en ML al integrado de Vision.
Para la mayoría de apps, los modelos preentrenados de Apple cubren las primitivas de percepción (clasificar, detectar, segmentar) sin requerir entrenamiento personalizado. El LLM en dispositivo de Foundation Models (cubierto en Foundation Models en dispositivo LLM) es el ejemplo más grande: un LLM multimillardo de parámetros que viene como un modelo Core ML detrás de una API Swift de alto nivel, despachado en el Neural Engine, disponible sin conexión.
Cifrado de modelos y consideraciones para la App Store
Un .mlpackage en el bundle de la app es legible por cualquiera que descomprima el IPA. Para modelos que representan propiedad intelectual significativa, Apple soporta el cifrado de modelos a través del flujo Encrypt your Core ML model9: se genera una clave de cifrado a través de Xcode y se gestiona a través de CloudKit, el modelo en el bundle se cifra, y Core ML lo descifra al cargarlo.
Para la mayoría de apps, el cifrado es excesivo. Un modelo entrenado con datos comunes de ImageNet no es un diferenciador competitivo; cifrarlo agrega complejidad operativa sin proteger nada valioso. Reserva el cifrado para modelos que representen una inversión genuina en datos de entrenamiento o ventaja competitiva.
Privacidad en dispositivo: la victoria arquitectónica
La historia de privacidad es directa. La inferencia de Core ML sucede enteramente en el dispositivo. Los datos de entrada (imágenes, audio, texto) no salen del dispositivo. El archivo del modelo es local; la inferencia es local; el resultado es local.
Para apps en industrias reguladas (salud, finanzas, educación), este hecho arquitectónico elimina toda una clase de trabajo de cumplimiento. No hay un procesador de datos de terceros que añadir a la política de privacidad. No hay un endpoint de API de modelo que auditar por seguridad. No hay pregunta de residencia de datos porque los datos nunca se mueven.
El formato Privacy Manifest10 codifica la historia de privacidad para el envío a la App Store: una app que usa Core ML para inferencia en dispositivo y nada más puede declarar cero compartición de datos con terceros para la ruta de inferencia. El proceso de envío es más rápido, la revisión de privacidad es más corta, y la etiqueta nutricional de privacidad de cara al usuario es más limpia.
La conexión con flujos de trabajo de agentes
Core ML se combina con tres patrones que el cluster ya ha cubierto:
VNCoreMLRequest del framework Vision. Modelos Core ML personalizados se ejecutan a través del pipeline de Vision con preprocesamiento automático. El patrón (cubierto en Vision Framework) es la forma correcta de enviar a producción un clasificador o detector de imágenes personalizado dentro de una app iOS.
LLM en dispositivo de Foundation Models. El LLM de Apple Intelligence es un modelo Core ML detrás de una API Swift de alto nivel. Aplican los mismos patrones de despacho (Neural Engine primero), cuantización (INT4 para los pesos del LLM) y presupuesto de latencia (sub-segundo para generaciones cortas). El post sobre Foundation Models cubre la API; este post cubre el motor subyacente.
Herramientas de App Intents que usan ML local. Un AppIntent que ejecuta un clasificador local de imágenes o de texto devuelve resultados estructurados a Apple Intelligence sin un viaje de red. La combinación es lo que hace que el “Apple agéntico” sea realmente privado; las herramientas del agente se ejecutan localmente porque el framework lo soporta.
Cuándo la inferencia en la nube es la decisión correcta
El techo de Core ML es el cómputo del dispositivo. Tres casos donde la nube es lo correcto:
Modelos demasiado grandes para empaquetar en un bundle. Un LLM de 70B parámetros no cabe en el bundle de una app. Para cargas de trabajo a esa escala, la inferencia en la nube (o en dispositivo vía streaming de pesos, un patrón distinto) es la herramienta correcta.
Estado compartido entre dispositivos durante la inferencia. Modelos que necesitan leer o escribir en una base de datos compartida durante la inferencia (sistemas de recomendación con filtrado colaborativo contra miles de millones de registros). El modelo puramente local de Core ML no encaja.
Iteración rápida del modelo. Un equipo que envía actualizaciones de modelo a diario se beneficia de la inferencia del lado del servidor porque los despliegues no requieren ciclos de revisión de la App Store. El patrón de Core ML de empaquetar el modelo en la app añade fricción a la cadencia de revisión del modelo; la contrapartida es real.
El patrón: la nube gana en escala y velocidad de iteración; Core ML gana en latencia, costo y privacidad.
Lo que este patrón significa para apps iOS 26+
Tres conclusiones.
-
Por defecto, usa Core ML para cualquier modelo que quepa en el bundle y produzca un resultado por llamada sobre el que el usuario pueda actuar. Clasificación de imágenes, detección de objetos, clasificación de audio, reconocimiento de gestos, generación de embeddings, tareas de lenguaje pequeñas a medianas. El despacho automático del framework y la NPU de Apple Silicon producen inferencia con latencia de submilisegundos a decenas bajas de milisegundos gratis.
-
Cuantiza agresivamente cuando el impacto en precisión sea aceptable. INT8 suele ser seguro; INT4 es apropiado para modelos grandes donde el ahorro de tamaño importa. Mide la precisión sobre un conjunto apartado en lugar de confiar en que la cuantización sea universalmente segura.
-
Combina con Vision y Foundation Models para pipelines locales completos. Core ML es el motor; Vision es la API de percepción encima de él; Foundation Models es el LLM encima de él. El post de Vision y el post de Foundation Models del cluster cubren las superficies de más alto nivel.
El cluster completo del Ecosistema Apple: App Intents tipados; servidores MCP; la pregunta de enrutamiento; Foundation Models; la distinción entre LLM de runtime y de tooling; tres superficies; el patrón de fuente única de verdad; Dos Servidores MCP; hooks para desarrollo Apple; Live Activities; el contrato de runtime de watchOS; internals de SwiftUI; el modelo mental espacial de RealityKit; disciplina de esquemas en SwiftData; patrones Liquid Glass; envío multiplataforma; la matriz de plataformas; framework Vision; Symbol Effects; sobre lo que me niego a escribir. El hub está en la Serie del Ecosistema Apple. Para contexto más amplio sobre iOS con agentes de IA, mira la guía de Desarrollo de Agentes iOS.
FAQ
¿Cómo decide Core ML entre Neural Engine, GPU y CPU?
Core ML examina cada operación en el grafo del modelo y la despacha al objetivo más rápido que soporte la operación. El Neural Engine maneja las operaciones soportadas (la mayoría de multiplicaciones de matrices, convoluciones, atención) con la latencia y el consumo más bajos. El GPU maneja las operaciones que el NE no soporta. La CPU maneja el resto. La decisión es por operación, automática y más rápida que una heurística escrita a mano.
¿Debería usar siempre .computeUnits = .all?
Casi siempre. El despacho automático del framework está bien afinado. Anúlalo a .cpuOnly cuando pruebes paridad de salida (el mismo modelo devuelve resultados ligeramente distintos en NE vs CPU debido a redondeo en punto flotante) o a .cpuAndGPU para liberar el Neural Engine para una tarea concurrente.
¿Cuál es la diferencia práctica entre .mlpackage y .mlmodel?
.mlpackage es el formato moderno introducido en Xcode 13. Soporta metadatos almacenados, múltiples variantes de modelo para compilación de ML Program (mlprogram) y el toolchain posterior a iOS 13. .mlmodel es el formato heredado. Ambos siguen cargándose a través de MLModel; el desarrollo nuevo debería usar .mlpackage.
¿Qué tan grande puede ser un modelo Core ML en el bundle de una app?
No hay un límite fijo, pero los tamaños de bundle de la App Store están limitados a 4 GB para descarga y tienen límites prácticos para instalación por aire. El LLM en dispositivo de Foundation Models pesa alrededor de 3 GB y lo distribuye el sistema operativo en lugar del bundle de la app. Para modelos empaquetados con la app, menos de 100 MB es cómodo; 100-500 MB es factible con una estrategia de carga al inicio; 500 MB+ se maneja mejor a través de descarga en segundo plano con BGProcessingTask o recursos bajo demanda.
¿Cómo sé si la cuantización afectó la precisión de mi modelo?
Aparta un conjunto de prueba, ejecuta inferencia sobre el modelo Float32 original y el modelo cuantizado, compara métricas (precisión top-1 para clasificadores, F1 para detectores, perplejidad para modelos de lenguaje, BLEU para traducción, etc.), decide según los requisitos de precisión de la aplicación. El entrenamiento consciente de la cuantización (entrenar el modelo con la cuantización simulada en la pérdida) usualmente recupera la mayor parte de la pérdida de precisión.
Referencias
-
Apple Developer Documentation: Core ML. Referencia del framework que cubre el comportamiento de despacho automático entre unidades de cómputo. ↩
-
Apple Developer Documentation:
MLModelConfiguration.computeUnits. Casos del enum que controlan qué unidades de cómputo puede usar el modelo. ↩ -
Apple Developer: Apple silicon performance (introducción de WWDC 2020 a la arquitectura de memoria unificada de Apple Silicon). ↩↩
-
Apple Developer Documentation: Core ML Model. Referencia del formato
.mlpackagey.mlmodel. ↩ -
Documentación de
coremltools. El paquete Python de código abierto de Apple para convertir modelos entrenados de PyTorch, TensorFlow y ONNX a Core ML. ↩↩ -
Apple Developer Documentation: Profiling Core ML models with Instruments. La plantilla de Core ML de Instruments para análisis de latencia y despacho por capa. ↩
-
Optimización de
coremltools. Técnicas de cuantización y patrones de preservación de precisión soportados por Core ML. ↩ -
Apple Developer: Core ML Models. La galería de modelos preentrenados de Apple listos para incorporar a apps iOS. ↩
-
Apple Developer Documentation: Encrypting a Model in Your App. El flujo de cifrado respaldado por CloudKit para modelos Core ML. ↩
-
Apple Developer Documentation: Privacy manifest files. El formato para declarar los comportamientos de recopilación de datos y rastreo de una app. ↩