Когда нужны результаты лучше, чем "удовлетворительно"


Часть 1
Часть 2



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


Предисловие


Прошлые пару недель были весьма непростыми. Мы опубликовали первую и вторую части наших статей по поводу классификации покрова в масштабе целой страны при помощи фреймворка eo-learn. eo-learn — это библиотека с открытым исходным кодом для создания прослойки между получением и обработкой снимков со спутников и машинного обучения. В предыдущих статьях в примерах мы указывали только маленькое подмножество данных и показывали результаты лишь на малом проценте всей зоны интереса (AOI — area of interest). Знаю, это выглядит по меньшей мере не слишком впечатляюще, а возможно — весьма грубо с нашей стороны. Всё это время вас мучили вопросы, как можно использовать эти знания и перенести их на следующий уровень.


Не волнуйтесь, именно для этого нужна третья статья в этом цикле! Хватайте чашку кофе, и присаживайтесь...


All our Data are Belong to You!


Вы уже сидите? Может оставьте кофе на столе еще на секунду, потому что сейчас вы услышите лучшие новости за сегодня…
Мы в Sinergise решили опубликовать полный набор данных по Словении за 2017 год. Бесплатно. Вы беспрепятственно можете получить доступ к 200ГБ данных в виде ~300 фрагментов EOPatch, каждый примерно в размере 1000х1000, в разрешении 10м! Подробнее про формат EOPatch можете прочитать в прошлом посте про eo-learn, но по сути это контейнер для гео-темпоральных EO (Earth Observation) и не-EO данных: например, спутниковые снимки, маски, карты, и пр.



Структура EOPatch)


Мы не халтурили, когда загружали эти данные. Каждый EOPatch содержит изображения Sentinel-2 L1C, соответствующую им маску s2cloudless, и официальную карту покрова земли в растровом формате!


Данные хранятся на AWS S3 по адресу: http://eo-learn.sentinel-hub.com/


Десериализация объекта EOPatch довольно проста:


EOPatch.load('path_to_eopatches/eopatch-0x6/')

В результате вы получите объект следующей структуры:


EOPatch(
  data: {
    BANDS: numpy.ndarray(shape=(80, 1010, 999, 6), dtype=float32)
  }
  mask: {
    CLM: numpy.ndarray(shape=(80, 1010, 999, 1), dtype=uint8)
    IS_DATA: numpy.ndarray(shape=(80, 1010, 999, 1), dtype=uint8)
    IS_VALID: numpy.ndarray(shape=(80, 1010, 999, 1), dtype=bool)
  }
  mask_timeless: {
    LULC: numpy.ndarray(shape=(1010, 999, 1), dtype=uint8)
    VALID_COUNT: numpy.ndarray(shape=(1010, 999, 1), dtype=int64)
  }
  meta_info: {
    maxcc: 0.8
    service_type: 'wcs'
    size_x: '10m'
    size_y: '10m'
    time_difference: datetime.timedelta(-1, 86399)
    time_interval: (datetime.datetime(2017, 1, 1, 0, 0), datetime.datetime(2017, 12, 31, 0, 0))
  }
  bbox: BBox(((370230.5261411405, 5085303.344972428), (380225.31836121203, 5095400.767924464)), crs=EPSG:32633)
  timestamp: [datetime.datetime(2017, 1, 1, 10, 4, 7), ..., datetime.datetime(2017, 12, 25, 10, 15, 32)], length=80
)

Доступ к разным атрибутам EOPatch осуществляется следующим образом:


eopatch.timestamp
eopatch.mask['LULC']
eopatch.data['CLM'][0]
eopatch.data['BANDS'][5][..., [3, 2, 1]]

EOExecute Order 66


Отлично, данные загружаются. Пока мы ждём завершения этого процесса, давайте взглянем на возможности класса, который еще не обсуждался в этих статьях — EOExecutor. Этот модуль занимается выполнением и мониторингом конвейера и позволяет без лишних усилий использовать многопоточность. Больше никаких поисков на Stack Overflow о том, как правильно распараллеливать конвейер или как заставлять работать прогресс-бар в таком режиме — мы уже всё сделали за вас!


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



Граф зависимости задач в конвейере, генерируемый eo-learn


Эксперименты с машинным обучением


Как и обещали, эта статья в основном предназначена для исследования разных моделей с eo-learn используя предоставленные нами данные. Ниже мы подготовили два эксперимента, где мы изучаем влияние облаков и разных алгоритмов ресемплинга при темпоральной интерполяции на конечный результат. После всего этого, мы начнём работу со свёрточными сетями (CNN), и сравним результаты двух подходов — попиксельный анализ деревом решений и глубокое обучение при помощи свёрточных нейронных сетей.


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


Играем с облаками


Облака — огромная боль в мире EO, особенно если речь заходит об алгоритмах машинного обучения, где хочется их определить и убрать из набора данных для проведения интерполяции по пропущенным значениям. Но насколько большая выгода от этой процедуры? Стоит ли оно того? Ru?wurm и Korner в статье Multi-Temporal Land Cover Classification with Sequential Recurrent Encoders даже показали, что для глубокого обучения процедура фильтрации облаков возможно абсолютно неважна, поскольку классификатор сам способен обнаруживать облака и игнорировать их.



