История о том, почему в ML побеждают не те, у кого самая большая модель, а те, кто понимает, что они делают.

Введение

Современные object detection-модели достаточно мощные, чтобы «из коробки» выдавать приемлемую точность. Особенно если задача выглядит простой — например, определить, где на покерном столе лежат карты.

Но «приемлемо» и «надёжно» — не одно и то же.

В одном из проектов заказчик обучил модель, которая показывала 93% точности на валидной выборке, но на практике её приходилось постоянно подчищать вручную. Модель теряла карты в нужных моментах, срабатывала на графику трансляции и мешала, а не помогала аналитике.

Мы не делали «революции». Просто убрали одно лишнее допущение. Вот как это было.

Что было

У клиента уже была обученная модель на базе YOLO. Датасет — полусинтетический: микс реальных изображений и синтетики сформированной на их основе. Синтетическая часть была сделана аккуратно — карты размещались не хаотично, а строго в тех зонах виртуального стола, где они действительно могут находиться во время партии.

Результат выглядел достойно: высокая точность, хорошая визуализация, адекватная скорость. Но при этом:

  • путала масти одного цвета;

  • порой было несколько пересекающихся детекций разных классов на одной карте

  • ошибалась при появлении рядом с картой надписи WIN

  • требовала ручной верификации — каждый розыгрыш приходилось пересматривать.

Что-то шло не так — и это «что-то» не было архитектурой.

Синтетика ≠ реальность

Такая «правильная» генерация не закрывала весь спектр реальных условий игрового клиента. В настоящей сессии могут меняться скины стола, появляться анимации, надписи вроде WIN или Next hand, динамические элементы интерфейса, индикаторы ставок и таймеры. Иногда карты частично перекрываются всплывающими подсказками или графикой чата.

В результате модель, натренированная на чистых и предсказуемых кадрах, иногда терялась, когда встречала такие элементы. Это классическая история про переобучение на «лабораторных» условиях: данные хорошие, но слишком стерильные. К счастью, в онлайн-покере этот разрыв между тренировочными и боевыми данными можно относительно быстро сократить — достаточно добавить в датасет примеры с реальными визуальными шумами и анимациями.

Постобработка: виноват agnostic=False

Второй источник проблем оказался в NMS. В конфиге стоял стандартный режим agnostic=False, при котором подавляются только пересекающиеся боксы одного и того же класса. В реальности детектор иногда выдавал по одной и той же карте два предсказания разных классов (типичная ошибка при близких по виду номиналах/мастях). Из‑за agnostic=False эти боксы не конфликтовали и оба проходили постобработку — в данных появлялись дубликаты одной карты с разными метками, что ломало аналитику.

Мы переключили режим на agnostic=True, чтобы NMS сравнивал пересекающиеся боксы без учёта класса и оставлял самый уверенный. Дубли исчезли сразу: по каждой карте стал оставаться ровно один бокс с корректной меткой. Важно: обычно agnostic=True применяют осмотрительно — при плотных сценах он способен «съесть» соседние объекты разных классов. Но в онлайн‑клиенте покера карты на виртуальном столе практически не перекрываются по IoU, поэтому риск ложных удалений минимален; дополнительно мы поджали IoU/score‑пороги под наш стрим.

Итог — стабильные счётчики, чистая разметка на выходе и рост доверия к расчётам именно там, где это критично.

Остальные правки — инженерные

Кроме agnostic, мы пересмотрели конфигурацию обучения. Убрали несколько параметров, которые в этом проекте скорее мешали: Подняли мозайку с 0.8 до 1.0, как правило она увеличивает точность и помогает отучить модель от того, чтобы смотреть на контекст вокруг (недостатки архитектуры YOLO) и заставить концентрироваться на самой карте. Также убрали горизонтальный переворот т.к. отражённом виде карты на инференс никогда не поступят. Также были небольшие правки типа более агрессивного порога IOU опущенного с 0.6 до 0.3, карты на столе почти не пересекаются. Количество эпох увеличено со 150 до 1200, чтобы получить хотя бы 50 тысяч итераций, при 44 итерациях за эпоху..

Это были не эксперименты, а результат понимания: что реально встречается в продакшене, и как модель должна на это реагировать. Дообучение шло на тех же весах, без изменения архитектуры. Просто аккуратная доводка.

Финал

После правок:

  • модель перестала делать двойные предсказания для одной карты

  • не срабатывала на титры и лишние графические элементы,

  • не требовала ручной верификации.

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

Вывод

Это не был проект «спасения модели». Это был проект здравого смысла. Здесь не понадобились ни новая архитектура, ни огромный GPU кластер, ни 200 тысяч размеченных картинок. Всё сработало потому, что человек, который на это смотрел, понимал, что делает.

И знал, что agnostic=True — это не просто флаг. Это решение. И в этой задаче — правильное.

Комментарии (0)