🎯 Вероятности при малом числе партий: prior + сглаживание вместо Монте-Карло
О чём это
Обсуждение 2026-08-08. Аналитика показывает win-rate по ключу
normalized_fen + dice_sorted. Для частых позиций хватает эмпирики из БД, а для редких сегодня предполагается фолбэк наMonteCarloEquity— он медленный и отвечает не на тот вопрос. План: заменить «MC при малом N» на калиброванный prior от модели + байесовское сглаживание, MC оставить валидатором. Контекст по данным: собрано уже 1,5 млн партий (DiceChess.com + play.jc.id.lv + немного Beturanga.com), окно вычислений — Azure-кредит €150 / 20 дней (до ~2026-08-28) либо локальный MacBook Pro.Связанные: what-is-lightgbm · what-is-nnue · value-model-improvement-plan · model-improvement-results-and-oracle-bots-roster · monte-carlo-vs-aggressive-analysis · opening-book-as-built
Замерено 09.08.2026: ядро этого плана не подтвердилось — читать вместе с журналом
Brier-бенчмарк на холдауте из 2 млн ходов (журнал, запись «ночь 09.08») опроверг два пункта ниже:
- сглаживание
(w + α·p_prior)/(n + α)не нужно — смесь проигрывает чистой модели во всех сегментах, а α подбирается в максимум сетки, то есть «эмпирику почти игнорировать». Модель точнее эмпирики даже там, где n ≥ 10;- изотоническая пост-калибровка не нужна — модель уже откалибрована (0.2132 против 0.2132 по Brier).
Причина, которую план не учёл: 97% позиций встречаются ровно один раз, а 0,26% дебютных покрывают 25,8% ходов. Эмпирика существует только в голове распределения, и даже там она хуже модели. Формулировка «эмпирика для частых, prior для редких» перевёрнута: модель — основной оценщик везде.
Что из плана подтвердилось: отказ от Монте-Карло (замер: MAE 4,5 пп, сохраняет 43% сигнала, 25 с/позицию) и выбор LightGBM на rich+KCP как оценщика. Разделы 1 и 3 остаются в силе; разделы 2 (шаги 2–3) читать как «идея, проверенная и отклонённая».
1. Почему Монте-Карло здесь плох — и почему это не лечится
MonteCarloEquity (движок, порт C++-референса) — Rao-Blackwell-роллауты: на каждом ply аналитически интегрируется точная вероятность взятия короля (KingCaptureProbability, все 216 исходов), а дальше позиция продвигается случайным ходом. У него две независимые проблемы:
Проблема 1 — смещение случайной политики. Rao-Blackwellization честно убирает дисперсию (и это красиво сделано), но оценка отвечает на вопрос «кто выиграет, если обе стороны ходят случайно». Случайная игра размывает материальное и позиционное преимущество: всё сводится к «у кого чаще выпадает удар по королю». Это систематическая ошибка — добавление роллаутов её не уменьшает, только сужает доверительный интервал вокруг смещённого ответа. Дельты против БД в mise run eval:mc — ровно это.
Проблема 2 — цена. Каждый ply роллаута = один DFS KingCaptureProbability по 216 исходам (~10–15 мс, см. замеры в model-improvement-results-and-oracle-bots-roster) плюс generateAllLegalTurnPaths для случайного продолжения. При 200 роллаутов × десятки ply это порядка минут на одну позицию — в горячий путь API не ставится в принципе.
Вывод
MC — не «медленный, но точный», а «медленный и смещённый». Ускорять его бессмысленно: смещение политики останется. Нужен другой каркас.
2. Предлагаемый каркас: эмпирика + калиброванный prior
Идея в том, чтобы никогда не переключаться между «эмпирикой» и «моделью» по порогу, а всегда смешивать их с весами, зависящими от количества данных.
Шаг 1. Калибровка: оценка модели → вероятность
Любая оценка позиции (LightGBM-скор, выход сети, даже HunterEval) — это ещё не вероятность. Одноразово подгоняем отображение eval → P(win) на исходах реальных партий: логистическая регрессия (или изотоническая, если форма кривой нестандартная). Это ровно то, что Stockfish делает с centipawn → win% и Leela со своей WDL-головой. После калибровки модель для любой позиции выдаёт честную вероятность p_prior за микросекунды-миллисекунды.
На ком калибруем = чью вероятность показываем
Эмпирика по всем игрокам отвечает «как выигрывают в среднем», а
domain-conventions.mdаналитики фиксирует референс: win-rate сильных игроков. Калибровать надо на партиях сильных (фильтр/взвешивание по рейтингу), иначе prior и эмпирика будут мерить разное, и сглаживание начнёт их «спорить». С тремя источниками (DiceChess.com, play.jc.id.lv, Beturanga) это важно вдвойне: пулы игроков разные — источник и рейтинг должны быть фильтрами калибровки.
Шаг 2. Байесовское сглаживание (empirical Bayes / shrinkage)
Показываемая вероятность:
P̂ = (wins + α · p_prior) / (n + α)
n— партий в БД для этого узла,wins— из них выигранных (ничья = 0.5);p_prior— калиброванная вероятность от модели;α— «вес prior’а в эквивалентных партиях», обычно 10–50.
При n = 0 показываем чистый prior, при n ≫ α — чистую эмпирику, между ними — плавный переход без порогов и швов. α не выдумывается, а подбирается минимизацией log-loss/Brier на отложенной выборке с временны́м сплитом по партиям (обучение до даты T, проверка после — позиции одной партии не должны попадать в обе стороны).
Шаг 3. Иерархия для ключа (позиция, бросок)
Ключ explorer’а normalized_fen + dice_sorted в ~56 раз реже, чем сама позиция (56 мультимножеств броска). Двухуровневое сглаживание:
эмпирика (pos, dice) → сглаживается к эмпирике (pos) → та к p_prior
Prior при этом может быть roll-aware: ценность лучшего хода при данном броске, если модель/поиск умеет оценивать после броска (наши _nodice-модели оценивают до броска — обе точки зрения полезны).
Шаг 4. Честный UI
При малых n любая «точная» цифра — иллюзия: биномиальная ошибка при n = 25 — это ±20 пп (95% CI), при n = 400 — ±5 пп. Показывать рядом с вероятностью счётчик партий и/или интервал.
3. Чем заполнить prior: меню быстрых оценок
Ключевая поправка после замеров KCP (см. model-improvement-results-and-oracle-bots-roster): стоимость prior’а — это стоимость его фичей, а не модели. Сам LightGBM-инференс — микросекунды, но KCP-фичи к нему стоят ~40–60 мс на позицию.
| Вариант | Цена/позицию | Данных нужно | Статус у нас | Вердикт |
|---|---|---|---|---|
| LightGBM на material+dice | ~мкс | мало | ✅ baseline обучен | нижняя планка, слеп позиционно |
| LightGBM на rich-фичах | ~мс | 1,5M партий — с запасом | ✅ df_rich.onnx | фаворит для массового прекомпьюта |
| LightGBM на KCP-фичах | ~40–60 мс (фичи!) | с запасом | ✅ kcp_nodice.onnx | точнее (AUC 0.711), но только голова/on-demand |
| Raw-board сеть (value) | ~мс CPU | десятки млн позиций — теперь есть | ✅ rawboard_l000.onnx | тёмная лошадка, см. ниже |
| NNUE-style сетка | ~мкс | десятки млн + лучше с дистилляцией | ❌ нет | отдельная история → what-is-nnue |
| Дистилляция Hunter → студент | ~мкс после обучения | генерируется бесплатно | 🟡 distill.py есть | приватный трек (см. open-core) |
| Expectimax d1–2 поверх KCP | ~десятки мс | не нужны | частично в движке | точная «тактическая» фича/страховка |
Policy ≠ value: почему raw-board рано хоронить
Гейты ev#16 мерили raw-board как игрока (пре-ранкер/политика) против oracle-3 — и там она проигрывает. Аналитике нужен не игрок, а калиброванный value: планка «полезный prior с весом α≈20 партий» на порядки ниже планки «обыграть oracle-3». Включить
rawboard_l000.onnxв бенчмарк стоит — это бесплатно. Тем более что данных стало в 10 раз больше: главный ограничитель сырых досок ослаб.
Open-core
Модели, обученные на исходах партий, чисты для публичных репо. Веса, дистиллированные из Hunter, — де-факто публикация закрытого eval’а: такие артефакты держим приватно (прецедент: модель в приватном GHCR-образе у house-ботов).
4. Что меняет масштаб 1,5 млн партий
- Позиций-строк — десятки миллионов (при ~30–50 ходов на партию). Для LightGBM это комфортная зона уже давно; для сырых досок и NNUE-класса сетей — впервые реалистичная.
- Сплит только по партиям (все ходы партии делят исход; по-строчный сплит = утечка). В
dicechess-ev/data.pyэто уже сделано правильно. - Гетерогенность источников — фича, а не шум:
source × ratingкак фильтры калибровки; сильные игроки DiceChess.com — референс, партии наших ботов с play.jc.id.lv — отдельный срез (боты играют не как люди). - Эмпирическая голова стала плотнее, но хвост остался хвостом: комбинаторика позиций растёт быстрее любой коллекции. Каркас prior+сглаживание нужен при любом размере БД.
5. Вычислительный план: MacBook против Azure (€150 / 20 дней)
MacBook Pro (бесплатно, часы):
- свежий экспорт
db:export-trainingc 1,5M партий, rich-обогащение; - LightGBM-переобучение, калибровка, подбор α, Brier-бенчмарк — всё это CPU-минуты/часы;
- первые итерации сетей (PyTorch/MPS) — тоже потянет.
Azure-кредит — на то, что реально параллелится или требует GPU:
- KCP-обогащение новой выгрузки — «the cloud-CPU run»: при ~50 мс/позицию миллион позиций ≈ 14 CPU-часов, т.е. многоядерная ВМ прожёвывает голову БД (несколько млн уникальных позиций для прекомпьюта книги) за считанные дни;
- GPU-ВМ для raw-board/NNUE-экспериментов, если бенчмарк покажет, что сети того стоят.
Гочи кредитной подписки (уже наступали)
На кредитной подписке
currentSpend = 0.00— бюджетный алерт не сигналит о конце кредита. При круглосуточной ВМ прошлый замер давал ~€9.4/день ⇒ €150 ≈ 16 дней, меньше календарного окна. Правила: ВМ гасить после прогона, тяжёлое — батчами, прогресс — чекпойнтами, дедлайн ~2026-08-28 держать в голове.
6. План действий
- Свежий экспорт на 1,5M партий + rich-обогащение (MacBook), KCP-обогащение головы (Azure CPU).
- Brier-бенчмарк на временнóм holdout — сравнить оценщики: сырая эмпирика / MC /
kcp_nodice/df_rich/rawboard_l000(+ Hunter статикой, приватно). Harness: расширитьEvaluateMonteCarloAppили скрипт вdicechess-ev(evaluate.pyуже умеет калибровочные таблицы). - Выбрать prior по log-loss за единицу стоимости серва; откалибровать на сильных игроках; подобрать α (и α₁/α₂ для иерархии).
- Прекомпьют prior-колонки для головы (opening book / частые позиции), on-demand — для хвоста.
- MC перевести в валидаторы (
eval:mcостаётся регрессионным тестом каркаса). Если когда-то захочется роллаутов для книги — политикой Hunter с температурой, офлайн, с кэшем, не случайной.
Ожидание: побеждает LightGBM на rich/KCP-фичах как prior сейчас; raw-board/NNUE — кандидаты на апгрейд prior’а после (данных уже хватает), причём каркас (калибровка + сглаживание) при смене prior’а не меняется.