Apple Core AI Export (.aimodel)¶
Experimental — Use with Caution
Core AI export is experimental and work-in-progress. The .aimodel runs on iOS, iPadOS and macOS 27 or later, and dynamic_batch=True is not supported: export one .aimodel per batch size instead.
Core AI is Apple's on-device inference framework from iOS, iPadOS and macOS 27. format="coreai" traces the model with torch.export and converts it with coreai-torch into an .aimodel asset — no ONNX step. Core AI decides at load time whether the CPU, the GPU or the Neural Engine runs it.
Prerequisites¶
coreai-torch supports Python 3.11 to 3.13 and installs on macOS (Apple silicon) and Linux x86-64, so an .aimodel can be exported on either. Running it needs the Core AI runtime of iOS, iPadOS or macOS 27.
Basic Core AI Export¶
from rfdetr import RFDETRNano
model = RFDETRNano(pretrain_weights="<path/to/checkpoint.pth>")
model.export(format="coreai")
This produces output/rfdetr-nano_fp32.aimodel. Segmentation and keypoint models export the same way. Pass coreai_precision="float16" for a half-size rfdetr-nano_fp16.aimodel whose input and outputs are float16 as well.
The asset keeps the contract of the other formats: one fixed [batch, 3, H, W] input, resized without antialiasing and ImageNet-normalized, as in the ONNX Inference example. Unlike CoreML, the tensors keep their names — input, then dets and labels, plus masks or keypoints — and any notes are stored in the asset metadata under rfdetr_notes.
Core AI Inference Example¶
import asyncio
import coreai.runtime as rt
import numpy as np
async def run(image: np.ndarray) -> dict[str, np.ndarray]:
model = await rt.AIModel.load("output/rfdetr-nano_fp32.aimodel", rt.SpecializationOptions.default())
outputs = await model.load_function("main")({"input": rt.NDArray(image)})
return {name: outputs[name].numpy() for name in ("dets", "labels")}
# image: (1, 3, H, W) float32, preprocessed as in the ONNX Inference example
outputs = asyncio.run(run(image))
import CoreAI
let model = try await AIModel(contentsOf: url) // SpecializationOptions.default
let main = try model.loadFunction(named: "main")!
var outputs = try await main.run(inputs: ["input": input]) // input: NDArray [1, 3, H, W]
let dets = outputs.remove("dets")!.ndArray!
let labels = outputs.remove("labels")!.ndArray!
Precision, Compute Units and Latency¶
Start with float32. With the default specialization Core AI runs a float32 .aimodel on the GPU, where it matches eager PyTorch detection for detection. Single-image latency of pretrained models with public test images (batch 1; M5 Pro Mac: macOS 27.0, Python runtime, median of 100 runs after 10 warm-ups; M4 iPad Air and A15 iPhone 13: 27.0, native Swift runtime in a release-profile app, median of three runs of 20 after 2 warm-ups):
| Model, precision | Core AI default | Core AI CPU | CoreML ALL |
CoreML CPU_ONLY |
|---|---|---|---|---|
RFDETRNano fp32, Mac |
7.4 ms | 30.6 ms | 7.7 ms | 28.0 ms |
RFDETRNano fp16, Mac |
3.6 ms | 20.0 ms | 3.4 ms | 14.2 ms |
RFDETRMedium fp32, Mac |
15.7 ms | 68.4 ms | 16.0 ms | 64.8 ms |
RFDETRSegNano fp32, Mac |
11.1 ms | 47.4 ms | 10.8 ms | 45.1 ms |
RFDETRNano fp32, iPad |
18.2 ms | — | 18.6 ms | — |
RFDETRNano fp16, iPad |
24.1 ms | 20.2 ms | — | — |
RFDETRNano fp32, iPhone |
52.3 ms | — | 44.2 ms | — |
RFDETRNano fp16, iPhone |
30.5 ms | 32.6 ms | — | — |
On Macs and M-series iPads Core AI and CoreML run RF-DETR at the same speed; choose by the framework your application targets. On iOS and iPadOS the default specialization places a float16 .aimodel on the Neural Engine. Whether that pays off depends on the chip:
- On the M4 iPad it is slower than the float32 GPU path.
- On the A15 iPhone 13 it is the fastest option, 1.4× faster than CoreML float32.
The first load compiles the asset for the Neural Engine (5 to 9 s on these devices; cached afterwards), so measure on your target devices before choosing float16.
float16 and the Neural Engine
On the Neural Engine a float16 topk returns corrupt indices, which would make RF-DETR's two-stage query selection gather the wrong encoder tokens and detect nothing (a float16 failure with the same symptom is reported in apple/coreai-torch#115). The exporter therefore runs that one topk in float32; the rest of a float16 graph stays float16. With it, float16 RFDETRNano on the Neural Engine of an M5 Pro Mac scores 47.97 box AP on COCO val2017, against 48.02 for float32.
Keypoint models: do not run float16 on the Neural Engine
A float16 RFDETRKeypointPreview .aimodel terminates the process when Core AI runs it on the Neural Engine: the first inference aborts inside MPSGraph (ANERegion.mm:414: ANE inference operation failed), and no error reaches the caller. iOS and iPadOS choose the Neural Engine for float16 by default. Measured on macOS 27.0 (26A428), M5 Pro, with a Neural Engine preference; the same asset is correct with SpecializationOptions.cpu_only() or a GPU preference, and float32 is correct on every compute unit. Export keypoint models in float32, which is the default.
How the Conversion Works¶
coreai-torch has no lowering for aten.grid_sampler_2d, which the deformable attention uses, so the exporter decomposes it into gathers. Its in-bounds masks use float arithmetic rather than a comparison-to-bool chain, which the Core AI runtime can mishandle (apple/coreai-torch#11). The approach follows the RF-DETR port in the community coreai-model-zoo.