Нейросети CIFAR на Cortex-M0+ теряют до 40% точности: пять багов и их исправления
Нейросети на микроконтроллерах ARM Cortex-M0+ теряют от 30 до 40 процентов точности из-за багов квантизации и особенностей компилятора GCC, и в этом разборе собраны конкретные исправления, которые возвращают потерянное качество на датасетах вроде CIFAR-10.

Квантизация (сжатие весов модели из 32-битных чисел в 2-битные тернарные значения) позволяет запускать нейросети cifar на устройствах без математического сопроцессора, но скрытые баги обнуляют веса и ломают точность, причём ошибки проявляются только на целевом железе, а не в Python.
Автор проекта Fakeonomics опубликовал детальный разбор пяти архитектур нейросетей, которые он довёл до работы на ARM Cortex-M0+, микроконтроллере без аппаратной поддержки операций с плавающей точкой (FPU). Полный пайплайн замкнут: обучение в Python, экспорт, генерация кода на C11, компиляция через arm-gcc, запуск в эмуляторе Unicorn. 192 файла, 34 тысячи строк кода, 95 тестов. Три из пяти архитектур показали прирост точности после исправлений, две не взлетели по архитектурным причинам.
Что понадобится
- Среда для обучения моделей в Python (PyTorch или аналог)
- Компилятор arm-none-eabi-gcc для сборки под ARM Cortex-M0+
- Эмулятор Unicorn для прогона бинарников без реального железа
- Датасеты: MNIST, Fashion-MNIST или CIFAR-10
- Время: обучение одной модели занимает от 20 до 49 минут в зависимости от архитектуры и числа эпох
Пять багов, которые крадут точность, и как их чинить
- Проверьте таблицу тернарного маппинга. В кодогенераторе для свёрточных сетей (CNN) третий элемент таблицы
ternary_map[2]был равен нулю вместо +1. Это значит, что при распаковке весов из сжатого формата все значения +1 молча превращались в ноль, и модель работала с испорченными весами. Исправление: убедитесь, чтоternary_mapсодержит ровно три значения: -1, 0, +1.
// Было (баг):
const int8_t ternary_map[3] = {-1, 0, 0};
// Стало (исправлено):
const int8_t ternary_map[3] = {-1, 0, 1};
- Отключите встроенные функции GCC флагом
-fno-builtin. При оптимизации-O2компилятор GCC превращает циклwhile(n--)внутриmemsetв рекурсивный вызовbl memset. На Cortex-M0+ это приводит к бесконечному циклу и зависанию. Добавьте флаг при сборке:
arm-none-eabi-gcc -mcpu=cortex-m0plus -O2 -fno-builtin -o model.bin model.c
- Замените простое приведение типа на явное ограничение диапазона (saturation). Выражение
(int8_t)(acc >> 7)при переполнении даёт мусор. Нужна функцияsat_q7(), которая ограничивает значение диапазоном от -128 до 127 перед приведением кint8_t.
static inline int8_t sat_q7(int32_t val) {
if (val > 127) return 127;
if (val < -128) return -128;
return (int8_t)val;
}
-
Расширьте тип индекса выхода с
uint8доuint16. Если в модели больше 255 нейронов на выходном слое, индексы 834 и выше не помещаются в 8-битную переменную. Результат: неверная классификация, которая выглядит как «модель плохо обучилась», хотя виноват тип данных. -
Добавьте обучаемое масштабирование для Vision Transformer (ViT). Тернарные значения в проекциях Q, K, V (query, key, value, три проекции входных данных в механизме внимания) без нормализации дают дисперсию на порядки выше нормы. Функция softmax вырождается в «горячий» вектор, градиенты обнуляются, модель не учится. Решение: пять обучаемых параметров масштабирования.
self.log_scale_qk = nn.Parameter(torch.zeros(1))
self.log_scale_v = nn.Parameter(torch.zeros(1))
self.log_scale_o = nn.Parameter(torch.zeros(1))
self.log_scale1 = nn.Parameter(torch.zeros(1))
self.log_scale2 = nn.Parameter(torch.zeros(1))
Какие результаты дали исправления?
- GraphKAN на MNIST: после перехода на полный датасет (60 тысяч примеров вместо 10 тысяч) и исправления бага с
ternary_mapточность составила 94.46% за 20 эпох обучения с плавающей точкой плюс 5 эпох STE (Straight-Through Estimator, метод обратного распространения градиентов через дискретные значения) - Fashion-MNIST: с 76.6% до 86.73% при 30 эпохах плюс 10 эпох STE, полный датасет, 49 минут обучения
- CNN на Fashion-MNIST: аугментация данных (искусственное расширение обучающей выборки поворотами, сдвигами) плюс cosine annealing (плавное снижение скорости обучения по косинусоиде) дали 90.54% при сжатии модели в 16 раз. Тернарная версия не потеряла точность по сравнению с float, а выиграла 0.44 процентных пункта
- ViT на CIFAR-10: 60.30% при размере модели 25.4 КБ. Для микроконтроллера без FPU это рабочий результат, хотя и далёк от лучших показателей на полноценном оборудовании
- RNN и LSTM: не взлетели. 18.2% и 20.64% соответственно, при float на той же архитектуре около 25%. Причина не в тернарности, а в малом размере скрытого слоя: hidden_dim=64 не справляется с 28 шагами по пикселям, нужно 128 или 256, что увеличивает число параметров в 4 и 8 раз
Что делать с этим прямо сейчас?
Если вы разработчик встраиваемых систем: проверьте таблицу маппинга и тип индексов в первую очередь. Эти баги не ловятся юнит-тестами на стороне Python, только bit-exact прогон на эмуляторе или железе покажет проблему.
Если вы автор на Дзене и пишете про нейросети cifar или edge AI: этот кейс даёт конкретные цифры для контента: сжатие в 16 раз, модель в 25 КБ, точность 90% на Fashion-MNIST. Это понятные читателю числа, которые показывают, что ИИ работает не только в облаке.
Если вы предприниматель и думаете об ИИ на устройствах: тернарные модели помещаются в дешёвые микроконтроллеры ценой менее доллара. Но путь от обученной модели до рабочей прошивки требует именно такой ручной отладки, готовых коробочных решений пока нет.
Автор обучил свёрточную сеть на Fashion-MNIST по схеме 10+20+5+10 эпох. Первые 10 эпох обучение с аугментацией и высокой скоростью обучения. Следующие 20 эпох с cosine annealing. Затем 5 эпох квантизации через STE. Финальные 10 эпох тонкая подстройка тернарной модели. Результат: 90.54% точности, сжатие в 16 раз. При этом тернарная модель оказалась на 0.44 процентных пункта точнее, чем версия с плавающей точкой, что контринтуитивно, но объяснимо: квантизация выступила как регуляризатор (метод борьбы с переобучением).
Первая: проверять точность только в Python. Баг с ternary_map и переполнение sat_q7 проявляются только после компиляции и запуска C-кода. Без bit-exact сверки результатов Python и эмулятора вы не увидите потерю 30 и более процентов точности.
Вторая: использовать флаг оптимизации -O2 без -fno-builtin. На x86 это безвредно, на Cortex-M0+ приводит к зависанию через рекурсию в memset.
Третья: пытаться запустить RNN или LSTM с маленьким скрытым слоем на последовательных задачах. Проблема не в квантизации, а в том, что 64 нейрона недостаточно для 28 временных шагов. Увеличение до 128 или 256 решает задачу, но кратно раздувает модель.
Этот проект показывает реальную цену запуска ИИ на копеечном железе: не «скачал библиотеку и заработало», а 34 тысячи строк кода и ручная охота за багами, которые теряют точность молча. По моим наблюдениям, большинство туториалов по edge AI заканчиваются на этапе «экспортировали модель», а самое ценное начинается дальше. Честная оговорка: результаты получены на эмуляторе Unicorn, а не на реальном микроконтроллере. На железе могут появиться дополнительные проблемы с таймингами и памятью. Кроме того, ViT с 60% на CIFAR-10 пока далёк от практического применения, но сам факт, что трансформер влезает в 25 КБ и работает без FPU, заслуживает внимания.
Хотите разобраться в нейросетях глубже?
Подписывайтесь на канал dzen.guru, чтобы получать разборы технологий ИИ с конкретными цифрами и применимыми советами.
ПодписатьсяПуть от Python-модели до рабочей прошивки на Cortex-M0+ усеян ловушками, которые не описаны ни в одном стандартном туториале, и именно поэтому этот разбор ценен: он перечисляет грабли поимённо, с кодом и цифрами, а не обещает, что «всё заработает из коробки».

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

Минторг США обвинил ASML в утечке чипов в Китай, но не показал доказательств
Компания ASML (производитель литографического оборудования, без которого невозможно выпускать самые передовые чипы в мире) оказалась в центре конфликта с…

Midjourney строит сканер тела на 500 000 датчиков, а генератор картинок открыла бесплатно
Midjourney, компания, которую знают по генерации картинок, 4 июня 2025 года объявила о запуске медицинского сканера тела, работающего на ультразвуке и…

США обязали Anthropic Claude отозвать две модели: найден обход защиты
Правительство США на прошлой неделе обязало компанию Anthropic отозвать две новейшие модели, Claude by Anthropic, Fable 5 и Mythos 5, сославшись на угрозу…
Комментарии