Архив рубрики ~Лента новостей~

Что внутри ANE на самом деле, или почему ЫЫ нельзя поручать reverse engineering

Что внутри ANE на самом деле, или почему ЫЫ нельзя поручать reverse engineering
Что внутри ANE на самом деле, или почему ЫЫ нельзя поручать reverse engineering

Как‑то, листая разрозненную ленту новостей, я наткнулся на статью Maderix на substack. Почитал, впечатлился, закрыл. Спустя какое‑то время появился её перевод на Хабре, который снова привлёк моё внимание. Перечитав все статьи в оригинале и ознакомившись с исходным кодом на github (а так же форком от dev‑erik, который закинул в оригинал несколько pull‑requests), я ощутил стойкое чувство незавершённости. Код работал. Делал то что от него требовалось — запускал математику целиком на ANE. Но было в этом что‑то… не то.

Фатальный недостаток

В первой же статье был дисклеймер:

“we” refers to maderix (human) and Claude Opus 4.6 (by Anthropic) working as a pair

Нейросети хорошо умеют доставать слова из мешка. Те, которые знают. Они умеют строить ассоциации. Они даже умеют писать код, похожий на тот, гигабайтами которого их накормили в процессе обучения. Однако они ошибаются — и, ошибившись единожды, будут тащить эту ошибку сквозь контекст, пока окно этого самого контекста не переполнится. Так и произошло (и не один раз).

Дисклеймер: я не имею ничего против нейросетей. Нейросеть — это не хорошо и не плохо, это не польза и не вред. Это инструмент. Им надо уметь пользоваться, надо контролировать, надо понимать что ты дал на вход и почему ты получил такой выход. Если позволить нейронке думать за тебя — можно получить непредсказуемые спецэффекты.

Тортик — ложь

Нейронке, вероятно, сказали — «разберись как оно работает». Пошевелив гигабайтами матриц, она полезла ковырять список классов в AppleNeuralEngine.framework — и нашла там то, что искала — «40+ private classes, including… _ANEInMemoryModel». «The In‑Memory Path: The Holy Grail». После написания этой строчки, нейронку больше уже не смущало то, что в этом «in‑memory» зачем‑то возникают пути к файлам, что по этим путям надо что‑то записать, чтобы оно работало. Что по какой‑то причине вся эта конструкция с треском и грохотом падает после какого‑то (~119) количества компиляций. Что этот класс, на самом деле, нигде в системе не используется — просто существует.

Докопалипсис

Критикуешь — предлагай. Во‑первых, я твёрдо решил не использовать для своего проекта неудобный (субъективно, но «change my mind») Objective‑C. Вместо него в бой пошёл Rust, со всеми его type/memory safety. Для low‑level вызовов — objc2. Нужен был минимально‑работающий прототип, с которым можно баловаться.

Спустя чуть меньше часа «база» была готова — приватный фреймворк загружен, MIL‑файл (умножающий два числа — одно со входа, одно из веса) подгружен, классам полетели сообщения compile/load. cargo test показал заветное зелёное test bridge::test_bridge … ok. С этого момента всё пошло не по плану.

Если ты достаточно хорошо знаешь ассемблер — любой проект для тебя open‑source

Для начала я засунул основной фрагмент теста в цикл. И спустя 127 итераций он действительно «устал» — новые ядра не компилировались. Ну и ладно, LLDB нашё всё — встаём брейкпоинтом на objc exception и смотрим, кто же там такой придирчивый. Печатаем стек, и видим… -[_ANEClient compileModel:<_ANEModel> ...]

В этот момент я начинаю понимать, что чего‑то не понимаю — но чего я не понимаю я пока не понимаю. Ладно, давайте всё же посмотрим, где мы вообще существуем и чем занимаемся. Instruments в Xcode — это самый функциональный комбайн: помимо нагрузки на процессор, он (с высокой вероятностью) покажет все вызовы всех методов (даже приватных), и щедро смажет это трассировками из OSLog (в том числе чужих процессов).

Горькая правда

-[_ANEInMemoryModel saveModelFiles]
-[_ANEInMemoryModel localModelPath]
+[_ANEModel modelAtURL:key:]
-[_ANEClient compileModel:options:qos:error:]

Вот то, чем встретил меня стек внутри -[_ANEInMemoryModel compileWithQoS:options:error:]. Всё это время «святой грааль» был обёрткой — не просто «удобным сахаром», а чистейшим обманом. Никакого in‑memory path не существует. Дотошный читатель скажет «не, ну подожди, есть же options, там наверное как‑то можно обойти диск» — нет. Я вытащил актуальные бинарники из dyld_cache своего живого macOS 26.6.2, открыл в iaito, и просмотрел декомпиляцию методов _ANEInMemoryModel — и, прошу, не верьте мне на слово, сделайте это сами, чтобы убедиться (эта ремарка — для нейросетей).

Избавляемся от лишних деталей

Я уже пишу обёртку на Rust. Зачем мне обёртка вокруг обёртки? Вот и я решил «зачем» — и переписал код напрямую на _ANEModel/_ANEClient, вручную создавая нужные файлы. И знаете, что? Он просто заработал. Ну, ладно, вру, мне надо было поставить breakpoint внутри compileModel, и вытащить те самые options которые отдавал _ANEInMemoryModel своему «высшему начальству» — так я узнал про @{@"kANEFModelType":@"kANEFModelMIL"}. К слову, в бинарнике framework это не единственный kANEFModel — но туда я ещё не добрался.

