Ядро солвера PLO5 / PLO6: где мы сейчас

данные на {{ dataDate }}
Солвер
сегодня
Префлоп
Флоп
Тёрн
Ривер
{{ cr.row }}
Показать
Вид карты
{{ edgesSvg }}
{{ pulse }}
{{ n.title }} {{ n.kidLabel }}
{{ n.stLabel }}
Готово - подтверждено кодом Текущий фокус Следующее по плану В плане / оценка Исследуем Ждёт данных Связь между ветками
Объяснялка 1 из 6

Дерево „взрывается“

Солвер хранит все возможные продолжения раздачи. Каждая ставка - развилка, а каждая новая карта - десятки развилок сразу. Переключите улицы и посмотрите, как растёт дерево.

{{ trSvg }}
{{ tl.t }}
Варианты ставок Новая карта на столе Схема упрощена: настоящих ветвей в тысячи раз больше
Ветвей на схеме {{ trLeaves }} {{ trT.ahead }}
Память{{ trRamTag.t }}
{{ trT.ram }} {{ trT.hands }}
Время расчёта, PLO6{{ trTimeTag.t }}
{{ trT.time }} {{ trT.where }}
Сколько памяти нужно улицеЛогарифмическая шкала: каждое деление - в 10 раз больше
{{ tb.t }}
{{ tb.lab }}{{ tb.tag.t }}
384 ГБ · сервер
ВыводРивер - сотни мегабайт, тёрн - тоже немного. Флоп точно по каждой руке помещается только на 2 000 рук: 72 ГБ. На группах флоп на 100 тыс. рук занимает до 166 ГБ и считается 2,6 часа на сервере (замер 019).
На группах RAM ≈ строки действий × группы × 4 байта + таблицы групп (16 байт на пару групп на каждой из 2 352 досок ривера); при сборке движка таблицы лежат дважды, поэтому пик в 2,4-2,6 раза выше. Флоп при банке 10 bb и стеке 50 bb: упрощённые ставки - 2,0 млн строк, по умолчанию 33/50/75/100% - 8,0 млн (точный подсчёт 019). Ривер и тёрн - замеры на ноутбуке при 10 000 и 1 000 рук; флоп - замер 019 на 100 тыс. рук, EPYC 9575F.
Объяснялка 2 из 6

Как солвер учится

Солвер не знает ответа заранее. Он раз за разом играет сам с собой и „жалеет“ о вариантах, которые принесли бы больше. Здесь - настоящий расчёт на самой простой игре, прямо в браузере.

Игрок 1 · ходит первымНатсы или воздух - 50 на 50

Банк 10 bb. С натсами всегда ставит 10 bb. Вопрос солверу: как часто ставить с воздухом, то есть блефовать?

Игрок 2Ловец блефов

Его рука бьёт только блеф. Вопрос солверу: как часто отвечать на ставку коллом?

Итерация {{ cfIt }}
100% 50% 0%
0итерации → {{ cfMax }}
Блеф воздухом - средняя Колл ловца - средняя Тонкие - текущая стратегия, она раскачивается
Воздух блефует {{ cfAB }}
Теория: 50% - тогда треть всех ставок блеф
Ловец коллирует {{ cfAC }}
Теория: 50%
Эксплуатируемость{{ cfExpl }}
EV игрока 1{{ cfEV }}теория 7,50 bb
Сошлось к равновесию - как в теории
ВыводТекущая стратегия всё время „качается“: блефуем много - соперник начинает коллировать, он коллирует - блефуем меньше. А средняя за все итерации приходит к равновесию. Наш солвер на этой игре даёт блеф 49,9% и колл 50,0% - это проверка /proof в Telegram-боте.
Здесь - vanilla regret matching с усреднением стратегии по reach, стартовые regrets 9:1 (блеф 90%, колл 10%). Ядро проекта использует Discounted CFR. Эксплуатируемость = NashConv / банк; у ривера PLO6 на 5000 рук - 0,25% банка.
Объяснялка 3 из 6

Диапазон - мешок рук

Мы не знаем карты соперника, но знаем, какие руки у него могут быть. Каждое его действие делает одни руки вероятнее, другие - почти невозможными. Нажимайте действия по очереди.

