our_knp/reports/2026-10-12/Отчёт_altai.md
2026-10-15 10:48:29 +03:00

100 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Отчёт: модель 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-бэкенд