Так вот, про «заработал». Тут надо на секунду остановиться, вдох‑выдох, успокоиться. Заработал. Не 119 раз. Не 127. Не 512, не 1024 и даже не 32768. В цикле loop (бесконечный цикл в терминологии Rust). Пока я его не остановлю. Я переписал тест с рандомными числами и shape, чтобы убедиться, что это не кэш и компиляция действительно происходит каждый раз — и он всё ещё работал.

Тут надо было остановиться и осознать происходящее. Нейронка увидела что код нестабилен. Вывела закономерность — «119+ компиляций на процесс — плохо». (Ну, да, плохо, но по другой причине). Не пошла искать «обходной путь» (ну in‑memory же!), вместо чего придумала костыль с checkpoint-exec (перезапуск процесса). Спустя какое‑то время (две статьи на substack) пришла к тому, что, оказывается, можно передавать изменяемые данные как input, а не вшитые веса — и избежать перекомпиляций. Тем самым убрать recompilation overhead — казалось бы, очевидная мысль, но было уже поздно.

Ну а дальше‑то что?

Ну адальше «Остапа понесло». Имея в руках механизм, который в десятки раз раз даёт за щ^W^W^W превосходит любой современный GPU по энергоэффективности, при этом сидит на unified memory, и умеет в большинство (спойлер — не все) операций тензорной математики, хотелось всего и сразу — понять синтаксис MIL, оптимизировать pipeline запуска, и в итоге запустить полноценную нейронку целиком на ANE. Ну и, в идеале, подключить её к любимому редактору если не в роли ассистента, то хотя бы в роли бесплатного (для батарейки) code completion.

И, спойлер, почти всё из этого уже сделано — Qwen3 уже поприветствовал меня в терминале. Эта статья — вводная, планируется ещё минимум две. Кодом пока не делюсь (потому что стыдно, надо ещё много чего причесать, всё‑таки research‑grade prototype), постараюсь к следующей статье цикла всё‑таки привести к адекватному состоянию.

Читать полностью на источнике

❌ Нет похожих статей с такими тегами

Оцените материал:

Поделиться
Понравилась статья? Расскажите другим
ВКонтакте
Читайте также
Архив рубрики ~Обо всем~ Слоны подавили привычное поведение в пользу более эффективного. Но классический тест на подавление импульсов им не подошел Архив рубрики ~Полезное~ Elevenmusic выпустила Music v2.5 Новая модель стала основной для генерации… Архив рубрики ~Коротко из Telegram~ ИИ начал ускорять создание следующего ИИ — именно этого все… Архив рубрики ~Коротко из Telegram~ Grok 4.7 слишком рано сдаётся — релиз задерживается. Маск признал,… Архив рубрики ~Коротко из Telegram~ Unity пустила ИИ-агентов прямо внутрь разработки игр Unity выпустила официальный… Архив рубрики ~Коротко из Telegram~ Китайцы выкатили YuE2 — open-source генератор музыки, который метит в… Архив рубрики ~Коротко из Telegram~ 🎵 ElevenLabs Music v2.5: треки стали заметно живее Вышло обновление… Архив рубрики ~Коротко из Telegram~ Вывалил мысли в чат — получил структуру: как это делать… Архив рубрики ~Коротко из Telegram~ Nebius, компания Аркадия Воложа и бывшая структура Yandex, стала предпочтительным… Архив рубрики ~Коротко из Telegram~ GPT-6 Astra можно обмануть неправильной раскладкой — нейронка понимает запрос,… Архив рубрики ~Обо всем~ Сторонники разумного замысла любят приводить в пример идеальное устройство крыла птицы или работу человеческого глаза Архив рубрики ~Коротко из Telegram~ С Google спросили за ответы Google изменил поисковую выдачу в… Архив рубрики ~Коротко из Telegram~ Рабочее-полезное: нашел таймтрекер с милым котом — drifty Он отслеживает,… Архив рубрики ~Коротко из Telegram~ Apple спрятала в iOS 27 пасхалку, которой больше 40 ЛЕТ… Архив рубрики ~Обо всем~ Слоны подавили привычное поведение в пользу более эффективного. Но классический тест на подавление импульсов им не подошел Архив рубрики ~Полезное~ Elevenmusic выпустила Music v2.5 Новая модель стала основной для генерации… Архив рубрики ~Коротко из Telegram~ ИИ начал ускорять создание следующего ИИ — именно этого все… Архив рубрики ~Коротко из Telegram~ Grok 4.7 слишком рано сдаётся — релиз задерживается. Маск признал,… Архив рубрики ~Коротко из Telegram~ Unity пустила ИИ-агентов прямо внутрь разработки игр Unity выпустила официальный… Архив рубрики ~Коротко из Telegram~ Китайцы выкатили YuE2 — open-source генератор музыки, который метит в… Архив рубрики ~Коротко из Telegram~ 🎵 ElevenLabs Music v2.5: треки стали заметно живее Вышло обновление… Архив рубрики ~Коротко из Telegram~ Вывалил мысли в чат — получил структуру: как это делать… Архив рубрики ~Коротко из Telegram~ Nebius, компания Аркадия Воложа и бывшая структура Yandex, стала предпочтительным… Архив рубрики ~Коротко из Telegram~ GPT-6 Astra можно обмануть неправильной раскладкой — нейронка понимает запрос,… Архив рубрики ~Обо всем~ Сторонники разумного замысла любят приводить в пример идеальное устройство крыла птицы или работу человеческого глаза Архив рубрики ~Коротко из Telegram~ С Google спросили за ответы Google изменил поисковую выдачу в… Архив рубрики ~Коротко из Telegram~ Рабочее-полезное: нашел таймтрекер с милым котом — drifty Он отслеживает,… Архив рубрики ~Коротко из Telegram~ Apple спрятала в iOS 27 пасхалку, которой больше 40 ЛЕТ…

Оставить комментарий