Когда нужны результаты лучше, чем "удовлетворительно"
Переход зоны из зимнего сезона в летний, составлено из изображений 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 и Körner в статье 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% (пороговые значения могут отличаться для разных зон интереса). После этого, для получения значений пикселей в произвольные дни, используются маски облачности для того, что бы не учитывать такие данные.
Итого, возможны четыре варианта поведения:
- с фильтром снимков, учитывая маски облачности
- без фильтра снимков, учитывая маски облачности
- с фильтром снимков, не учитывая маски облачности
- без фильтра снимков, не учитывая маски облачности
Визуальное отображение стека изображений со спутника 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 из предыдущего шага. После интерполяции, мы совершаем ресемплинг со следующими вариациями:
- Равномерный ресемплинг с интервалом в 16 дней
- Равномерный ресемплинг с интервалом в 8 дней
- Выбор "лучших" дат, количество совпадает со случаем 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 авторы не показывали. Как альтернативу могу предложить следующие источники:
- U-Net: Convolutional Networks for Biomedical Image Segmentation — Olaf Ronneberger, Philipp Fischer, Thomas Brox — одна из базовых статей по архитектуре U-Net, не предполагающая темпоральных данных.
- https://eo-learn.readthedocs.io/en/latest/examples/land-cover-map/SI_LULC_pipeline.html — Страница документации eo-learn, где находится (возможно) более свежая версия конвейеров из 1,2 частей.
- https://github.com/divamgupta/image-segmentation-keras — Репозиторий с несколькими сетями, реализованными при помощи keras. У меня есть некоторые вопросы по поводу реализаций (они несколько отличаются от описанных в оригинальных статьях), но в целом решения легко адаптируются для личных целей и вполне рабочие.