Мешок рук соперникаВозможных рук: {{ rgLeft }} из 60 · размер = вес
{{ rc.t }}
Что сделал соперник
Доля каждого типа в мешке
{{ rs.t }}
{{ rs.share }}
{{ rgHist }}
ВыводЧтобы правильно разобрать ривер, солверу нужен мешок, каким он стал к риверу, а не „любые руки“. Поэтому так важен префлоп: это первый и самый большой фильтр, и его даст наша базовая стратегия. Числа в этой анимации условные - для иллюстрации.
P(h | a) ∝ P(h) · P(a | h), затем нормализация и исключение рук, конфликтующих с бордом (блокеры). На троих учитывается совместимость рук всех игроков. Популяционные диапазоны ≠ GTO-диапазоны.
Объяснялка 4 из 6

Память и процессор: склад и грузчики

Память (RAM) - склад: вся задача должна поместиться в него целиком. Процессор - грузчики: чем их больше, тем быстрее идёт работа. Но если груз не влез на склад, грузчики стоят.

Задача
Машина
{{ whS.s }}
Потоков
{{ whThr }}
Склад · RAM{{ whCapGB }}
Не влезло:
складданные ↔ расчётгрузчики
движения нет
Задача{{ whTaskGB }}{{ whTag.t }}
{{ whMsg }}
Грузчики · потоки CPU
Светлые - физические ядра, тёмные - вторые потоки тех же ядер (SMT)
не измерено идеал: ×N 32× 1× 1 поток 128 потоков
Скорость от числа потоков {{ whSpeed }} Ось потоков - логарифмическая. Серверы - замеры на тёрне PLO6 с 1 000 групп; ноутбук - замер 009. До 16 ядер скорость растёт почти как идеал. Дальше упор в память: 32 ядра дают 70-73% от идеала, 64 ядра EPYC 9575F - 44%, а вторые потоки тех же ядер - от +5% до −7%.
ВыводСначала нужно, чтобы задача влезла в память, и только потом важна скорость. Флоп на группах с 1 000 групп ривера занимает до 166 ГБ, с полными ставками - до 226 ГБ: хватает сервера на 256-384 ГБ. С 2 000 групп ривера пик 475 ГБ, пока при сборке движка таблицы лежат дважды. Ядра сверх 16-32 дают всё меньше.
Объяснялка 5 из 6

Где помогает видеокарта

У видеокарты тысячи маленьких ядер, но они сильны, только когда делают одно и то же одновременно. Солверу же приходится идти по дереву, где каждая ветка - своя дорога.

Видеокарта · много маленьких ядер
{{ gpGpuTxt }}
Процессор · 16 больших ядер
{{ gpCpuTxt }}
Поэтому этапы разделены и арендуются отдельно
CPU-сервер
солвер на Rust
Датасет
решения солвера
GPU по часам
обучение сети
Модель
быстрые ответы
Оператор
разбор за секунды
Deep CFR: нейросеть стоит внутри цикла CFR - процессор и видеокарта нужны одновременно и постоянно обмениваются данными. Выигрыш по времени для PLO6 неизвестен.
Обычный путь: месяцами считаем на процессоре, потом на несколько часов арендуем видеокарту для обучения. Постоянно платить за оба сервера не нужно.
ВыводВидеокарта сильна там, где много одинаковых операций сразу: обучение моделей и большие матричные умножения, например выплаты на троих. Обход дерева CFR ей даётся плохо. Deep CFR - отдельная исследовательская ветка, её проверяем своим бенчмарком. Анимация - схема, не замер.
Объяснялка 6 из 6

Префлоп зависит от всего будущего

Чтобы понять, стоит ли рейзить руку до флопа, нужно знать, чем закончится раздача на всех следующих улицах. Посмотрите, где полный перебор упирается в память и как его обходит базовая стратегия.

