Игорь Градов
Игорь Градов
6 мин
ai

Apple Neural Engine без документации: 163 MIL-файла в macOS заменяют закрытую спецификацию

Apple Neural Engine (ANE) позволяет запускать языковые модели на устройствах Apple без участия GPU и CPU, но документации по работе с ним почти нет: приходится разбирать системные файлы macOS и писать собственные инструменты.

Этот гайд показывает, как найти рабочие примеры MIL-кода (Model Intermediate Language, промежуточный язык описания моделей для чипов Apple) прямо в системе, отфильтровать пригодные для ANE, собрать билдер на Rust и запустить модель Qwen3-0.6B целиком на нейронном движке, без GPU.

Почему это важно

Apple не публикует спецификацию ANE для разработчиков, и до сих пор все проекты ссылались на одно и то же исследование Maderix Claude. Теперь появился воспроизводимый путь: 163 файла с валидным MIL-кодом лежат в самой macOS, а готовый билдер для Qwen экономит недели обратного инжиниринга компилятора.

Автор материала продолжает серию по реверс-инжинирингу Apple Neural Engine. Предыдущие части описывали обёртку на Rust для сборки и запуска MIL. В этой части разобраны конкретные паттерны кода, ограничения ANE и рабочий пайплайн от поиска примеров до загрузки весов модели Qwen3-0.6B.

Что понадобится

  • Mac с чипом Apple Silicon (M1 и новее) и установленной macOS
  • Rust и Cargo (для сборки билдера и утилиты ane-bridge)
  • Терминал с доступом к /System/Library
  • Крейт half для работы с форматами fp16/bf16 в Rust
  • Библиотеки memmap2 и safetensors для потоковой загрузки весов
  • Модель Qwen3-0.6B (веса в формате safetensors с Hugging Face)
  • Примерно 2 часа на первый прогон, включая компиляцию и отладку

Как найти MIL-примеры и собрать билдер: пошаговая инструкция

  1. Найдите все MIL-файлы в системе. Откройте терминал и выполните:
find /System/Library -name '*.mil' -type f

Команда вернёт около 163 файлов (число зависит от версии macOS). Это валидный CoreML MIL-код, который Apple использует в собственных приложениях. Не все файлы скомпилируются под ANE, но это лучший набор примеров, доступный без NDA.

  1. Изучите ключевые паттерны в найденных файлах. Обратите внимание на четыре вещи:

  2. Динамические формы (dynamic shapes): работают через аннотацию FlexibleShapeInformation, которая содержит DefaultShapes и EnumeratedShapes. Диапазонные размеры (RangeDims) ANE не поддерживает

  3. Новые типы данных: tuple, list, dict для структур, а также pixel_buffer, tensor_buffer и state для данных
  4. Набор операций (operation set): полный список того, что ANE умеет делать с тензорами, с примерами валидных аргументов
  5. Мультифункциональные ядра (multi-function kernels): функция внутри MIL может называться как угодно, main не обязательна, и в одном файле допускается несколько функций

  6. Автоматизируйте проверку файлов. Проверять 163 файла вручную бессмысленно. Используйте утилиту ane-compile (пример из крейта ane-bridge): она принимает путь к MIL-файлу, сама раскладывает файлы с весами (blobfile) по временным директориям и патчит пути с /../. Запуск:

find /System/Library -name '*.mil' -type f -exec ane-compile {} \;
  1. Отсейте неподдерживаемое. ANE не может выполнить несколько категорий операций. Ни в одном файле, успешно собранном под Apple Neural Engine, нет:

  2. scatter*, slice_update: собрать тензор из оригинала и обновлённой части стандартным способом не получится

  3. write_state, read_state: модели с состоянием (stateful) на ANE не запускаются
  4. RangeDims: только EnumeratedShapes для динамических размеров

Это значит, что обновление KV-кэша (структура, где модель хранит промежуточные результаты при генерации текста) в чистом ANE невозможно напрямую. Задача сложнее, чем кажется на старте.

  1. Соберите билдер вместо ручного написания MIL. Компилятор ANE придирчив, подсветки синтаксиса нет, автодополнения нет. Билдер на Rust решает проблему: каждая операция дописывается в конец программы, предыдущие можно ссылать по имени. Пример кода билдера для финального слоя Qwen:
let program = ProgramBuilder::new()
    .build_info(HashMap::from([
        ("ane_fn_name".to_owned(), "qwen_out".to_owned())
    ]))
    .func("qwen_out_b1")
    .input("w_model_norm", TensorType::new(TensorDtype::Fp16, &[hidden_size])?)
    .input("w_lm_head", TensorType::new(TensorDtype::Fp16, &[self.config.vocab_size, hidden_size])?)
    .input("i_hidden", TensorType::new(TensorDtype::Fp16, &[hidden_size])?)
    .rms_norm("i_x_norm", "i_hidden", "w_model_norm", rms_eps, 0, nwp1)?
    .matmul("logits", "i_x_norm", "w_lm_head", false, true)?
    .done(["logits"])
    .done();

