Pull to refresh

Kaggle: анализ местности Амазонки по спутниковым снимкам

Reading time 6 min
Views 12K
image

Недавно на kaggle.com проходило соревнование Planet understanding the amazon from space
До этого распознаванием изображений не занимался, поэтому подумал, что это отличный шанс научиться работать с картинками. Тем более, что по заверениям людей в чатике, порог вхождения был очень низкий, кто-то даже прозвал датасет «MNIST на стероидах».

Задача


Собственно, с чего начинается каждое соревнование — с постановки проблемы и метрики качества. Задача заключалась в следующем: были даны снимки со спутников местности Амазонки, и для каждого снимка нужно было проставить лейблы: дорога, река, поле, лес, облака, ясное небо и так далее (всего 17 штук). Причем на одной картинке могли одновременно находиться несколько классов. Как видно, кроме типа местности, присутствовали еще и классы, относящиеся к погодным условиям, и, что кажется логичным, погода на снимке может быть только одна. Ну не может быть одновременно и ясно, и облачно. При решении соревнования я не смотрел глазами на данные, надеясь, что машина сама разберется, кто чей брат, поэтому пришлось покопаться, чтобы привести примеры изображений:

image

Baseline


Как такую задачу решать? Взять какую-нибудь сверточную нейронную сеть, предобученную на крупном датасете, и дообучать веса на своем наборе картинок. В теории я, конечно, это слышал, и все тут вроде бы понятно, но взять и реализовать это пока руки не доходили. Ну что же, первым делом нужно выбрать фреймворк для работы. Я пошел по простому пути и использовал keras, так как у него очень хорошая документация и понятный человеческий код.

Теперь немного подробнее про процедуру дообучения весов(в отрасли это называется Fine-tune). Берется сверточная нейронная сеть, например VGG16, обученная на датасете ImageNet, состоящем из нескольких миллионов картинок, предсказывать один из 1000 классов. Ну хорошо, предсказывает она кошку, собаку, машину, ну и что? У нас то классы совсем другие… А смысл в том, что нижние слои нейросети уже умеют распознавать такие базовые компоненты картинки, как линии и градиенты. Нам остаётся лишь удалить верхний слой из 1000 нейронов и поставить вместо него свой из 17 нейронов(именно столько классов может быть на спутниковых снимках).

Таким образом, нейросеть будет предсказывать вероятность каждого из 17 классов. Как по вероятности сказать, есть ли конкретный класс на картинке? Самая простая идея — отсекать по единому порогу: если вероятность больше, чем, например, 0.2, то класс включаем, если меньше — то не включаем. Можно этот порог подобрать для каждого класса отдельно, и я не придумал ничего умнее, чем независимо(что конечно же неправда, улучшение одного порога может влиять на подбор другого) перебирать, как их называли в чате, thresholds.

Сказано — сделано. Результат — топ 90% лидерборда. Да, плохо, но надо же с чего-то начинать. И тут хочется сказать про огромное преимущество соревнований — форум, на котором куча людей, профессионалов и не очень, работают над одной проблемой, и даже публикуются готовые baseline'ы. Из обсуждений я сразу понял, что неправильно файнтюнил. Дело в том, что нужно дообучать веса в два этапа:

  1. «Заморозить» веса всех слоев, кроме последнего(того, что из 17 нейронов) и обучать только его
  2. После того, как лосс упадет до некоторого значения и дальше будет колебаться около него, «разморозить» все веса и обучать сетку целиком

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

Аугментации


Я слышал, что для обогащения датасета можно делать аугментацию — некоторые трансформации подаваемого на вход нейросети изображения. Ну действительно, если мы повернем картинку, то никуда речка или дорога с нее не денутся, но теперь для обучения у нас будет не одна картинка, а целых две. Я решил особо не мудрить и поворачивал картинки только на углы, кратные 90 градусам, а так же отзеркаливал их. Таким образом, размер тренировочного датасета увеличился в 8 раз, что сразу в лучшую сторону отразилось на качестве.
image
Дальше я подумал, почему бы не делать то же самое, но на фазе предсказания: взять выходы сети для преобразованных картинок и усреднить? Кажется, что так предсказания будут более стабильными. Попробовал реализовать, благо поворачивать картинки я уже научился. Неожиданно, но это реально сработало: при той же архитектуре сети я поднялся на лидерборде на 100 строчек. Только потом из чата я узнал, что уже все придумано до меня и такая техника называется Test Time Augmentation.

Ансамбль 1


