Нейросети для чайников. Объясняет ChatGPT.
Эта статья сгенерирована нейросетью. В ней мы разберём другую нейросеть, которая обучается играть в Гомоку на доске 15×15. Мы будем использовать код на C++ с LibTorch, и ChatGPT объяснит нам каждый слой, каждый параметр и логику работы сети для тех, кто не сталкивался с нейронными сетями раньше.
Примечание. Поначалу код нашей нейронной сети был сгенерирован на Gemini. Однако позже мы перешли на разработку через ChatGPT. Изначально роль тут сыграла недостаточность просмотрового окна в Gemini. другими словами, в него нельзя передать слишком большой кусок кода (или какого-то другого текста), хотя бы 400-500 строк для анализа. ChatGPT сразу заняло проактивную позицию, критикуя существующую архитектуру и предлагая улучшения, многие из которых и были сделаны в последствии. Об этом можно почитать в последующих статьях. Забегая вперед, можно сказать что была проведена большая работа, анализу логов обучения, и исправлению всевозможных недочётов (да и откровенных багов) и улучшению логов с целью контроля за ходом прогресса обучения.
Что такое свёрточные нейронные сети (CNN)
Сверточные сети — это особый вид нейронных сетей, которые хорошо работают с изображениями и двумерными структурами, такими как доска в Гомоку. Главная идея:
- Свертка (Convolution): маленький фильтр (ядро) сканирует входные данные и выявляет локальные шаблоны, например ряд из трёх камней или диагонали. В нашем случае Фильтр 3×3 перемещается по доске. В каждой позиции он умножает свои веса на значения клеток и суммирует результат. Так получается одно число — выход одного нейрона. Размер выходного слоя остаётся 15×15, потому что padding=1 добавляет по одному ряду пустых клеток с кажого края, компенсируя ужимание от свёртки ядром 3×3.
- Нелинейность (Activation): после свёртки применяется функция активации
tanh, которая сжимает значения в диапазон от -1 до +1. Это важно, потому что оценки ходов в сети тоже лежат примерно в этом диапазоне. - Batch Normalization (BN): слой
BatchNorm2dнормализует выходные значения каждого канала. Это ускоряет обучение и делает его более стабильным. - Полносвязный слой (Linear): после свёрточных слоёв карты признаков разворачиваются в длинный вектор и передаются на линейный слой. Linear слой оценивает стратегическую ценность каждого хода на доске.
Понятия каналов, фильтров и карт признаков
- Каналы: каждый канал — это карта 15×15. Важно: канал — это НЕ один нейрон, а целая сетка из 225 нейронов.
- Фильтры: это маленькие матрицы весов (например, 3×3), которые обучаются находить локальные шаблоны.
- Карты признаков: результат применения одного фильтра ко всей доске. Один фильтр = один канал.
Подробное объяснение Conv2dOptions
torch::nn::Conv2d(torch::nn::Conv2dOptions(in_channels, out_channels, kernel_size).padding(p))
| Параметр | Значение | Назначение |
|---|---|---|
| in_channels | 1 → 64 → 64 → 128 | Сколько каналов приходит на вход |
| out_channels | 64 → 64 → 128 | Сколько фильтров (и каналов) создаётся |
| kernel_size | 3 | Размер фильтра 3×3 |
| padding | 1 | Сохраняет размер 15×15 |
Архитектура GomokuNet (старая)
Это старая, более простая архитектура. Проблема старой архитектуры была в большом Linear слое, а конкретнее, в большом количество входов этого слоя, для каждого из которых настраивается вес этого входа на каждый из 255 нейронов. Получается, что веса не распределены между слоями, а сконцентрированы в последнем, что отражает принцип "большой мешок весов".
Linear слой был поначалу заменён на 1x1 свертку в ветке neural, Но в последствии, мы перешли на alpha-zero подобную архитектуру, в которой нет такого слоя, но зато добавляется два новых: value head и policy head.
- Conv1: 1 → 64 каналов
- Conv2: 64 → 64
- Conv3: 64 → 128
- Linear: 28800 → 225
Сколько нейронов в каждом слое
- Conv1: 64 × 15×15 = 14400
- Conv2: 14400
- Conv3: 28800
- Linear: 225
Сколько входов у одного нейрона
- Conv1: 3×3×1 = 9 входов
- Conv2: 3×3×64 = 576 входов
- Conv3: 3×3×64 = 576 входов
- Linear: 28800 входов
Сколько параметров (весов) в сети
- Conv1: 64 × (3×3×1 + 1) = 640
- Conv2: 64 × (3×3×64 + 1) = 36928
- Conv3: 128 × (3×3×64 + 1) = 73856
- Linear: 28800 × 225 + 225 ≈ 6.48 млн
Вывод: почти все параметры сети находятся в Linear слое.
Почему Linear слой — узкое место
Linear слой имеет миллионы параметров. Это:
- замедляет обучение
- повышает риск переобучения
- игнорирует пространственную структуру доски
Как данные текут через слои
- Вход: 1×1×15×15
- Conv1 → BN → tanh
- Conv2 → BN → tanh
- Conv3 → BN → tanh
- Flatten → 28800
- Linear → 225
Почему каналы — это не нейроны
1 канал = 15×15 = 225 нейронов. Поэтому 64 канала = 14400 нейронов.
Почему 1 входной канал — это ограничение
Сейчас используется кодировка:
- 1 = свой камень
- -1 = чужой
Лучше использовать:
- канал 1: свои камни
- канал 2: чужие
Роль функции активации (tanh)
tanh ограничивает значения в [-1, 1], что хорошо совпадает с рейтингами ходов.
BatchNorm — что он делает
Нормализует каждый канал отдельно, чтобы значения не "разъезжались".
Интерпретация выходов сети
225 чисел — это оценки ходов, а не вероятности.
Как считается ошибка (Loss)
Используется MSE, но только для известных ходов (через mask).
Два режима обучения
- По всей позиции
- По одному ходу
Как сеть выбирает ход
Запрещённые клетки получают штраф, затем берётся argmax.
Как можно улучшить эту сеть (уровень AlphaZero)
- Несколько входных каналов
- Residual-блоки (ResNet)
- Убрать Linear слой
- Сделать отдельные головы:
- Policy (куда ходить)
- Value (кто выигрывает)
Схема сети с визуальными пояснениями
Итог
Сеть анализирует доску через свёртки, извлекает шаблоны и оценивает каждый ход. Основная сложность и сила модели — в том, как она преобразует локальные паттерны в глобальную стратегию.