Kernel::compile("qwen_out", &self.bridge, &program.mil(), &[])?
  1. Разберитесь с индексами буферов. Компилятор ANE не сохраняет порядок объявленных входов и выходов: что-то сортирует по алфавиту, что-то по размеру. Решение: у загруженной ANEModel вызовите modelAttributes, она вернёт структуру со всеми номерами программ, идентификаторами буферов, соответствующими названиями и размерами. Напишите парсер, после чего передавайте и получайте данные по имени.

  2. Загрузите веса модели. ANE считает только в fp16 (формат чисел с плавающей точкой половинной точности). На вход можно подать fp32 или int8, но тогда конвертация произойдёт внутри ANE. Формат bf16, в котором распространяется большинство моделей на Hugging Face, ANE не поддерживает. Для конвертации bf16 в fp16 используйте крейт half. Для загрузки весов: memmap2 плюс safetensors, подключите rayon для параллельной обработки. Проверку на nan/inf в весах можно пропустить для ускорения.

  3. Запустите первую модель. Автор начал с Qwen3-0.6B: модель компактная, математика простая, референсная реализация на numr была написана за час.

Что получается на практике

На входе: команда find /System/Library -name '*.mil' -type f на Mac с Apple Silicon. На выходе: 163 файла с валидным MIL-кодом. После фильтрации через ane-compile остаются только те, что компилируются под ANE. Билдер на Rust принимает спецификацию модели Qwen3-0.6B, генерирует корректный MIL, компилирует его через ane-bridge и запускает инференс (исполнение модели, генерация ответа) целиком на нейронном движке. Веса подгружаются из safetensors с конвертацией bf16 в fp16 на лету, без промежуточных копий в памяти.

Частые ошибки
  • Путать CoreML MIL и ANE MIL. Найденные 163 файла валидны как CoreML MIL, но не все скомпилируются под Apple Neural Engine. Фильтрация обязательна.
  • Использовать scatter* или write_state. Эти операции не работают на ANE. Если ваша модель обновляет KV-кэш через них, придётся искать обходной путь.
  • Подавать веса в bf16 напрямую. ANE не понимает этот формат. Конвертируйте в fp16 до загрузки, иначе получите ошибку компиляции или мусор на выходе.
  • Хардкодить индексы буферов. Компилятор переставляет их произвольно. Всегда парсите modelAttributes и обращайтесь к буферам по имени.
  • Игнорировать пути с /../ в системных MIL. Некоторые файлы ссылаются на blobfile уровнем выше. Без патчинга путей компиляция упадёт.

Кому это пригодится и что делать прямо сейчас?

Разработчику на Swift/Rust, который хочет запускать LLM (большую языковую модель) локально на Mac без зависимости от GPU: билдер и утилита ane-compile дают рабочий пайплайн от MIL до инференса.

Автору на Дзене или контент-маркетологу: пока Apple Neural Engine остаётся инструментом для разработчиков, но понимание того, что Mac может исполнять модели без GPU, полезно при выборе железа. Если вы запускаете локальные модели для генерации текстов, следите за развитием ANE-совместимых проектов.

Предпринимателю в РФ: устройства Apple доступны, чипы M1-M4 содержат ANE. Локальный инференс без облака означает, что чувствительные данные не покидают устройство. Для задач, где конфиденциальность критична, это может быть аргументом.

В России доступных аналогов ANE-пайплайна нет: YandexGPT и GigaChat работают в облаке. Локальный запуск моделей на российском рынке чаще делают через llama.cpp на CPU или GPU.

Мнение редакции dzen.guru

Автор материала проделал работу, которую Apple, судя по отсутствию публичной документации, делать для сторонних разработчиков не планирует. 163 системных MIL-файла и список того, что ANE точно не умеет, это практический результат, который экономит недели экспериментов.

По моим наблюдениям, интерес к локальному запуску моделей растёт: люди не хотят зависеть от облака и платить за каждый запрос. ANE даёт Mac с чипом Apple Silicon дополнительный вычислительный ресурс, который сейчас почти не используется сторонними приложениями.

Честная оговорка: путь от «Qwen3-0.6B работает на ANE» до полноценного чат-бота с KV-кэшем длинный. Ограничения на write_state и scatter означают, что для авторегрессивной генерации (когда модель выдаёт текст слово за словом) нужны обходные решения, которых пока нет в открытом доступе.

Если вы работаете с моделями на Mac, начните с команды find /System/Library -name '*.mil' -type f и посмотрите, что Apple уже положила в вашу систему. Это самый быстрый способ понять, на что способен Apple Neural Engine, без ожидания документации, которая, возможно, никогда не выйдет.

Поделиться:TelegramVK
Игорь Градов
Игорь Градов

Основатель dzen.guru. Эксперт по монетизации и продвижению на Дзен. Автор курса «Старт на Дзен 2026».

Комментарии

Читайте также

Google Gemini занизил запасы воды и еды: троих туристов пришлось спасать на горе Шаста
ai

Google Gemini занизил запасы воды и еды: троих туристов пришлось спасать на горе Шаста

Три туриста попали в беду на горе Шаста в Калифорнии после того, как полностью доверили планирование восхождения чат-боту Google Gemini, и этот случай стал…

5 мин
Perplexity AI обошлась без отдельного движка встраиваний: три сервиса на одном GPU
ai

Perplexity AI обошлась без отдельного движка встраиваний: три сервиса на одном GPU

Perplexity AI нейросеть использует для поиска три внутренних сервиса, Ivy, Tulip и ROSE, которые превращают один движок для больших языковых моделей в быструю…

7 мин
Hermes Desktop запускает локальные модели нейросети в один клик: настройка не нужна
ai

Hermes Desktop запускает локальные модели нейросети в один клик: настройка не нужна

Hermes Desktop от Nous Research читает характеристики компьютера, сама выбирает подходящую открытую модель нейросети и настраивает запуск без единой ручной…

5 мин