nesformer запускает процессор приставки NES внутри весов Qwen3.5

Репозиторий nesformer на GitHub показывает, как процессор 6502 приставки NES (ядро чипа 2A03), её 2 КБ рабочей памяти и программа с картриджа выполняются внутри обычного чекпойнта Qwen3_5ForCausalLM из семейства Qwen3.5. Веса никто не обучал: каждый из них вычислил компилятор. Во время игры модель токен за токеном предсказывает журнал выполнения процессора, а небольшая программа-хозяин (host) играет роль остальной приставки: рисует картинку, читает контроллер и запускает прерывание vblank (начало вертикального гашения).
Проект опирается на Qwenputer Дивьянша Агравала (Divyansh Agrawal), где в Qwen3.5-4B скомпилировали сначала CHIP-8, а затем процессор RISC-V. nesformer берёт оттуда компилятор и главный приём: памятью машины служит состояние Gated DeltaNet. Каждая голова DeltaNet хранит матрицу состояния 128 × 128, которую правило дельты обновляет на каждом токене. Если открыть затвор и использовать one-hot-ключ (вектор с одной единицей), обновление перезаписывает ровно одну строку матрицы, а one-hot-запрос читает её обратно. Так каждая строка становится ячейкой памяти, и картридж, ОЗУ и регистры живут в строках. Чекпойнт, обычная папка Hugging Face, которая загружается через Qwen3_5ForCausalLM.from_pretrained без кастомного кода; файл nesformer.json фиксирует, в каком слое и в какой голове лежит каждая часть машины.
Каждая инструкция превращается в запись, последний токен которой фиксирует её выполнение. Счётчик команд (PC) не записывается явно: финальный токен несёт длину инструкции, три счётчика DeltaNet считают инструкции каждой длины с последнего перехода, а PC равен адресу перехода плюс это смещение. Большинство инструкций занимают один токен; на реальном игровом коде выходит в среднем 1,1-1,3 токена на инструкцию. Хост видит регистры и ОЗУ только через этот журнал.
Скорость скромная. Движок по умолчанию (numba, пропуск нулевых блоков) выдавал около 1650 токенов/с на одном ядре CPU той машины, где проект собирали; движок на numpy, около 210, штатный transformers, около 10. Настоящей NES нужно около 700 000 токенов в секунду. Чтобы не тратить время, хост находит точно повторяющийся цикл ожидания vblank без записей в ОЗУ и ввод-вывод и перематывает часы к ближайшему событию PPU (графического процессора приставки): число токенов падает в 2,6-4,2 раза. В итоге nesformer работает в 150-290 раз медленнее настоящей консоли. Первый запуск тратит около 20 секунд на компиляцию движка, затем кадр занимает 1-6 секунд, и 600 кадров (10 секунд игрового времени) считаются около 25 минут.
Проверка. По README, на входящих в репозиторий тестовых играх каждый кадр совпадает с выводом обычного эмулятора 6502 точно. Эталонный процессор в Python совпадает с золотым журналом nestest на 3348 инструкциях и с эмулятором py65 на 5,7 млн инструкций игрового кода. Точная схема в вычислителе Qwenputer предсказывает каждый эталонный токен: весь nestest плюс 283 610 позиций загрузки двух игр. Чекпойнт в штатном transformers (bf16, CPU) предсказывает 2651 позицию nestest и Full Game без расхождений. Ещё один тест показывает, что пропуск холостых циклов не меняет видимого результата.
Ограничения. Поддерживаются только картриджи NROM (iNES mapper 0): процессор адресует 32 КБ ПЗУ, которые лежат в фиксированной таблице внутри модели, поэтому переключение банков (MMC1, MMC3) пока не отслеживается. Только официальные опкоды (неофициальный даёт HALT), код должен исполняться из ПЗУ картриджа, прерываний IRQ нет (BRK и NMI работают), PPU и APU в веса не входят, эффекты в середине строки не воспроизводятся, звука нет. ROM пользователь приносит сам: в репозитории лежат лишь три свободно лицензированных тестовых ROM (nestest, Full Game, Thwaite). Код выпущен под лицензией MIT, ROM сохраняют свои лицензии.
Ключевые факты
- Процессор 6502 приставки NES, её 2 КБ ОЗУ и ПЗУ картриджа скомпилированы в веса стандартной модели Qwen3.5 (Qwen3_5ForCausalLM); обучения нет, каждый вес вычислил компилятор.
- Память машины, состояние Gated DeltaNet: каждая строка матрицы 128 × 128 служит ячейкой памяти; проект развивает Qwenputer Дивьянша Агравала.
- По README, на тестовых играх каждый кадр точно совпадает с эмулятором 6502; эталонный процессор сверен с nestest (3348 инструкций) и py65 (5,7 млн инструкций).
- Работает в 150-290 раз медленнее настоящей консоли: кадр занимает 1-6 секунд, 600 кадров считаются около 25 минут.
- Только картриджи NROM (mapper 0), официальные опкоды, без звука и IRQ; ROM нужно приносить своё, код под лицензией MIT.
Почему это важно
Проект показывает, что обычную трансформерную модель можно превратить в точный вычислитель, не обучая её: веса получены компиляцией, а токены модели образуют журнал выполнения настоящего процессора. Для NES это продолжение линии Qwenputer, где так же собирали CHIP-8 и RISC-V. Практического применения у демонстрации нет: она в 150-290 раз медленнее консоли, но наглядно показывает, как состояние DeltaNet работает адресуемой памятью.
Кому это важно
Исследователям архитектур с линейным вниманием и DeltaNet, интересующимся тем, что такие слои могут вычислять в точности; энтузиастам эмуляции и ретрокомпьютинга; всем, кто изучает, как устроены веса модели изнутри. Для повседневной работы с нейросетями проект напрямую не нужен.
Как это применить
Нужен Python 3.11 или новее и пакеты numpy, scipy, numba, pillow. Распакуйте nesformer.zip и nesformer-weights.zip в одну папку (папка weights/ лежит рядом с пакетом nesformer/) и запустите, например, python -m nesformer run roms/thwaite.nes --frames 600 --show; по окончании сохранится GIF. Кнопки задаются параметром --buttons. Своя игра подходит, если она на плате NROM (в README упомянуты Super Mario Bros., Donkey Kong и Excitebike), ROM надо принести самому. Для запуска на штатном transformers нужны torch 2.6+ и transformers 5.22+ (флаг --engine hf), но он работает около 10 токенов/с. Код под MIT; тесты идут несколько минут и требуют pytest и py65.
Можно ли доверять
Источник, README самого репозитория, то есть утверждения автора проекта. Он описывает несколько уровней проверки: сверка с nestest и py65, проверка точной схемы и чекпойнта в transformers, а также тесты в репозитории, которые можно запустить самостоятельно. Совпадение кадров с эмулятором заявлено именно для входящих в репозиторий тестовых игр; о других играх README ничего не утверждает. Размер весов «~1 ГБ» из заголовка обсуждения на Hacker News в тексте README не подтверждён.
Риски и подводные камни
Это демонстрация, а не играбельный эмулятор: слишком медленно для реального времени. Ограничения серьёзные: только NROM без переключения банков, только официальные опкоды, нет IRQ, PPU и APU вне весов (PPU рисует по одной строке, эффекты в середине строки не воспроизводятся), нет звука; обращения к ОЗУ как к коду дают HALT. Игры с ROM нужно добывать самостоятельно, и их лицензии остаются за правообладателями; три тестовых ROM имеют свои лицензии, в том числе GPL-3.0 у Thwaite.
«Эти веса никто не обучал; каждый из них вычислил компилятор.»
— README репозитория nesformer