examples/ is based on KasperskyLab/knp at 55470ed6 with local changes to the mnist-learn altai/blifat models, cuda-backend CMake and model_loader. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
8.9 KiB
Markdown
100 lines
8.9 KiB
Markdown
# Отчёт: модель altai на MNIST
|
||
|
||
Oct 12, 2026
|
||
|
||
Модель `altai` заметно лучше `blifat`: на полном MNIST без правок она даёт 73,3% верных ответов против 30,9%, а с порогом, подобранным на отдельной валидационной выборке, — 82,5%.
|
||
|
||
## Что это
|
||
|
||
В примере `mnist-learn` две модели с одинаковой архитектурой: `blifat` (нейроны с вещественными параметрами) и `altai` (нейроны под чип «Алтай»). У `altai` все веса и пороги умножены на 1000, а перед проверкой сеть квантуется: веса и пороги сжимаются в целые числа в диапазоне ±255, как требует чип.
|
||
|
||
В прошлом отчёте выяснилось, что `blifat` теряет точность из-за порога, который застывает после обучения. Здесь проверено, есть ли та же проблема у `altai`.
|
||
|
||
## Результаты
|
||
|
||
Все прогоны на одних и тех же 10 000 тестовых картинках, однопоточный CPU-бэкенд. Порог для `altai` выбран на валидационной выборке (обучающие картинки 50 000–59 999), тестовые картинки в подборе не участвовали.
|
||
|
||
| Обучение | blifat как есть | altai как есть | altai, `act=40`, без добавки к порогу |
|
||
| --- | --- | --- | --- |
|
||
| 3 000 | 49,5% | 76,2% | **84,2%** |
|
||
| 30 000 | 42,0% | 75,6% | **84,1%** |
|
||
| 60 000 | 30,9% | 73,3% | **82,5%** |
|
||
|
||
Подробнее по `altai` (верно / ошибки / молчание):
|
||
|
||
| Обучение | Как есть | С подобранным порогом | Время прогона |
|
||
| --- | --- | --- | --- |
|
||
| 3 000 | 7622 / 1545 / 833 | 8418 / 1521 / 61 | 1–3,5 мин |
|
||
| 30 000 | 7563 / 787 / 1650 | 8409 / 1068 / 523 | 5,5–7 мин |
|
||
| 60 000 | 7326 / 790 / 1884 | 8247 / 1235 / 518 | 14 мин |
|
||
|
||
- Почти весь выигрыш даёт ответ на картинки, на которые сеть раньше молчала: на полном MNIST молчаний стало 518 вместо 1884.
|
||
- Для сравнения: `blifat` с подобранным порогом давал 75,5%, но тот порог подбирался прямо на тесте, так что оценка была оптимистичной.
|
||
|
||
### Полный MNIST, altai с порогом `act=40`: результаты по цифрам
|
||
|
||
| Цифра | Верно | Не отвечено | Ложные срабатывания | Precision | Recall |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| 0 | 825 | 63 | 92 | 0,900 | 0,929 |
|
||
| 1 | 1062 | 2 | 71 | 0,937 | 0,998 |
|
||
| 2 | 674 | 127 | 231 | 0,745 | 0,841 |
|
||
| 3 | 699 | 142 | 169 | 0,805 | 0,831 |
|
||
| 4 | 754 | 27 | 201 | 0,790 | 0,965 |
|
||
| 5 | 718 | 34 | 140 | 0,837 | 0,955 |
|
||
| 6 | 881 | 22 | 55 | 0,941 | 0,976 |
|
||
| 7 | 913 | 31 | 84 | 0,916 | 0,967 |
|
||
| 8 | 856 | 47 | 71 | 0,923 | 0,948 |
|
||
| 9 | 865 | 23 | 121 | 0,877 | 0,974 |
|
||
| **Итого** | **8247 (82,5%)** | **518** | **1235** | | |
|
||
|
||
Самые слабые цифры — 2 и 3 (их чаще всего путают), самые надёжные — 1 и 6.
|
||
|
||
## Что выяснилось
|
||
|
||
- **Почему altai лучше.** У `blifat` потенциал теряет треть за каждый шаг, и нейрон фактически видит только последние 2–3 шага картинки. У `altai` утечки нет (`potential_leak = 0`): нейрон суммирует все 10 шагов, то есть сравнивает с шаблоном всю картинку целиком.
|
||
- **Проблема с порогом та же.** Порог входного нейрона — это основная часть плюс добавка, пропорциональная сумме положительных весов. Добавка растёт с длиной обучения (до квантования 1797 → 3008 → 3342 для 3k → 30k → 60k) и застывает на проверке. Поэтому и `altai` теряет точность при более длинном обучении.
|
||
- **Квантование почти ничего не стоит.** После него веса становятся целыми от −6 до +2, и 37–60% из них нули. Но без квантования точность 76,8% против 76,2% (3 000 картинок). Вариант, где веса растягиваются на весь диапазон ±255, а порог масштабируется тем же множителем, дал 76,7%.
|
||
- **Потенциал переносится между картинками.** Между картинками он не сбрасывается, и недобранный заряд переходит на следующую картинку. Сброс в офлайн-симуляции помогал только при высоком пороге; при подобранном пороге выигрыша нет, поэтому в сеть я его не добавлял.
|
||
- **Лучший порог не зависит от длины обучения.** На валидации плато при `act` от 20 до 60 и для 3k, и для 30k; выбран `act=40` для всех.
|
||
- **Altai воспроизводим.** Повторные прогоны совпали до картинки (на 30k и 60k), коллапса весов, как у одного прогона `blifat`, не было.
|
||
- **Колонки из 20 нейронов и у altai работают как один нейрон**: веса внутри колонки идентичны.
|
||
|
||
## Как проверял
|
||
|
||
1. Добавил в пример `altai` выгрузку весов и порогов входного слоя до и после квантования.
|
||
2. Написал на numpy офлайн-симулятор нейрона AltAI по формулам бэкенда (без утечки, сброс в 0 при спайке, обнуление отрицательного потенциала, округление). Он совпадает с KNP до картинки: например, 8418 / 1521 / 61 и в KNP, и в симуляторе.
|
||
3. На симуляторе перебрал пороги, утечку и сброс между картинками на валидационной выборке.
|
||
4. Выбранный вариант подтвердил полными прогонами в KNP; все цифры в таблицах результатов — из KNP.
|
||
|
||
## Что изменено
|
||
|
||
В `examples/mnist-learn/models/altai/prepare_network_for_inference.cpp` добавлены переменные окружения. Без них пример работает как раньше; изменение видно в `git diff`, его можно откатить.
|
||
|
||
| Переменная | Что делает |
|
||
| --- | --- |
|
||
| `KNP_MNIST_THR` | заменяет порог входных нейронов на проверке (в единицах после квантования) |
|
||
| `KNP_MNIST_ADD_THR_SCALE` | умножает добавку к порогу входных нейронов на проверке (0 — убрать) |
|
||
| `KNP_MNIST_QUANT` | `none` — без квантования, `weights` — масштаб только по весам |
|
||
| `KNP_MNIST_DUMP=<папка>` | сохраняет веса и пороги до (`float_*.csv`) и после (`quant_*.csv`) квантования |
|
||
|
||
## Как запускать
|
||
|
||
```bash
|
||
cd ~/run/exp
|
||
# лучший вариант для полного MNIST
|
||
MODEL=altai ./run.sh myrun 60000 KNP_MNIST_THR=40 KNP_MNIST_ADD_THR_SCALE=0
|
||
cat myrun/result.csv
|
||
```
|
||
|
||
| Путь | Что внутри |
|
||
| --- | --- |
|
||
| `~/run/exp/tr<N>.bin`, `tr<N>.target` | N обучающих картинок + одни и те же 10 000 тестовых |
|
||
| `~/run/exp/val<N>.bin`, `val<N>.target` | N обучающих картинок + валидация (картинки 50 000–59 999) |
|
||
| `~/run/exp/run.sh` | запуск: `MODEL=altai run.sh <имя> <N> [ПЕРЕМЕННАЯ=значение]` |
|
||
| `~/run/exp/altai*/` | результаты прогонов altai и выгрузка весов |
|
||
|
||
## Следующие шаги
|
||
|
||
- [ ] Исправить порог в самом обучении, а не только на проверке
|
||
- [ ] Использовать колонки по-настоящему: развести 20 нейронов колонки, чтобы они учили разные варианты написания цифры
|
||
- [ ] Запустить altai на GPU, когда заработает GPU-бэкенд
|