{{ pb.t }} {{ pb.mT }}
{{ pb.sub }}
{{ ps.n }}{{ ps.t }}
Так будет выглядеть чартМакет, не GTO
PLO66-maxBTNпротив рейза UTG100bb
A♠ A♥ K♠ Q♥ J♦ T♦
Фолд- %
Колл- %
Рейз- %
Частот пока нет: их даст базовая стратегия.
Почему один чарт не подходит всем Частоты зависят от позиции, глубины стеков, рейка, размера рейзов и всей истории до вас. Другая позиция или другой SPR - другой чарт. В PLO6 у одного игрока 20 358 520 стартовых рук - удобной таблицы 13 × 13 как в холдеме не будет. Нужен просмотр по типам: пары, масти, связанность, блокеры. Глубина стеков в клубе разная, но чаще всего большая: по первому просмотру 7,7 млн раздач клуба эффективный стек от 120 bb в 86% раздач, от 250 bb - в 47%. Базу считаем отдельно для каждой глубины.
ВыводПолный перебор префлопа не поместится ни в один сервер. Поэтому префлоп считаем своим солвером как базовую стратегию: похожие руки объединены в группы, размеров ставок немного, расчёт идёт на арендованном сервере. Сначала холдем, для него есть открытые чарты для сверки, затем PLO4, PLO5 и PLO6. Чарты клиента не обязательны, но пригодятся для сверки.
Калькулятор

Сколько нужно памяти

Память ≈ строки действий × группы рук × байты на пару + таблицы групп на каждой доске ривера, и всё это с запасом на сборку движка. Модель сверена с тремя замерами флопа (019). Двигайте ползунки или выберите готовую конфигурацию.

Строки действий в дереве{{ rnL }}
Точный подсчёт (019): упрощённые ставки при стеке 50 bb - 2,0 млн, полные - 8,0 млн, глубокий банк без 3-бета - 25 млн
Групп рук на ривере{{ rhL }}
К ним добавляются 200 разбираемых рук отдельными группами
Байт на строку и группу{{ rbtL }}
4 - сожаления и стратегия в 16 битах, как в движке сейчас
Запас на сборку движка{{ roL }}
По замерам пик в 2,4-2,6 раза выше данных и таблиц: при сборке таблицы лежат дважды
Модель, сверенная с замерами Нужно памяти {{ rcGB }} {{ rcFormula }}
{{ rs.t }}{{ rs.v }}
Шкала памяти · логарифмическая: 10 ГБ → 2 ТБ
{{ rm.m }}{{ rm.n }}
Модель для одного флопа. На замерах 019 она расходится с пиком памяти не больше чем на 5%: 160 ГБ против 166, 500 против 475, 231 против 226. Глубокие стеки - оценка: таких замеров ещё нет. Строки дерева берите из точного подсчёта: они зависят от ставок, олл-инов и глубины. Когда уберём вторую копию таблиц, запас на сборку уменьшится.
Калькулятор

Сценарий окупаемости

Сколько дополнительного математического ожидания даёт команде небольшое улучшение игры. Это сценарий, а не прогноз прибыли: дисперсия, соперники и усвоение тренировок здесь не учтены.

Раздач в месяц{{ roiHands }}
Устойчивое улучшение игры{{ roiDeltaL }}
Значения по умолчанию - вводные заказчика из обсуждений: 30+ игроков, около 1000 раздач в день, $25/$50. Документами клуба не подтверждены.
Сценарный EV, не прогноз прибыли Дополнительное ожидание команды в месяц {{ roiEV }}
Сервер окупается при{{ roiBE }}
Ожидание / стоимость{{ roiX }}
УлучшениеОжидание команды в месяц {{ rr.d }}{{ rr.v }}
Формула: игроки × раздачи в месяц / 100 × улучшение bb/100 × $BB. Не учитывает дисперсию, игру сотрудников клуба друг против друга, неполное освоение тренировок и реальные лимиты. Эффект обучения измеряется отдельно - на новых раздачах.
Цифры

Замеры и оценки

Что реально запускали и измеряли - отдельно от того, что пока только оценено по размеру дерева.

