Буквально недавно мы заняли 7 место в конкурсе https://www.kaggle.com/c/humpback-whale-identification.

Цель - идентифицировать горбатых китов по их хвостам: либо кит входит в число известных 5004, либо это «новый кит» - пока неизвестно).

Набор данных очень сложен, так как он взят из реальной жизни, где у вас есть только одно изображение для идентификации кита, несколько изображений (читается как - очень несбалансированный набор данных) или «новых китов», тех китов, которые неизвестны. Образы в любом масштабе, с любого ракурса, разные (старые - киты были молодыми и красивыми, новые - росли и менялись, но оставались красивыми: D))).

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

Звучит весело, да?)

Игорь пригласил меня принять участие в этом испытании, и путешествие началось :) Мы создали команду, а потом объединились с Дмитрием.

Наша часть работы была сосредоточена на метрическом обучении.

Поначалу подход был простым и понятным, вот все основные части:

  1. Мы выбрали изображения из каждого класса единообразно: по два изображения на каждый идентификатор - привязку и позитивное изображение для каждой эпохи. Мы начали с использования LAP, но перешли к классической стратегии жесткого отрицательного майнинга (сбор всех характеристик во время обучения и вычисление самого жесткого отрицательного якорного изображения после каждой эпохи), чтобы ускорить процесс.
  2. Набор для проверки: у нас было очень маленькое в начале, все изображения, которые имеют более трех изображений на идентификатор - одно из них запрашивает, другая галерея + new_whales в качестве отвлекающих факторов. Мы использовали однократные снимки (увеличенный положительный имидж) для обучения. У нас был подход запроса / галереи. Позже мы перешли к данным соревнований по игровым площадкам и оценили на них наши модели.
  3. Игорь промаркировал и создал детектор, коробки из которого мы использовали большую часть времени соревнований.
  4. После получения достаточно хороших моделей мы создали и проверили список плохих изображений и удалили их из обучения.
  5. Мы пробовали разные размеры изображений, мы тренировались на изображениях RGB: 256x256, 384x384, 448x448, 360x720.
  6. Мы использовали дополнения: случайное стирание, аффинные преобразования (масштаб, сдвиг, сдвиг), яркость / контраст.
  7. Мы использовали следующие модели: resnet34, resnet50, resnet101, densenet121, densenet162, seresnext50 - опробованные нами опорные архитектуры, за которыми следуют GeM pooling layer + L2 + multiplier.
  8. Убыток: сильная тройная потеря
  9. Мы также использовали циклический lr и взяли функции (максимальное + среднее объединение) из 3–4 различных контрольных точек. Помогло, вначале…)

До того, как мы объединились с Дмитрием, у нас был ансамбль из 10–12 лучших моделей. Затем мы перешли к новому конвейеру, в котором наши модели служили инициализацией для моделей классификаторов, и это действительно хорошо сработало для нас.

Подробнее об этой части пути и нашем окончательном решении читайте здесь: https://medium.com/@ducha.aiki/thanks-radek-7th-place-solution-to-hwi-2019-competition-738624e4c885

Кроме того, мы пробовали кое-что…:

  • Модель сегментации. Мы пометили и обучили Unet, извлекли сегментированные изображения с небольшим расширением масок сегментации и попробовали обучение на этих сегментированных изображениях, что не улучшило для нас производительность.
  • Детектор ключевых точек. Мы дополнительно разметили и обучили детектор ключевых точек для совмещения изображений. Мы сделали расклад. Наконец-то. Это помогло, но не сильно.

И еще немного…)

  • Мы разметили данные и создали классификатор полукитов. Кроме того, мы заменили те изображения, которые были только наполовину китами, на выровненные, обрезанные и зеркальные, чтобы получить «полное» изображение кита.
  • Балансировка одноразовых классов: получение первой частоты классов и замена класса «новый кит» на классы, которые являются одноразовыми и не представлены @ top-1.

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

И попробовал еще ... Не получается:

  • PCA + отбеливание
  • DBA
  • Предварительно обучен от классификатора VGG16
  • Контрастная потеря + жесткий майнинг при нашей базовой настройке
  • Слияние слоев (работало для resnet34, позже не работает для других архитектур)
  • Балансировка классов вероятности
  • Повторное ранжирование
  • Псевдо-метки
  • TTA работал только для переворачивания изображений, добавляя очень небольшой процент, и не работает ни для чего другого.

Итак, вот и вся история)

Хочу поблагодарить моих замечательных товарищей по команде, организаторов, Семью, Вселенную и, конечно же, Радека! :)