Core ML

Core ML — это формат моделей Apple для работы на устройстве. LibreYOLO трассирует детектор за обёрткой предобработки, своей для каждого семейства, поэтому конвертированный граф всегда принимает канонический вход-изображение RGB, а затем записывает .mlpackage в формате ML Program с приложенными метаданными модели.

Флаг
export(format="coreml")
Записывает
Один бандл .mlpackage (директория) в формате ML Program
Дополнительно
pip install "libreyolo[coreml]"
Загружается обратно
LibreYOLO("weights/LibreYOLO9t.mlpackage") на macOS
Формы
Фиксированные. Вход — жёстко заданный ct.ImageType.
Точность
FP32, FP16 (half=True). INT8 нет.
Семейства
Только детекция, для yolox, yolo9, rtdetr и rfdetr

Установка

Установка
pip install "libreyolo[coreml]"

Для предсказания нужен macOS. На любой другой платформе LibreYOLO() отказывается принимать .mlpackage и называет в сообщении текущую платформу, а матрица поддержки отмечает эти комбинации как доступные на том основании, что для паритета среды выполнения нужен macOS-раннер.

Экспорт

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Записывает бандл weights/LibreYOLO9t.mlpackagepath = model.export(format="coreml")print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format coreml
Аргументы
model.export(    format="coreml",    imgsz=640,    batch=1,    half=False,           # True конвертирует с вычислительной точностью FLOAT16    compute_units="all",  # all | cpu_and_gpu | cpu_and_ne | cpu_only    output_path=None,     # None записывает weights/<stem>.mlpackage) # dynamic принимается, но вход — это ct.ImageType с фиксированной формой,# и встроенные метаданные в любом случае записывают dynamic=False.

Бандл записывается в weights/ под именем чекпойнта, с добавлением _fp16, когда half=True. .mlpackage — это директория, поэтому копировать нужно всё дерево.

Каждое семейство трассируется за обёрткой предобработки, поэтому конвертированный граф принимает один канонический вход: RGB, scale=1/255, без смещения, объявленный как ct.ImageType. Обёртка вбирает в себя собственное соглашение семейства: BGR в диапазоне от 0 до 255 для YOLOX, среднее и стандартное отклонение ImageNet для RF-DETR, тождественное преобразование для YOLO9 и RT-DETR. Именно поэтому потребитель Core ML подаёт обычное изображение, а не тензор конкретного семейства.

Конвертация нацелена на ML Program с минимальной целевой платформой iOS 15. compute_units сохраняется в конвертированной модели, и его можно переопределить ещё раз при загрузке артефакта.

Метаданные модели попадают в user_defined_metadata в виде строк — оттуда бэкенд читает семейство, задачу, имена классов, размер входа и схему позы.

Встроенный NMS

Встраивание слоя NMS от Apple
from libreyolo import LibreYOLO # Только детекция YOLOX и YOLO9, батч 1.LibreYOLO("LibreYOLO9t.pt").export(    format="coreml",    nms=True,    conf=0.25,    iou=0.45,)
CLI
libreyolo export --model LibreYOLO9t.pt --format coreml --nms \  --conf 0.25 --iou 0.45

nms=True оборачивает модель в Core ML-пайплайн, который заканчивается слоем NonMaximumSuppression от Apple. У результата два выхода: confidence формы N на число классов и coordinates формы N на 4 — нормализованные xywh.

Это работает только для детекции в YOLOX и YOLO9 и требует батча 1. Семейства в стиле DETR отклоняются по имени, потому что предсказание множества берёт top-k по запросам и классам без шага IoU и не может использовать этот слой. max_det здесь тоже не выведен наружу; когда важен предел на число детекций, используйте встроенный NMS в ONNX.

Запуск артефакта

Через LibreYOLO, на macOS
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO(    "weights/LibreYOLO9t.mlpackage",    compute_units="all",   # или cpu_and_ne, чтобы закрепить Neural Engine)result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
Голый coremltools
import coremltools as ctfrom PIL import Image mlmodel = ct.models.MLModel("weights/LibreYOLO9t.mlpackage")print(mlmodel.user_defined_metadata["model_family"])print(mlmodel.user_defined_metadata["names"]) # Вход — изображение с именем "image" фиксированного размера экспорта.image = Image.open(SAMPLE_IMAGE).convert("RGB").resize((640, 640))out = mlmodel.predict({"image": image})print({name: value.shape for name, value in out.items()}) # Леттербоксинг и постобработка на этом пути на вас.

LibreYOLO() распознаёт директорию с суффиксом .mlpackage и возвращает тот же объект Results, что и чекпойнт. compute_units — единственный аргумент, который фабрика пробрасывает для этого формата, и он принимает all, cpu_and_gpu, cpu_and_ne и cpu_only. Аргумент device игнорируется, потому что Core ML маршрутизирует вычисления через compute units.

Второй сниппет — путь через голую среду выполнения. Леттербоксинг, декодирование, NMS и пересчёт координат становятся там вашей задачей, а имена классов лежат в user_defined_metadata.

Ограничения

Четыре семейства, только детекция: yolox, yolo9, rtdetr и rfdetr. Всё остальное отклоняется на предварительной проверке, потому что именно обёртка предобработки, знающая своё семейство, делает контракт фиксированного входа-изображения корректным, а семейство вне этого списка сконвертировалось бы с неправильной нормализацией. В ошибке как альтернативы названы ONNX и TorchScript.

Форма входа жёстко зафиксирована через ct.ImageType, поэтому dynamic=True ничего не меняет, а метаданные записывают dynamic=False. Для второго разрешения экспортируйте второй бандл.

half=True конвертирует с вычислительной точностью FP16. Пути к INT8 у этого экспортёра нет.

Полную сетку семейств и задач смотрите в матрице экспорта. О более новом формате Apple для работы на устройстве — Core AI. Для одной комбинации:

Проверка одного семейства и задачи перед экспортом
libreyolo formats --family yolo9 --task detect

Прочитано из libreyolo/export/coreml.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/coreml.py и pyproject.toml в ветке dev.