🗺️ План усиления value-модели: богатые фичи + Oracle
О чём это
Мы уже выжали, что могли, из поиска (2-ply expectimax, 🎓 2-ply Expectimax поверх value-модели): ~52% против
aggressive, балансируя на пороге. Следующий рычаг — сама оценка. Сейчас модель видит только материал (7 фич), потому что python-пайплайн не умеет генерировать ходы. План: считать богатые фичи в движке (единый источник и для обучения, и для игры), с честным учётом их стоимости на инференсе, и использовать под это грант Oracle ($300/30 дней) — на CPU, не на GPU.
Связанные: 🎓 2-ply Expectimax поверх value-модели · Что такое LightGBM · 03 Идеи по улучшению алгоритмов
1. Корень проблемы (напоминание)
dicechess-ev/features.py честно пишет в шапке: «features computable from FEN + dice alone. No move generator». Отсюда все фичи — материальные (MATERIAL_COLUMNS = 7) + состав костей (DICE_COLUMNS = 6). Модель не отличает две позиции с одинаковым материалом — мобильность, безопасность короля, угрозы для неё не существуют. Это и есть потолок: 1-ply ≡ greedy.
Позиционные фичи требуют генерации ходов. Генератор ходов есть только в движке (Scala, source of truth). Значит богатые фичи считаем там.
2. Железное правило: train == serve
Сейчас материальные фичи продублированы вручную в двух местах: features.py (Python, обучение) и OnnxFeatures.extract (Scala, инференс). Совпадают «по договорённости» — хрупко. С богатыми фичами дублировать формулы на двух языках — гарантированный источник train/serve-skew.
Единый экстрактор фич в движке
Фичи вычисляет один объект в движке (расширенный
OnnxFeatures/ новыйFeatureExtractor). Он используется:
- при обогащении обучающих данных (enrichment-шаг гоняет его по каждой строке CSV → фича-колонки);
- при инференсе в
OnnxEvalSearch/OnnxExpectimaxSearch.Python больше не считает эти фичи — он читает готовые колонки из обогащённого CSV. Совпадение train/serve гарантировано тем, что это буквально один и тот же Scala-код.
3. Какие фичи добавить — и чего они стоят
Ключевая тонкость, которую нельзя игнорировать: фича платится на каждом листе поиска. У 2-ply на ход ~360k листьев (K=8 × 56 бросков × сотни ответов). Фича в 1 мс × 360k = 6 минут на ход — нежизнеспособно. Поэтому фичи делятся по стоимости:
| Фича | Источник в движке | Стоимость | Где применима |
|---|---|---|---|
| материал (7, есть) | OnnxFeatures.extract | ~µs | везде |
| мобильность (число псевдо-легальных ходов / атакованных клеток) | MoveGenerator.generateMoves | ~µs–десятки µs | везде, в т.ч. листья 2-ply |
| king safety | Evaluator.evaluateKingSafety | ~µs | везде |
| P(захват короля) короля/ферзя, своя и соперника | KingCaptureProbability.{king,queen}CaptureProbability | ~мс (DFS по 216 броскам) | дорого для листьев; см. ниже |
Главная идея — распределение бюджета: богатая оценка vs глубокий поиск
KingCaptureProbability— почти идеальный предиктор в dice chess (условие победы = захват короля; фича прямо кодирует «насколько я близок к потере короля», интегрируя по будущему броску соперника). Но она дорогая. Отсюда два взаимоисключающих режима на одну и ту же модель:
- 1-ply + дорогие фичи (KCP): сотни оценок на ход × мс = сотни мс/ход — приемлемо. KCP даёт зрение, ради которого мы городили lookahead, но статически и дёшево по числу вызовов.
- 2-ply + только дешёвые фичи (мобильность, king-safety): сотни тысяч листьев × µs — тоже приемлемо.
Самый интересный эксперимент: 1-ply+KCP против 2-ply+материал. Гипотеза — 1-ply с KCP догоняет или обгоняет 2-ply на материале, будучи проще. Это прямой замер «где компуют полезнее: в оценке или в глубине».
На обучении стоимость не проблема: KCP × 1.3M строк один раз (часы) — ровно то, что параллелится на Oracle CPU (см. §5).
4. Архитектура пайплайна
graph LR DB[(prod DB<br/>dexus)] -->|"ExportTrainingDataApp<br/>(как сейчас)"| RAW["raw CSV<br/>fen, dice, result…"] RAW -->|"enrichment (Scala, движок)<br/>FeatureExtractor по строкам"| RICH["enriched CSV<br/>+ mobility, king-safety, KCP…"] RICH -->|"features.py читает колонки"| TRAIN["LightGBM train<br/>(dicechess-ev)"] TRAIN --> MODEL["oracle-N.onnx"] MODEL -->|"тот же FeatureExtractor на инференсе"| BOT["OnnxEvalSearch /<br/>OnnxExpectimaxSearch"]
Enrichment вынесен отдельным шагом на CSV (не внутрь экспортёра), чтобы CPU-тяжёлую часть отвязать от хоста БД (dexus тесен по RAM) и гонять где угодно — в т.ч. на Oracle. Вход/выход — файл, зависимость — движок (JVM). Место: раннер в dicechess-analytics (уже зависит от движка) или маленький модуль движка.
5. Как использовать Oracle ($300 / 30 дней) — CPU, не GPU
Пошаговый how-to
Провижнинг, bootstrap и запуск — в отдельном раннбуке: Oracle Cloud — раннбук. Ниже — только зачем и что.
GPU нам не нужен (и, вероятно, недоступен)
LightGBM на табличных фичах учится за ~15 с на CPU; данных (~79k независимых партий) хватает только на маленькую модель, которая и на CPU быстра. GPU не поднимает качество — только скорость итераций, которой у нас и так довольно. Плюс SR на GPU-лимит ранее отклонили → скорее всего доступен только CPU. Это удачно совпадает с тем, что вся тяжёлая работа тут — CPU-bound.
Три CPU-задачи под грант:
- Обогащение 1.3M строк фичами (особенно KCP): embarrassingly parallel
mapпо строкам. На многоядерном инстансе — минуты-часы вместо суток на homelab. - Честные большие арены: сначала засеять
Randomбота в арене (сейчасfindBestMove(state)→new Random(), из-за чего гейт шумит ±4 п.п.), затем гонять тысячи партий по вариантам (набор фич × 1-ply/2-ply × K) параллельно. $300 CPU = очень много арена-часов. - Свипы гиперпараметров LightGBM параллельно.
Шейпы (ориентир): Free Tier VM.Standard.A1.Flex = 4 OCPU / 24 ГБ (always-free) — уже годится. PAYG под 0.01/OCPU-ч (напр. 64 OCPU × неделя ≈ 0.03/vCPU-ч. Хватает с запасом; можно держать живой инстанс на оба дня хакатона под демо.
6. Порядок работ и метрики успеха
Метрик две (модель нужна и для бота, и для grading в analytics-UI): сила (win-rate в арене) и калибровка/AUC (для оценки ходов игроков).
- Починить сид арены — иначе нечем честно мерить. Мелкий фикс в
OnnxExpectimaxArenaRunner/BotMatchRunner(передавать засеянныйRandom). - Единый
FeatureExtractorв движке — расширитьOnnxFeatures: сперва дешёвые фичи (мобильность, king-safety). Инференс уже через него. - Enrichment-раннер (Scala, CSV→CSV) + прогон на Oracle.
- Переобучить (dicechess-ev) на дешёвых фичах → замер AUC/калибровки + арена (1-ply и 2-ply).
- Добавить KCP в экстрактор → отдельная ветка модели; эксперимент 1-ply+KCP vs 2-ply+материал на Oracle (много партий).
- Победивший вариант → новый
oracle-Nв парке house-bots (паттерн (модель, поиск), новый релиз/деплой).
Честный риск
Ожидаем, что KCP-фичи дадут заметный скачок (прямое зрение на условие победы). Но это гипотеза — проверяется замером. Дешёвые фичи (мобильность/king-safety) могут дать лишь скромную прибавку. Поэтому порядок: сперва дешёвая быстрая итерация, KCP — как отдельный сильный эксперимент.