Измерено в проектеЗамер
Ноутбук Ryzen 7 5800H (8 ядер / 16 потоков), Rust; банк ≈10bb, стек 50bb; ставки 33/75/100%, рейз в банк, олл-ин; остановка ≈0,3% банка. СпотРук на игрокаВремяПамять {{ bm.spot }}{{ bm.hands }}{{ bm.time }}{{ bm.ram }} Rust быстрее Python в 14-17 раз на ривере и в 45-47 раз на тёрне; на 8 физических ядрах - ≈7-8× от одного потока.
Серверы: один замер на наших расчётахЗамер
Каждую машину-кандидата проверяем одним и тем же замером: без данных, около 7 минут. Он меряет скорость памяти, подготовку групп и итерации тёрна PLO6 (10 000 рук) при 300, 1 000 и 2 000 групп и при разном числе потоков, точный расчёт по рукам. Из этого - время и память флопа.
ЗамерНоутбук Ryzen 7 5800H2 × EPYC 7443EPYC 9355PEPYC 9575F {{ bs.k }}{{ bv.t }}
Оценки флопа - по точному размеру дерева (банк 10 bb, стек 50 bb), по 1 000 групп на каждой улице и без пика при сборке движка; прежняя оценка через дерево тёрна завышала в 2-4,75 раза. Настоящий флоп на 100 тыс. рук посчитан в задаче 019 на EPYC 9575F: 5 000 групп флопа и тёрна, 1 000 ривера и 200 разбираемых рук, поэтому он тяжелее оценки. После 16 ядер отдача от новых ядер падает, поэтому недорогой сервер на несколько суток часто выгоднее мощного на несколько часов.
Ривер на троих: эталон на PythonЗамер
PLO5, ноутбук; банк 10 bb, стеки по 50 bb. Время одной итерации CFR при разном числе рук у каждого игрока. Расчёт растёт примерно как куб числа рук. СтавкиТочек решения100 рук300 рук1 000 рук {{ b3.cfg }}{{ b3.nodes }}{{ b3.h100 }}{{ b3.h300 }}{{ b3.h1000 }} Память при 1 000 рук - около 240 МБ. Перенос на Rust и группы рук - задача 021, следующая после данных клуба.
Флоп PLO6: замер 019Замер
Флоп Ks9h4c, банк 10 bb, стек 50 bb, 100 тыс. рук на группах, EPYC 9575F. Точный расчёт по рукам на флопе помещается только на 2 000 рук - это эталон для проверки групп. РасчётСтрок действийИтерацияДанные и таблицыПик памяти {{ be.cfg }}{{ be.nodes }}{{ be.h500 }}{{ be.h1000 }}{{ be.h5000 }} Подготовка групп - 47 минут, 500 итераций с упрощёнными ставками - 2,6 часа. Пик выше данных и таблиц, потому что при сборке движка таблицы лежат дважды: в Python и в Rust.
Цифры

Четыре подхода к флопу

Сейчас флоп считается на группах рук (019), а точный расчёт по рукам служит эталоном. Value Network и Deep CFR - кандидаты для скорости, их ещё не проверяли.

{{ cr.k }}{{ cv.t }}
Сделано в 014-019: группы рук по всему диапазону, 16 бит, упрощённые ставки, точный подсчёт дерева. Дальше для скорости разбора - модели значений тёрна и ривера: с ними флоп решается только до тёрна. Deep CFR - альтернатива со своим бенчмарком „время до одинакового качества“. Метрики GTO Wizard относятся к PLO4 и на PLO6 не переносятся.
{{ dc.date }}{{ dc.st }}

{{ dc.t }}

Ситуация{{ dc.ctx }}
Что решили{{ dc.chosen }}
Почему{{ dc.why }}
Какие ещё были варианты ВариантЗаПротив {{ al.t }}{{ al.pro }}{{ al.con }}
{{ ds.t }}

Словарь

Покерные, математические и инженерные слова, которые встречаются на карте. В режиме „Технически“ - подробности.

Такого термина нет. Попробуйте поиск в шапке - он ищет и по карте.
{{ gg.t }}
{{ gi.t }}

{{ gi.s }}

{{ gi.x }}

Ссылки

Внешние материалы и серверы, которые упоминаются на карте. Цифры из чужих работ, например для PLO4, на PLO6 автоматически не переносятся.

Исследования и солверы МатериалГде на карте {{ lr.t }}{{ lr.used }}
Серверы для аренды Кандидаты для тестов и для префлоп-солвера. Цены и наличие меняются, актуальные - на сайтах поставщиков. СерверГде на карте {{ ls.t }}{{ ls.used }}