Задача по распознаванию картинок от Kaggle или жизнь Machine Learning community в Челябинске

  


    Всякая неожиданная живность постоянно заводится в самых неожиданных местах. То же самое произошло и в Челябинске. Наше Machine Learning сообщество образовалось под эгидой ODS всея Руси и сейчас достаточно стремительно развивается. Как образовалось? Сначала просто завели тред в глобальном ODS Slack, а дальше закрутилось. Сейчас перешли в Телеграмм, где уже начинаются холивары за Random Forest:)
    Локальные сообщества подразумевают встречи. У нас они начались достаточно рутинно: сначала организационная встреча, на которой поговорили об ML, обсудили совместные планы на жизнь и составили небольшую схему дальнейшего развития.

   


Если расшифровать и подытожить, к чему мы пришли, то появилось несколько форматов общения и развития сообщества:

  • "Спикер жжёт" - обычный формат лекций.
  • Мини-хакатон - что-то наподобие полноценного хакатона, но меньший по времени, в пределах 6 часов.
  • Тренировки/зарешки - совместное решение и разбор решений внешних конкурсов (kaggle) по машинному обучению.
  • "Письмо дяди Федора" - совместное онлайн решение, ограниченное по времени, с получением баллов за обнаружение особенностей в данных. Участники решают задачу, по нахождению чего-либо интересного, отправляют сообщение о найденном в общий для всех решающих чат. Первому, обнаружившему какую-либо интересную закономерность, присваивается балл.
  • Совместный просмотр видео с обсуждением. В нашем сообществе есть несколько топовых специалистов из разных профессиональных областей по машинному обучению, поэтому мы пришли к этому формату. Один человек, который достаточно хорошо знаком с областью и может объяснить суть происходящего, по ходу видео-лекции и разъясняет некоторые нюансы и отвечает на вопросы остальных слушателей.
  • Twitch-трансляция. Один опытный человек в интерактивном режиме показывает свои подходы к решению задачи: как визуализировать, обрабатывать, отбирать данные, обучать модель. Ключевая идея - передача тяжелого, но ценного жизненного опыта.

    Об одном мероприятии, в формате "Тренировки/зарешки", в котором мы непосредственно участвовали, я расскажу и коротко законспектирую. 

