Привет, Хабр! Пару лет назад мы с коллегами из Центра искусственного интеллекта СФУ искали способы набраться практического опыта в задачах компьютерного зрения.Привет, Хабр! Пару лет назад мы с коллегами из Центра искусственного интеллекта СФУ искали способы набраться практического опыта в задачах компьютерного зрения.

Хакатон Норникеля: как мы выжали максимум из YOLO и заняли 2 место

Привет, Хабр! Пару лет назад мы с коллегами из Центра искусственного интеллекта СФУ искали способы набраться практического опыта в задачах компьютерного зрения. Одним из таких форматов оказались хакатоны — соревнования по решению ML-задач на реальных кейсах с жесткими дедлайнами.

За эти пару лет мы успели поучаствовать примерно в десяти хакатонах (Цифровой прорыв, Атомик Хак) и в половине из них доходили до призовых мест. Один из кейсов оказался особенно интересным из-за условий, в которых его пришлось решать. Это хакатон от Норникеля под названием «Интеллектуальные горизонты»

Промо-баннер хакатона (материалы организаторов)
Промо-баннер хакатона (материалы организаторов)

Выбор кейса

Организаторы подготовили три кейса на выбор, среди которых были «Флотомашина времени», «Мультимодальные RAG-модели» и кейс под названием «Грязные дела», который мы и выбрали.

Задача из нашего кейса звучала так «Разработка метода определения степени загрязнения кадра, для обеспечения надежной работы камер на производстве, а также роботов-курьеров и автономных транспортных средств».

Пример данных. Изображение и маска
Пример данных. Изображение и маска

По сути, это задача бинарной сегментации изображений (Binary Image Segmentation).

Подробности о том, что это за камера (скорее всего эндоскоп) и условия ее использования не уточнялись, но проблема ясна: подобные загрязнения могут мешать другим моделям ИИ анализировать видеопоток, и нужен был фильтр, который бы говорил, где грязное пятно и на какую область кадра не обращать внимания.

Проблема системы валидации решений

Основная причина, по которой этот хакатон стал для нас необычным — это проблема системы проверки решений. Дело в том, что в обычно для проверки обычно участник отправляет на платформу submission-файл с предсказанными метками для тестовой выборки, а система сверяет их с правильными и выдает score по какой-нибудь метрике (в нашем случае это была mIoU), что и определяет позицию команды на лидерборде.

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

Содержимое архива для сабмита
Содержимое архива для сабмита

И вот тут важная деталь: у платформы был только один фиксированный docker-образ с типовым набором библиотек: ultralytics, torch, torchvision и другое типичное навесное.

В результате стабильно работало фактически только одно решение — бейзлайн от организаторов, основанный на применении YOLOv11 для задачи сегментации. Любые отклонения от предложенного шаблона (другая модель или иная сборка окружения) почти гарантированно приводили к ошибке на стороне сервера.

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

Работа с данными в условиях фиксированной модели

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

Всего организаторы дали 250 реальных + 147 синтетических изображений с разметкой контурами, и формально этого достаточно, чтобы дообучить YOLO. Но проблема была в том, что все команды делали ровно то же самое.

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

  • берет исходное изображение и маску;

  • случайно применяет набор трансформаций: повороты, флипы, яркость и контраст;

  • применяет raindrop к оригиналу (с альфой) и к маске.

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

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

Оптимизация пред- и постобработки

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

Рассматривая выводы модели, капитану команды Константину Кожину пришла в голову гипотеза: маски, которые модель выдает на выходе, часто получаются чуть меньше, чем истинные контуры. Мы попробовали это компенсировать тем, что искусственно расширили контуры маски на постобработке, отправили решение на проверку и… ура: метрика стала выше и на обучающей, и на валидационной выборке, и на лидерборде.

Было решено дальше копать в этом направлении, и мы выбрали 5 параметров, которые подбирали, а именно:

  • яркость,

  • контраст,

  • шумоподавление (cv2.bilateralFilter),

  • масштабирование,

  • сглаживание контуров.

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

Если упростить, то дифференциальная эволюция работает так: мы заводим популяцию наборов параметров, а дальше начинаем их скрещивать и мутировать. Те параметры, которые дают метрику лучше, остаются, а другие отбрасываются. И так несколько поколений подряд.

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

Схема решения
Схема решения

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

Результаты

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

График моделей (all 0 - пустые маски)
График моделей (all 0 - пустые маски)

Возник логичный вопрос: будет ли этот подход работать на тестовых данных организаторов? Как оказалось — да. По финальному скору мы вышли на первое место в лидерборде.

Лидерборд (скриншот с платформы)
Лидерборд (скриншот с платформы)

В итоговом зачете, где учитывались не только метрики, но и защита решения, а также качество оформления, мы заняли второе место.

Финальный лидерборд
Финальный лидерборд

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

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

Участники команды

Константин Кожин — Капитан команды, Data Scientist;

Павел Шерстнев — ML-Engineer;

Владислава Жуковская — Дизайнер;

Софья Голубовская — Дизайнер;

Алина Нуриманова — Data Analyst.

Источник

Возможности рынка
Логотип YOLO
YOLO Курс (YOLO)
$0.000000006497
$0.000000006497$0.000000006497
+1.07%
USD
График цены YOLO (YOLO) в реальном времени
Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу [email protected] для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.