В последнее время бытует мнение, что для победы в соревновании нужно просто «стакать xgboost'ы». Да, без построения ансамблей вряд ли удастся выйти в топ, но без хорошего фичинженеринга, без грамотной валидации, это просто не даст никакого результата. Поэтому перед тем, как приступить к ансамблированию, нужно проделать немалый объем работы.
Какие модели можно комбинировать в задаче распознавания изображений? Очевидная идея — различные архитектуры сверточных нейросетей. Про их топологии можно почитать в этой статье.

Я использовал следующие:

  • VGG16
  • VGG19
  • Resnet101
  • Resnet152
  • Inception_v3

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

Команда


Худо-бедно, я добрался до границы бронзовой медальки. А тем временем, до конца соревнования оставалась неделя. Именно в это время наступает так называемый merge deadline — момент, после которого запрещается объединение в команды. И вот, 20 минут до deadline'a, я думаю, а почему бы мне, собственно, не объединиться с кем-нибудь в команду? Смотрю на лидерборд, в надежде найти кого-нибудь из чата возле себя. Но никого нет online. Только asanakoy, который на тот момент был на целых 40 строк выше меня. А что, а вдруг? Ну я и написал. Остается 2 минуты до deadline'a — получаю ответ, что asanakoy не против объединиться, если я готов и дальше что-то делать. Артём Санакоев оказался PhD student in Computer Vision с уже имеющимися победами в соревнованиях, что, конечно не могло меня не радовать. Объединение в команды — огромный плюс участия в соревнованиях на kaggle, потому что это позволяет новичкам вроде меня узнавать что-то новое от своих более опытных коллег непосредственно во время совместного решения задачи. Пробуйте участвовать, и если у вас будут хоть небольшие успехи и большое желание что-то делать, то вас обязательно возьмут в команду, где всему научат и все покажут. Ну что же, первое, что хочется после объединения — получить моментальный буст, объединив свои решения. Что мы и сделали, поднявшись при этом на 30 строчек, что было вполне неплохо, учитывая что для этого было приложено минимум усилий. Благодаря Артёму я понял, что сильно недообучал свои сети, и одна его модель в хлам уделывала по качеству все мои вместе взятые. Но было еще время, чтобы с помощью советов своего сокомандника все исправить.

Ансамбль 2


И вот оставалось несколько дней до конца соревнования, Артём уехал на конференцию CVPR, а я остался сидеть с пачкой предсказаний различных сеток. Усреднение — это конечно хорошо, но существуют более продвинутые техники, такие как стекинг. Идея следующая — разбить тренировочный сет, например, на 5 частей, обучать модель на 4 из них, предсказывать на 5й,
и сделать так для всех 5ти фолдов. Поясняющая картинка:

image

Подробнее про стекинг, опять же, на примере соревнования, можно почитать тут.

Как это применить к нашей задаче: есть у нас предсказания вероятностей каждой сети на каждый из 17 классов, итого 6 сетей * 17 классов = 102 признка. Это и будет нашей новой тренировочной выборкой. На полученной таблице я обучал бинарный классификатор для каждого из классов(итого 17 классификаторов). В результате на выходе были вероятности лейблов для каждого снимка. Далее к ним можно применить уже использовавшийся ранее жадный алгоритм. Но, к моему удивлению, стекинг давал результаты хуже, чем простое усреднение. Для себя я это объяснил тем, что у нас были разные разбиения тренировочного сета на фолды — Артём использовал 5 фолдов, а я только 4(чем больше фолдов, тем обычно лучше, но нужно тратить больше времени на обучение моделей). Тогда было решено делать стекинг только на предсказаниях своих нейросетей, а потом взять взвешенную сумму результата с предсказаниями Артёма. В качестве моделей второго уровня использовались: lightgbm, xgboost и трёхслойный персептрон, после чего их выходы усреднялись.

image

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

Итоги


Тем не менее, в результате мы оказались на 17 месте из почти тысячи, что для первого соревнования по deep learning кажется очень неплохо. Золотые медальки начинались с 11 места, и я понял, что мы были реально близки, а решение отличается от топового, возможно, только деталями реализации.

Что еще можно было сделать


  1. На форуме многие писали, что архитектура Densenet показывает очень хорошие результаты, но из-за моей криворукости недостатка опыта, не получилось ее подключить
  2. Сделать единые фолды, да побольше(в чате писали, что делают по 10 фолдов)
  3. Для предсказания погоды можно было использовать не одну модель, а несколько

В заключение, хочется поблагодарить отзывчивое комьюнити чата ods.ai, где всегда можно спросить совета, и почти всегда помогут. Кроме того, двум командам из чата удалось занять 3 и 7 места соответственно.
Tags:
Hubs:
+25
Comments 3
Comments Comments 3

Articles