Вот такую красивую афишу нам сделали:


   Несколько фотографий для истории:


    А теперь как я и обещал - тот самый конспект выступления о решении соревнования Statoil на Kaggle.
    Смысл соревнования был в классификации снимков на два класса: айсберги и корабли. О том, как снимались эти данные, можно получить представление по левой части слайда. Только вместо самолёта представляем спутник. И соответственно получаем снимки как справа. Эти данные уже так подготовлены, что требуемый нам объект практически всегда находится в центре. Только следует понимать, что это визуализация - не совсем корректное действие, так как многие паттерны в этих снимках глаз практически неспособен уловить. Например, впоследствии мы выяснили, что есть полезная информация из, казалось, простого шума вокруг целевого объекта. То есть, если брать меньшую зону снимка для предсказания, это даёт худшее качество.
   Неприятная особенность этого соревнования заключалась в том, что можно было делать только две отправки решения в день, вместо обычных пяти. Это было связанно с предотвращением пробития leaderboard, то есть понимания участниками реальных классов на публичной части данных, путем подбора правильных ответов перебором возможных вариантов.
    Данных было весьма мало, особенно для направления Deep Learning. Полей также было не так много:

  • id - уникальный хэш для sample,
  • band1 и band2 - снимки,
  • is_iceberg — значение, которое нужно было предсказывать,
  • inc_angle — это свойство помогло выигрывать этот конкурс, но об этом позже. Его физическое значение — это угол, под котором производился снимок относительно перпендикуляра к земле.

    Всего 1604 обучающих примеров в тренировочной выборке. Кораблей и айсбергов примерно равное количество. Выборка была достаточно сбалансированной, что уже неплохо. В тесте было 8424 обучающих примера, но следует понимать, что все это ложь. Почему ложь? Kaggle это любит - в тесте было 5000 сгенерированных изображений в целях предотвращения ручной разметки. Хотя в нашем случае ручная разметка была бы достаточно бесполезным делом, так как данные в очередной раз довольно плохо подготовили и сгенерированные изображения можно было без проблем находить по количеству знаков после запятой у inc_angle. Для сгенерированных было больше десяти, для реальных же только 4.
    Ещё про особенности: очень маленькое количество sample для оценки своего решения в процессе решения соревнования, то есть на leaderboard, всего 685.
    Все это привело к тому, что более опытные товарищи посмотрели на это соревнование и решили не участвовать, так как у многих уже был печальный опыт - не так давно закончилось соревнование Mercedes-Benz Greener Manufacturing. Там также была маленькая выборка и после окончания соревнования произошёл шейк-ап, то есть результат сильно поменялся после открытия приватной части, по которой и оценивались результаты решений. Как это было? Ты был на первом месте на публичной части, а на приватной оказался на последнем и наоборот. Это явление называется overfitting на публичный тест - на новых данных алгоритм не показывает должного качества, поскольку слишком хорошо адаптировался к какой-то подвыборке от оригинальной.


    Так вот, вернёмся к Statoil. Зря они не участвовали. Опыт их подвёл, так как в данных был лик - своеобразная особенность данных, которая практически всегда применима только относительно соревнований и, которую невозможно перенести на реальные решения из жизни. Эта особенность позволила получить хорошее решение и вытянуть его на первые места.
    Теперь подробнее о том, что представлял из себя лик. Как писалось выше, в тесте были сгенерированные изображения. После удаления их можно анализировать реальные данные.
    На изображении выше слева блок с тренировочными данными, справа тест. По оси X просто случайные числа, но тест и трейн не смешивается. По оси Y - величина inc_angle. Цветом выделяется целевая переменная. Для тренировочной - все просто окрашивается с помощью целевой переменной, для тестовой — это бинаризованное по порогу 0,5 предсказание лучшей модели. 
    Как можно увидеть, на этом графике появляются своеобразные полочки, внутри которых предсказание и целевая переменная всегда имеет один и тот же класс. И предсказание модели в большинстве случаев подтверждает эту гипотезу. На всех этих полочках модель показывает один и тот же класс.
    Как оказалось после завершения конкурса, предположение о одинаковом целевом классе на этих полочках было полностью верно.
  У нас было два ключевых подхода к генерации дополнительных фич из имеющихся данных:

  1. Генерация различных нелинейных преобразований, за которыми зачастую бывали какие-то эвристики (для преобразования №1 с картинки - отсечение низкочастотного шума), но как правило их нет, то есть просто перебор.
  2. Вейвлет преобразование.


    Тут все просто - в качестве базовых моделей использовались только 6 сверхточных нейронных сетей. В процессе решения мы сделали интересное наблюдение - никакие сложные структуры, как правило, не давали прироста в качестве, а зачатую только ухудшали его. Вероятно, по 2 причинам: слишком маленькая обучающая выборка и маленький размер исходных снимков.
    Пять из шести наших моделей использовали только простые структуры, что-то вроде 2-3 сверхточных слоя, затем 2 полносвязанных. И только одна предобученная модель VGG16 показала хороший материал, но возможно было это несколько некорректно, так как она в отчие от остальных моделей использовала угол, и возможно уловила лик.
    Также пробовались другие предобученные модели: ResNet50, Xception, Densenet, но они не показали должного качества.
Что сработало


Итого - простые архитектуры, лик и stratified validation по inc_angle  определенно давали прирост качества. Лик и простые модели давали хорошее качество, а правильная валидация давала уверенность.
Что не сработало
Самая веселая часть - что не помогло решению:

  1. Была попытка руками доразметить данные.
    • Выделить глазами плохие/хорошие изображения и подать как метапризнак в модель более высокого уровня.
    • Размерить местонахождение целевого объекта на снимке, чтобы потом сделать модель для предсказания местонахождения объекта.
  2. Статистики, как на исходных снимках  (min, max, mean и тд), так и на размеченных руками областях (из предыдущего пункта), а также просто на отцентрированных изображениях по самому яркому пикселю.
  3. Smooth likelihood.
  4. TTA - усреднение предсказаний одного и того же снимка, но с различными искажениями. Для примера: 360 вариаций одного и того же изображения с вращением его от 1 до 360 градусов.
  5. Pseudo labeling - добавление в обучение примеров из тестовой части, отобранных по какому-либо признаку.
  6. Некоторые виды аугментации, например, слишком сильный поворот изображения (>35 градуса).
  7. Кластеризация изображений, базирующаяся на схожести снимков.

    Далее все это подавалось на стекинг, то есть предсказания от 6 моделей первого уровня являлись метапризнаками для моделей второго уровня - в модели xgboost и lightgbm, которые являлись реализациями градиентного бустинга. Дополнительна фича - агрегация предсказаний имеющихся моделей по inc_angle, дала наибольший прирост качества. Фактически это значило, что модели стабильно могут ошибаться на некоторых значениях этого угла. Но так как у нас было предположение, что в данных есть лик, то эта стабильная ошибка на некоторых углах становилась видна для конечного алгоритма.

  В заключение этой статьи от лица всего Челябинского ML-коммьюнити хочу выразить отдельную благодарность Андрею Шапиро и Дмитрию Ботову, которые организовали описанное мероприятие.

Комментарии

Популярные сообщения из этого блога

Подготовка данных для алгоритмов машинного обучения

Выбор метрики в машинном обучении

Встречайте церковь «Путь будущего»