Активация входного слоя (сверху) и модуляционного слоя (снизу) на последовательности снимков определённого фрагмента для нейронной сети. Можно заметить, что этот фрагмент сети научился сам создавать маски облачности и фильтровать полученные результаты. (Страница 9 в https://www.researchgate.net/publication/322975904_Multi-Temporal_Land_Cover_Classification_with_Sequential_Recurrent_Encoders)


Вкратце напомним структуру шага фильтрации данных (подробности в [предыдущей статье]()). После получения снимков Sentinel-2 мы начинаем фильтровать облачные снимки. Отсеиванию подлежат все снимки, в которых количество не-облачных пикселей не превышает 80% (пороговые значения могут отличаться для разных зон интереса). После этого, для получения значений пикселей в произвольные дни, используются маски облачности для того, что бы не учитывать такие данные.


Итого, возможны четыре варианта поведения:


  1. с фильтром снимков, учитывая маски облачности
  2. без фильтра снимков, учитывая маски облачности
  3. с фильтром снимков, не учитывая маски облачности
  4. без фильтра снимков, не учитывая маски облачности


Визуальное отображение стека изображений со спутника Sentinel-2. Прозрачные пиксели слева подразумевают пропавшие пиксели ввиду облачности. Стек по центру показывает значения пикселей после фильтрации снимков и их интерполяции с маской облачности (Случай 4), а стек справа показывает результат интерполяции в случае без фильтрации снимков и без масок облачности (1). (Прим. пер. — судя по всему, в статье опечатка, и подразумевалось наоборот — по центру случай 1, а справа — 4).


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


Результаты указаны в таблице ниже. Можно заметить, что в целом влияние облаков на результат работы модели достаточно низок! Это может быть связано с тем, что референсная карта очень хорошего качества и модель способна игнорировать большую часть снимков. В любом случае, такое поведение нельзя гарантировать для любой AOI, так что не торопитесь выбрасывать этот шаг из своих моделей!


Model Точность [%] F_1 [%]
Без фильтров, без маски 92.8 92.6
Без фильтров, с маской 94.2 93.9
С фильтром, без маски 94.0 93.8
С фильтром, с маской 94.4 94.1

Влияние разных подходов к ресемплингу


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


Для этого эксперимента, будем использовать вариацию 1 из предыдущего шага. После интерполяции, мы совершаем ресемплинг со следующими вариациями:


  1. Равномерный ресемплинг с интервалом в 16 дней
  2. Равномерный ресемплинг с интервалом в 8 дней
  3. Выбор "лучших" дат, количество совпадает со случаем 2.

Выборка в случае 3 базируется на самом большом количестве общих дат для всех EOPatch в выбранной AOI

График показывает количество фрагментов EOPatch, которые содержат данные за каждый день 2017 года (синий). Красными линиями показаны оптимальные даты для ресемплинга, которые базируются на датах снимков Sentinel-2 для заданной AOI 2017 года.


Взглянув на таблицу ниже, можно заметить, что результаты не слишком впечатляющие, как и в прошлом опыте. Для случаев 2 и 3 количество затраченного времени вырастает примерно вдвое, но при этом разница с начальным подходом составляет меньше 1%. Подобные улучшения слишком незаметны для практического применения, так что можно считать 16-дневный интервал подходящим для задачи.


Model Точность [%] F_1 [%]
Равномерно каждые 16 дней 94.4 94.1
Равномерно каждые 8 дней 94.5 94.3
Выбор лучших дат 94.6 94.4

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


Глубокое обучение: используем свёрточную нейронную сеть (CNN)


Глубокое обучение стало стандартным подходом к многим задачам, таким как компьютерное зрение, обработка текстов на естественных языках, и обработка сигналов. Это связано с их способностью выделять шаблоны из сложных многомерных входных данных. Классические подходы машинного обучения (такие, как деревья решений) использовались во многих задачах, связанных с темпоральными геоданными. С другой стороны, свёрточные сети использовали для анализа пространственной корреляции между соседними снимками. В основном, их применение ограничивалось работой с единичными снимками.


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


Для этого, мы использовали темпоральные полносвёрточные сети (Temporal Fully-Convolutional Netvork, TFCN), а точнее, темпоральное расширение к U-Net, реализованную в TensorFlow. Если точнее, архитектура использует пространственно-временные корреляции для улучшения результата. Дополнительным преимуществом также является то, что структура сети позволяет лучше представить пространственные отношения в разных масштабах благодаря процессу кодирования\декодирования в U-net. Так же, как и в классических моделях, на выходе мы получаем двухмерную матрицу меток, которую будем сравнивать с истиной.



Натренированную модель мы использовали для предсказания меток на тестовом множестве, и полученные значения проверили с истиной. В целом точность составила 84.4% и F1 была равна 85.4%.



Сравнение разных предсказаний для нашей задачи. Визуальное изображение (левое сверху), истинная референсная карта (справа сверху), предсказание модели LightGBM(снизу слева) и предсказание при помощи U-net(снизу справа)


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


Другие эксперименты


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


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


От переводчика


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


  1. U-Net: Convolutional Networks for Biomedical Image Segmentation — Olaf Ronneberger, Philipp Fischer, Thomas Brox — одна из базовых статей по архитектуре U-Net, не предполагающая темпоральных данных.
  2. https://eo-learn.readthedocs.io/en/latest/examples/land-cover-map/SI_LULC_pipeline.html — Страница документации eo-learn, где находится (возможно) более свежая версия конвейеров из 1,2 частей.
  3. https://github.com/divamgupta/image-segmentation-keras — Репозиторий с несколькими сетями, реализованными при помощи keras. У меня есть некоторые вопросы по поводу реализаций (они несколько отличаются от описанных в оригинальных статьях), но в целом решения легко адаптируются для личных целей и вполне рабочие.

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