Конвертация ML-модели в Core ML формат для iOS

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Конвертация ML-модели в Core ML формат для iOS
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Конвертация ML-модели в Core ML формат для iOS

Получить .mlpackage из PyTorch или TensorFlow модели — задача с конкретными шагами, где каждый шаг может сломаться по специфической причине. coremltools конвертирует не всё и не всегда правильно. Разберём реальный процесс конвертации, включая то, что идёт не так.

Подготовка модели к конвертации

Перед конвертацией модель должна быть в eval-режиме с фиксированными весами. torch.jit.trace требует примера входных данных — он записывает граф выполнения для конкретного shape:

import torch
import coremltools as ct

model = MyModel()
model.load_state_dict(torch.load("weights.pth", map_location="cpu"))
model.eval()

# trace — фиксирует граф для конкретного shape
example_input = torch.zeros(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)

# Для моделей с условными ветками (if/else зависящими от данных) — script:
# scripted_model = torch.jit.script(model)  # анализирует код, не данные

torch.jit.trace не работает с динамическими ветками — если в forward() есть if x.shape[1] > 512: ..., trace запомнит только одну ветку. В таком случае нужен torch.jit.script, который анализирует весь код статически.

Конвертация через coremltools

mlmodel = ct.convert(
    traced_model,
    inputs=[ct.ImageType(
        name="input",
        shape=ct.Shape(shape=(1, 3, 224, 224)),
        color_layout=ct.colorlayout.RGB,
        # Нормализация встроена в модель — не нужно делать в Swift
        bias=[-0.485/0.229, -0.456/0.224, -0.406/0.225],
        scale=1/(255.0 * 0.229)
    )],
    outputs=[ct.TensorType(name="logits")],
    compute_precision=ct.precision.FLOAT16,
    minimum_deployment_target=ct.target.iOS16,
    convert_to="mlprogram"  # новый формат .mlpackage
)

# Добавляем метаданные
mlmodel.short_description = "Image classifier"
mlmodel.input_description["input"] = "RGB image 224x224"
mlmodel.output_description["logits"] = "Class probabilities"

mlmodel.save("MyModel.mlpackage")

convert_to="mlprogram" vs "neuralnetwork": mlprogram — новый IR, поддерживает FP16 ANE-операции, требует iOS 15+. neuralnetwork — старый формат, iOS 12+. Для новых проектов — mlprogram.

Частые ошибки конвертации

ValueError: TorchScript conversion failed — обычно из-за нестандартных операций. Проверяем через:

# Какие операции не поддерживаются:
print(ct.converters.mil.frontend.torch.ops.PYTORCH_OPS_REGISTRY.keys())
# Если операции нет — нужна кастомная реализация

RuntimeError: Only tuple/list outputs are supported — модель возвращает dict. Нужна обёртка:

class ModelWrapper(torch.nn.Module):
    def __init__(self, model):
        super().__init__()
        self.model = model
    def forward(self, x):
        out = self.model(x)
        if isinstance(out, dict):
            return out["logits"]  # извлекаем нужный ключ
        return out

Unsupported op: aten::einsum — einsum в PyTorch. Нужно переписать через стандартные matmul/bmm, или добавить custom op.

ONNX как промежуточный шаг — когда прямая конвертация не работает:

# PyTorch → ONNX → Core ML
torch.onnx.export(model, example_input, "model.onnx", opset_version=17)
mlmodel = ct.converters.onnx.convert(
    model="model.onnx",
    minimum_ios_deployment_target="15.0"
)

Конвертация через ONNX иногда решает проблемы с неподдерживаемыми PyTorch операциями.

Проверка корректности конвертации

import numpy as np
import PIL.Image

# Загружаем тестовое изображение
img = PIL.Image.open("test.jpg").resize((224, 224))

# Оригинальный PyTorch вывод
transform = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor(),
    torchvision.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
tensor = transform(img).unsqueeze(0)
with torch.no_grad():
    pytorch_out = model(tensor).numpy()

# Core ML вывод
coreml_out = mlmodel.predict({"input": img})["logits"]

# Сравниваем
max_diff = np.max(np.abs(pytorch_out - coreml_out))
print(f"Max difference: {max_diff}")
# Норма для FP16: < 0.01
# Если больше 0.05 — что-то пошло не так при конвертации

Если разница большая — проверяем нормализацию: возможно, bias и scale в ct.ImageType не соответствуют нормализации в pytorch transform.

Переменные размеры входа

Для моделей, работающих с изображениями разного размера:

# Диапазон размеров
flexible_shape = ct.Shape(
    shape=(1, 3, ct.RangeDim(min_val=64, max_val=1024), ct.RangeDim(min_val=64, max_val=1024))
)

# Или набор конкретных размеров
enumerated_shapes = ct.EnumeratedShapes(
    shapes=[
        ct.Shape(shape=(1, 3, 224, 224)),
        ct.Shape(shape=(1, 3, 384, 384)),
        ct.Shape(shape=(1, 3, 512, 512)),
    ]
)

mlmodel = ct.convert(traced_model, inputs=[ct.TensorType(name="input", shape=enumerated_shapes)])

EnumeratedShapes позволяет Core ML заранее оптимизировать граф для каждого из указанных размеров. RangeDim — более гибкий, но оптимизация хуже.

Кастомные операции

Если модель содержит операцию, которую coremltools не знает — можно добавить кастомный слой на Swift/Objective-C:

# Python: регистрация кастомной операции
@ct.converters.mil.register_torch_op()
def my_custom_op(context, node):
    # Реализация конвертации через MIL операции
    x = context[node.inputs[0]]
    result = mb.custom(params={"...": "..."}, inputs={"x": x}, ...)
    context.add(result)
// Swift: реализация кастомного слоя
import CoreML

@objc(MyCustomLayer)
class MyCustomLayer: NSObject, MLCustomLayer {
    required init(parameters: [String: Any]) throws { }

    func setWeightData(_ weights: [Data]) throws { }
    func outputShapes(forInputShapes inputShapes: [[NSNumber]]) throws -> [[NSNumber]] { ... }
    func evaluate(inputs: [MLMultiArray], outputs: [MLMultiArray]) throws { ... }
}

Кастомные слои всегда выполняются на CPU, без ANE/GPU ускорения. Если custom op — узкое место инференса, лучше переписать модель на стандартных операциях.

Интеграция .mlpackage в Xcode

Файл .mlpackage добавляется в проект — Xcode автоматически генерирует Swift-класс с typed API. Имя файла MyModel.mlpackage → класс MyModel с методом prediction(input:).

Размер .mlpackage в bundle влияет на время загрузки в App Store и размер скачиваемого приложения. Для больших моделей (>50 МБ) — размещать вне bundle, скачивать при первом запуске через URLSession и хранить в Application Support.

Процесс

Аудит модели на совместимость → конвертация с подбором параметров → верификация числовой точности → тестирование на целевых iOS-версиях → профилирование в Xcode Core ML Instrument.

Ориентиры по срокам

Стандартная модель без нестандартных операций — 3–7 дней. Модель со сложным графом, кастомными операциями, переменными размерами — 2–4 недели.