Русский
Русский
English
Статистика
Реклама

Big data

Расчет факторов в антифроде. Доклад Яндекса

04.07.2020 12:05:52 | Автор: admin
Антифрод сервис по поиску и нивелированию случаев эксплуатации других, общедоступных сервисов Яндекса. Три года назад мы начали проектировать платформу, позволяющую быстро и легко развернуть антифрод где угодно в компании. Сложность задачи в том, что многим сервисам нужны максимально строгие гарантии по скорости, надежности и качеству; часть из них оперирует очень большими объемами данных. Команде антифрода, в свою очередь, важна гибкость системы, простота поддержки и выразительность факторов, на которых будет строиться машинное обучение.


Руководитель антифрода Андрей Попов выступил с докладом о том, как мы смогли выполнить все эти противоречивые требования. Центральная тема доклада модель вычисления сложных факторов на потоке данных и обеспечение отказоустойчивости системы. Также Андрей кратко описал следующую, еще более быструю итерацию антифрода, которую мы сейчас разрабатываем.

Команда антифрода, по сути, решает задачу бинарной классификации. Поэтому доклад может быть интересен не только специалистам по борьбе с фродом, но и тем, кто делает разнообразные системы, в которых нужны быстрые, надежные и гибкие факторы на больших объемах данных.

Привет, меня зовут Андрей. Я работаю в Яндексе, руковожу разработкой антифрода. Мне сказали, что люди предпочитают использовать слово фичи, поэтому везде в докладе я буду упоминать его, но название и вступление остались старыми, со словом факторы.

Что такое антифрод?


Что вообще такое антифрод? Думаю, проще всего показать.

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

С чем вообще борется антифрод? Пара примеров.

Например, имитация действий пользователя. Этим занимаются ребята, которых мы называем черные SEO, те, кто не хочет улучшать качество сайта и контент на сайте. Вместо этого они пишут роботов, которые ходят на поиск Яндекса, кликают по их сайту. Они расчитывают, что так их сайт поднимется выше. На всякий случай напоминаю, что такие действия противоречат пользовательскому соглашению и могут привести к серьезным санкциям со стороны Яндекса.



Или, например, накрутка отзывов. Такой отзыв можно увидеть у организации на Картах, которая ставят пластиковые окна. За этот отзыв она же сама и заплатила.

Верхнеуровнево архитектура антифрода выглядит так: некоторый набор сырых событий попадают в саму система антифрод как в черный ящик. На выходе из него генерируются размеченные события.

У Яндекса много сервисов. Все они, особенно большие, так или иначе сталкиваются с разными видами фрода. Поиск, Маркет, Карты и десятки других.

Где мы были еще года два-три назад? Каждая команда выживала под натиском фрода как могла. Она генерировала свои команды антифрода, свои системы, которые не всегда работали хорошо, были не очень удобны для взаимодействия с аналитиками. И главное, они были слабо проинтегрированы между собой.

Я хочу рассказать, как мы это решили созданием единой платформы.



Зачем нам нужна единая платформа? Переиспользование опыта и данных. Централизация опыта и данных в одном месте позволяет быстрее и качественнее реагировать на крупные атаки они обычно бывают кросс-сервисными.

Единый инструментарий. У людей есть инструменты, к которым они привыкли. И, очевидно, скорость подключения. Если мы запустили новый сервис, на который сейчас происходит активная атака, то должны быстро подключить к нему качественный антифрод.

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

Расскажу немного про то, как мы классифицируем антифроды.



Это может быть офлайн-система, которая считает часы, дни и тяжелые офлайн-процессы: например, сложные кластеризации или сложное переобучение. Этой части я практически не буду касаться в докладе. Есть near real-time-часть, которая работает за единицы минут. Это некая золотая середина, у нее быстрая реакция и тяжеловесные методы. В первую очередь я остановлюсь на ней. Но не менее важно сказать, что на этом этапе мы используем данные с этапа уровнем выше.

Есть и онлайн-части, необходимые в тех местах, где требуется быстрая реакция и критично отсеять фрод еще до того, как мы приняли событие и передали его пользователю. Здесь мы вновь переиспользуем данные и алгоритмы машинного обучения, посчитанного на более высоких уровнях.

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

Я практически не буду касаться самих ML-методов. В основном я буду рассказывать о платформах, создающих фичи, которые мы потом используем в обучении.

Кому это может быть интересно? Очевидно, тем, кто пишет антифрод или борется с мошенниками. Но также и тем, кто просто запускает поток данных и считает фичи, считает ML. Так как мы сделали достаточно общую систему, может быть, что-то из этого вам будет интересно.

Какие у системы требования? Их достаточно много, вот некоторые из них:

Большой поток данных. Мы обрабатываем сотни миллионов событий за пять минут.
Полностью конфигурируемые фичи.
Декларативный язык описания факторов.
Конечно же, кросс-ДЦ и exactly-once-обработка данных, которая нужна для некоторых сервисов. Удобная инфраструктура как для аналитиков, которые подбирают итоговые фичи, обучают модели и подобное, так и для разработчиков, которые поддерживают систему.
И, конечно, скорость.

Дальше расскажу про каждый из этих пунктов в отдельности.

Так как я из соображений безопасности не могу рассказывать про реальные сервисы, давайте представлю новый сервис Яндекса. На самом деле нет, забудьте, это выдуманный сервис, который я придумал для показа примеров. Пусть это сервис, на котором у людей есть база всех существующих книг. Они заходят, ставят оценки от одного до десяти, и злоумышленники хотят влиять на итоговый рейтинг, чтобы их книги покупали.

Все совпадения с реальными сервисами, естественно, случайны. Рассмотрим в первую очередь near real-time-версию, так как онлайн конкретно здесь не нужен при первом приближении.

Большие данные



В Яндексе есть классический способ решения проблем с большими данными: использовать MapReduce. Мы используем нашу собственную реализацию MapReduce, называется YT. Кстати, у Максима Ахмедова сегодня вечером рассказ про нее. Вы можете использовать вашу реализацию либо опенсорсную реализацию вроде Hadoop.

Почему мы сразу не используем онлайн-версию? Она не всегда нужна, может усложнять пересчеты в прошлое. Если мы добавили новый алгоритм, новые фичи, мы хотим часто пересчитать данные в прошлое, чтобы изменить вердикты по ней. Сложнее использовать тяжеловесные методы думаю понятно, почему. И онлайн-версия по ряду причин может быть более требовательна по ресурсам.

Если мы используем MapReduce, получается примерно такая схема. Мы используем некий минибатчинг, то есть делим на максимально маленькие куски батчей. В данном случае это одна минута. Но те, кто работает с MapReduce, знают, что меньше этого размера, наверное, уже возникают слишком большие оверхеды самой системы накладные расходы. Условно, она не сможет справляться с обработкой за одну минуту.

Дальше мы над этим набором батчей запускаем набор Reduce и получаем размеченный батч.



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

Почему не использовать методы приблизительного подсчета? Короткий ответ: мы их тоже используем, но иногда в задачах антифрода важно иметь именно точное значение за какие-то интервалы. Например, разница между двумя и тремя прочитанными книгами может быть весьма существенна для тех или иных методов.

Как следствие, нам нужна большая история данных, в которой мы будем хранить эти статистики.



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

Те из вас, кто работает с MapReduce, наверное, знают, что такое может работать достаточно плохо. Если история может быть в сотни, а то и в тысячи, в десятки тысяч раз больше, чем сам батч, то такой процессинг может работать пропорционально размеру истории, а не размеру батча.



Заменим это на некий key-value store. Это вновь наша собственная реализация, key-value-хранилище, но она хранит данные в памяти. Наверное, ближайший аналог какой-нибудь Redis. Но у нас тут получается небольшое преимущество: наша реализация key-value store очень сильно проинтегрирована с MapReduce и кластером MapReduce, на котором это запускается. Получается удобная транзакционность, удобная передача данных между ними.

Но общая схема что мы в каждом джобе этого Reduce будем ходить в этот key-value storage, обновлять данные и записывать обратно после формирования вердикта по ним.

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

Конфигурируемые фичи


Немного о том, как мы конфигурируем фичи. Простых счетчиков часто бывает недостаточно. Для поиска мошенников нужны достаточно разнообразные фичи, нужна умная и удобная система по их конфигурированию.

Давайте разобьем на три этапа:
Extract, где мы изымаем данные для данного ключа и из лога.
Merge, где мы сливаем эти данные со статистикой, которая находится в истории.
Build, где мы формируем итоговое значение фичи.

Давайте, например, посчитаем процент детективов, прочитанных пользователем.



Если пользователь читает слишком много детективов, он слишком подозрительный. Никогда непонятно, чего от него ждать. Тогда Extract изъятие количества детективов, которые прочел пользователь в этом батче. Merge взятие всех детективов, всех этих данных из батчей за месяц. И Build это какая-то сумма.

Затем мы то же самое делаем для значения всех книг, которые он прочитал, и в итоге получаем деление.

А если мы хотим посчитать разные значения, например, количество различных авторов, которых читает пользователь?





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



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

Давайте, например, введем вот такие разрезы пользователь, автор и жанр.



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

Это может быть потенциальный сигнал. Он, конечно, может означать, что автор просто такой: вокруг него одни фанаты, все, кто его читают, читают только его. Но также это может значить, что сам автор пытается накручивать систему и создает этих фейковых пользователей, которые якобы его читают.

Давайте попробуем это посчитать. Посчитаем фичу, которая считает количество различных авторов за большой интервал. Например, здесь второе и третье значение кажутся нам подозрительными, их слишком мало.



Тогда посчитаем среднее значение по авторам, которые связаны за большой интервал. И тогда здесь среднее значение опять же достаточно низкое: 3. Этот автор нам почему-то кажется подозрительным.



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

Понятно, что само по себе это не может являться явным критерием, что пользователя надо фильтровать или что-то такое. Но это может быть один из сигналов, который мы можем использовать.

Как это сделать в парадигме MapReduce? Давайте сделаем несколько последовательных редьюсов и зависимости между ними.



У нас получается граф редьюсов. Он влияет на то, по каким срезам мы считаем фичи, какие джойны вообще допустимы, на количество потребляемы ресурсов: очевидно, чем больше редьюсов, тем больше ресурсов. И Latency, throughput.

Построим, например, такой граф.



То есть разобьем на два этапа редьюсы, которые у нас есть. На первом этапе мы посчитаем параллельно разные редьюсы по разным разрезам наши пользователи, авторы и жанр. И нам нужен какой-то второй этап, где мы соберем фичи из этих разных редьюсов и примем итоговый вердикт.

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

Здесь важно, что у нас нет вот такой зависимости:



То есть у нас фактически получается конвейер. То есть первый этап следующего батча может работать параллельно со вторым этапом первого батча.

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



Второе значение на первом этапе батча N+1, и итоговое значение нужно считать на втором этапе батча N+1. Таким образом, при переходе между первым этапом и вторым будут, может быть, не совсем точные статистики для батча N+1. Но обычно этого достаточно для подобных расчетов.



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



К этому добавляется то, что мы называем отношениями между событиями. Часто у нас в логах или в данных, которые нам посылаются, появляются дубликаты. Это могут быть либо технические события, либо роботное поведение. Мы такие дубликаты также обнаруживаем. Или, например, какие-то связанные события. Скажем, у вас в системе показываются рекомендации книг, и пользователи кликают по этим рекомендациям. Чтобы итоговые статистики, которые влияют на ранжирование, не портились, нам нужно следить, что если мы отфильтруем показ, то должны отфильтровать и клик по текущей рекомендации.

Но так как поток у нас может приходить неравномерно, сначала клик, то мы должны его отложить до момента, пока мы не увидим показ и не примем вердикт на его основе.

Язык описания фич


Расскажу немного про язык описания всего этого.



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



Это какая-то фича, nullable-число.



И какое-то правило. Что мы называем правилом? Это набор условий на этих фичах и что-то еще. Было у нас три отдельных файла.

Проблема в том, что тут одна цепочка действий разнесена по разным файлам. С нашей системой нужно работать большому количеству аналитиков. Им было неудобно.

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

Решение давайте сделаем свой DSL. Он более понятно описывает наш сценарий, он проще для новых людей, он более высокоуровневый. Вдохновение мы брали у SQLAlchemy, C# Linq и подобного.

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



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



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



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



К этому мы потом можем добавить условие фильтрации. То есть фильтр у нас может быть, например, таким: лояльность не слишком высокая и количество процентов детективов между 80 из 100.

Что мы для этого используем под капотом?



Под капотом мы используем самые современные технологии, напрямую из 70-х годов, такие как Flex, Bison. Может быть, слышали. Они генерируют код. У нас файл с кодом проходит через наш лексер, который сгенерирован во Flex, и через парсер, который сгенерирован в Bison. Лексер генерирует терминальные символы или слова в языке, парсер генерирует синтаксические выражения.

Из этого мы получаем абстрактное синтаксическое дерево, с которым уже можем делать преобразования. И в итоге превращаем это в низкоуровневые файлы, которые понимает система.

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

Надежность


Некоторые сервисы требуют отказоустойчивости: кросс-ДЦ и exactly-once-обработку. Нарушение может вызывать расхождение статистик и потери, в том числе денежные. Наше решение для MapReduce такое, что мы считаем данные в каждый момент времени только на одном кластере и синхронизируем их на второй.



Например, как бы мы вели себя здесь? Есть лидер, follower и message broker. Можно считать, что это условная кафка, хотя тут, конечно, собственная реализация.



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

Раз в какое-то время мы, естественно, должны сделать репликацию. То есть мы собираем снапшоты, собираем ченжлоги изменения за каждый батч. И то, и то синхронизируем на второй кластер follower. И также поднимаем историю, которая находится в таком горячем состоянии. Напомню, что история здесь хранится в памяти.

Таким образом, если один ДЦ почему-то становится недоступен, мы можем достаточно быстро, с минимальным лагом, переключиться на второй кластер.

Почему бы вообще не считать на двух кластерах параллельно? Внешние данные могут отличаться на двух кластерах, поставлять их могут внешние сервисы. Что вообще такое внешние данные? Это что-то, что с вот этого более высокого уровня поднимается. То есть сложные кластеризации и подобное. Либо просто вспомогательные для расчетов данные.

Нам нужно согласованное решение. Если мы будем параллельно считать вердикты с использованием разных данных и периодически переключаться между результатами из двух разных кластеров, согласованность между ними будет сильно падать. И, конечно же, экономия ресурсов. Так как мы в каждый момент времени используем ресурсы CPU только на одном кластере.

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



В случае недоступности кластера мы меняем эти инсталляции с прода на препрод. Таким образом, препрод у нас какое-то время лежит, но ничего страшного.

Преимущество мы можем на препроде считать больше фичей. Почему это вообще нужно? Потому что понятно, что если мы хотим большой объем фич считать, то нам часто не нужно все их считать на проде. Там мы считаем только то, что нужно для получения итоговых вердиктов.

(00:25:12)

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

К этому добавляются преимущества B2B-тестирования. То есть мы все выкатываем, естественно, сначала на препрод. Полностью сравниваем любые отличия, и, таким образом, не ошибемся, минимизируем вероятность, что мы можем ошибиться при выкатке на прод.

Немного про планировщик. Понятно, что у нас есть какие-то машины, которые запускают задачу в MapReduce. Это некие воркеры. Они регулярно синхронизируют свои данные в Cross-DC Database. Это просто состояние того, что они успели посчитать на данный момент.



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



Переподняться с него и продолжить работу. Продолжить ставить задачи на этом MapReduce.



Понятно, что в случае переподнятия этих задач, некоторое множество из них может перезапуститься. Поэтому здесь есть очень важное свойство для нас: идемпотентность, возможность перезапускать каждую операцию без последствий.

То есть весь код должен быть написан так, чтобы это нормально работало.



Немножко расскажу про exactly-once. Мы выносим вердикт согласованно, это очень важно. Используем технологии, которые дают нам такие гарантии, и мониторим, естественно, все расхождения, сводим их к нулю. Даже когда кажется, что это уже сведено, периодически возникает очень хитрая проблема, которую мы не учли.

Инструменты


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



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



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



Что мы вообще мониторим? Очевидно, лаг системы крайне важен. Очевидно, время работы каждой отдельной стадии и, конечно же, фильтрация отдельных правил. Это бизнесовое требование.

Возникают сотни графиков, дашборды. Например, на этом дашборде видно, что контуру сейчас было достаточно плохо, что мы набрали существенный лаг.

Скорость


Расскажу про переход в онлайн-часть. Тут проблема в том, что лаг в полноценном контуре может достигать единиц минут. Это в контуре на MapReduce. В некоторых случаях нам нужно банить, обнаруживать мошенников быстрее.

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



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

В такой схеме может возникнуть следующая проблема.



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

Тогда мы из этого key-value storage считаем данные на оба воркера из истории, мы его обновим по-разному и возникнет гонка при попытке записать обратно.

Решение: давайте сделаем предположение, что можно разделить чтение и запись, что запись может происходить с небольшой задержкой. Обычно это не сильно важно. Под небольшой задержкой я здесь подразумеваю единицы секунд. Это важно, в частности, по той причине, что наша реализация этой key-value store занимает больше времени на запись данных, чем на чтение.

Будем обновлять статистики с отставанием. В среднем это работает более-менее хорошо, с учетом того, что мы будем хранить на машинах кэшированное состояние.



И другая вещь. Для простоты сольем вот эти истории в одну и пошардируем ее по типу и по ключу разреза. У нас есть какая-то единая история.

Тогда мы вновь добавим балансер, добавим машины читателей, которые могут быть пошардированы как угодно например, просто по нагрузке. Они будут просто читать эти данные, принимать итоговые вердикты и возвращать их балансеру.

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



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

Здесь у него меняется его предназначение. Он больше не принимает вердикты. Вместо этого он просто принимает updates из Reader, смешивает их и правильно применяет к истории.

Понятно, что здесь нужна компонента, координатор, которая распределяет эти updates между ридерами и райтерами.

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



Что мы вообще получили? Аналитики стали делать работу быстрее и одинаково для всех сервисов. Это повысило качество и связанность всех систем. Можно переиспользовать данные между антифродами разных сервисов, а новые сервисы получают качественный антифрод быстро.



Пара мыслей в конце. Если вы будете писать нечто подобное, сразу подумайте про удобство аналитиков в части поддержки и расширяемости данных систем. Делайте конфигурируемым все что можно, это вам понадобится. Иногда свойств кросс-ДЦ и exactly-once бывает сложно достичь, но можно. Если вам кажется, что уже достигли, перепроверьте. Спасибо за внимание.
Подробнее..

Видеоаналитика в нефтехимии

02.07.2020 14:05:51 | Автор: admin
Привет!

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



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

Откуда мы берем данные


На каждом объекте у нас несколько сотен камер в технологическом периметре, о котором мы будем говорить. Существует ещё периметр, в который входят камеры службы безопасности, но о нем пока рассказывать не будем :). А вот так называемые производственные камеры, которые постоянно смотрят на тот или иной участок, узел, оборудование это именно то, на чем будет фокус.

Наши заводы разного возраста, и было время, когда не все они принадлежали СИБУРу. В течение предыдущих 15 лет активно проводилась их модернизация, и сейчас сложилась ситуация, когда на разных заводах могут быть разные камеры и системы работы с ними. Соответственно, каждый оператор на таких объектах привык к конкретному софту и привычной для него выдаче видеопотоков.

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

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

Пользователи нашей системы


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

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

Так и здесь оператор в состоянии заметить на видео что-то, что через 5 минут бездействия выльется в аварийный останов и убытки для компании. Или в ещё что-нибудь не очень полезное.



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

А ещё, конечно же, видеонаблюдение это безопасность труда. Когда описывают подобные кейсы, очень любят приводить в пример случаи, когда система в состоянии распознать, в каске человек или нет. Возможно, красиво звучит для людей, оторванных от производства. Реальность же такова, что на серьёзных объектах у сотрудников уровень самодисциплины вполне достаточен для того, чтобы понимать: раз каска нужна, значит, она должна быть на голове, ровно как и другие элементы СИЗ.

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



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



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

Первое предсказания. Куда ж без этого. Раз мы собираем записи о каких-то ситуациях, значит, у нас есть архив этих записей, их можно использовать. Например, те же забивки: собираем статистику о том, как они происходят, где чаще всего, какие это именно забивки и прочее, какова их интенсивность. Потом соединяем полученные данные с информацией, собранной с датчиков. Затем идём к коллегам, которые занимаются построение предиктивных моделей, и получаем возможность намного точнее предсказывать забивки и корректировать техпроцесс еще до того, как появятся их первые признаки.

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

Так как работает сама система?


С учётом географии нашей работы, собирать все видеопотоки в Москве и обрабатывать их тут мы не можем. Поэтому система у нас распределённая, мы должны ставить её максимально близко к видеопотокам, в противном случае имеющейся сети не хватит для передачи данных. Тут у нас часто спрашивают почему вы не хотите использовать камеры, позволяющие проводить предварительную аналитику непосредственно на камере? Хотим! :) Но! Здесь сразу два фактора, по которым обработка на камерах остается делом красивым, но трудно достижимым в большинстве случаев.

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

Во-вторых, остановка производства. Если у нас появляется возможность заменить камеры на более современные, без пауз в работе производства пойти и установить новое необходимое железо нельзя. Процесс поиска подходящего технологического окна тоже оттягивает внедрение.

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



Отдельный интерес для нас представляет решение задачи по непосредственно анализу сигнала. Тут сразу стоит оговориться, не все модели анализа изображений работающие в СИБУРе разработаны с нуля внутри. В соответствии с нашей парадигмой использования по максимуму того, что есть, мы активно используем результаты работы моделей, которые уже есть в системах видеонаблюдения или в системах видеоаналитики от других компаний. Но в случае если установленных моделей нет, нам нужно найти/разработать что-то новое. Для этого на этапе проектирования системы мы разработали и зафиксировали программный интерфейс для модели.

Это дало нам возможность привлекать сторонних разработчиков и быстро интегрировать такие классные штуки как OpenVINO. Спектр решаемых задач в распознавании у нас очень широк. Начиная с классических задач детектирования и классификации в rgb пространстве (анализ появления агломератов на виброситах), продолжая трекингом объектов (анализ пересортицы продукта) и заканчивая работой с rgbd при анализе потока с камер для контроля работы манипуляторов.



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

Сама же разработка у нас ведётся на Python, как бека, так и моделей. Разворачивание преимущественно в Docker.

Результаты


Проект запущен чуть больше года назад, за это время нам уже удалось внедрить своё ПО на наших производствах в Томске, Тобольске, Воронеже.

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

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



Например, такое возможно с полипропиленом. Конечный этап производства у нас это гранулы полипропилена, которые вы видели в наших других постах и роликах. Их удобно насыпать в мешки, транспортировать, засыпать в ёмкости, они соответствуют заявленным ТТХ. А вот если вовремя не заметить и не обработать ситуацию с забивкой, получится другой продукт. Будет сыпаться агломерат, гранулы начнут слипаться. Это всё тот же полипропилен, но из-за таких косяков при производстве это уже другая марка продукта. Само собой, более дешёвая.

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

Планы на будущее


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

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

Фидбек же от операторов приходит по большой части позитивный. Если бы мы решили делать систему, отталкиваясь от парадигмы А теперь вы все будете работать вот в этой новой штуке, он был бы, скорее всего, немного иным.
Подробнее..

На пути к индивидуальному образованию анализ данных Яндекс.Репетитора

25.06.2020 10:15:49 | Автор: admin



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


Такой инструмент позволил бы экономить огромное количество времени и при этом добиваться значительно лучших результатов. Эффективность обмена знаниями значительно повысилась бы, а вслед за этим ускорился бы и прогресс.


Но пока человечество совершает лишь робкие попытки подобраться к пониманию, как создавать такой инструмент. Свою попытку осуществила и команда Яндекс.Репетитора. Сервис, запущенный менее двух лет назад, накопил данные о ста миллионах решений различных задач, и этого достаточно для интересной аналитики. Понятно, что образование состоит не только из задач, но сегодня мы сфокусируемся на них.


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


1. Почему персонализированное образование это сложно


Построение современной персонализованной образовательной системы сложная задача. С точки зрения специалиста по анализу данных ситуация выглядит так:


  • Образовательные процессы предполагают чрезвычайно длительный feedback loop: воздействие производим прямо сейчас (выдаём задачку пятикласснику), результат наблюдаем очень нескоро (поступит ли он в МГУ, заработает ли миллион?). Это ограничивает число доступных наблюдений, затрудняет эксперименты и неблагоприятно сказывается на актуальности моделей: современным пятиклассникам нужно не то же самое, что пятиклассникам пять лет назад.
  • Образовательные данные очень шумные, их мало, к тому же они нерепрезентативны. Результаты обусловлены огромным числом ненаблюдаемых факторов (исторический момент, социальная среда, семья, друзья, дополнительные и самостоятельные занятия...) и доступны, как правило, только для небольших и очень разрозненных групп людей.
  • Exploration ограничен: чтобы получить данные для обучения моделей, нельзя обязать миллионы людей использовать случайные или просто существенно субоптимальные образовательные стратегии.
  • Объём доступного образовательного контента, который подходит для глубокой персонализации, незначителен. В лучшем случае контент производится с прицелом на несколько крупных и очевидных пользовательских групп. Например, это могут быть материалы курсов по ML для трёх типов людей:
    без математического образования,
    с математическим образованием и при этом новичков в ML,
    для людей, уже глубоко погруженных в ту или иную область.

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

2. Яндекс.Репетитор


Список выше можно продолжать, но перечисленные в нём проблемы поддаются решению. На мой взгляд, хороший план может выглядеть так:


  1. Рассматриваем одну очень простую задачу с коротким feedback loop, решение которой при этом будет востребовано широкими массами пользователей. Например, такой задачей может быть подготовка к выпускным школьным экзаменам: всякий школьник очень хочет получше сдать ОГЭ и ЕГЭ. Скорость фидбэка обеспечим так: индивидуальным событием будет успешность или неуспешность решения очередной предложенной задачи. Тестовый характер большинства заданий снимает сложности с анализом успешности решений.
  2. Создаваемый сервис должен быть популярен, чтобы покрыть максимально возможное количество пользователей. При этом он должен качественно логировать все события, чтобы в дальнейшем можно было учитывать их при создании моделей.
  3. Вместо того чтобы осуществлять честный exploration, можно просто сравнивать разные стратегии подбора заданий для пользователей. Если в их показателях будут статистически значимые различия вероятно, в будущем мы справимся с построением оптимальных стратегий.
  4. Тогда единицей контента будет являться конкретная задача. За годы создано создано огромное количество задач в области ОГЭ и ЕГЭ, и построение персональных наборов задач кажется очень содержательной работой. Ясно, что у всех разный уровень подготовки, и можно было бы строить рекомендации, исходя из сильных и слабых сторон каждого конкретного школьника.
  5. Когда работоспособность методов и моделей будет показана на примере задачи подготовки к ЕГЭ, мы сможем намного смелее подступаться и к другим дисциплинам, постепенно расширяя границы применимости рекомендательных моделей.

Исходя из таких рассуждений и появился сервис Яндекс.Репетитор. Это, в общем-то, большой задачник для школьников, готовящихся к ЕГЭ или ОГЭ. Школьные задачи можно решать по отдельности или в составе вариантов. Конечно, можно и просто смотреть разборы или оставлять задачи без ответов. При анализе такие случаи потребуется отбрасывать.


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



Ссылка на этот блок


В нём демонстрируются задания, подбираемые разными вариантами алгоритмов.


3. Простейшая аналитика


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


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




Но это всё лежит на поверхности и даже не требует создания нового сервиса хватило бы и анализа данных веб-поиска.


4. Бесконтекстные модели сложности


В простейшем случае показателем сложности задачи может служить средняя успешность её решений: задача, где верными оказались 40% ответов, почти наверняка сложнее задачи, где тот же показатель составляет 60%.


Но такой анализ слишком прост и не учитывает разного уровня подготовки пользователей. Простой пример: задачи тестовой части ЕГЭ по математике профильного уровня решаются в среднем существенно успешнее задач базового уровня. Конечно, из этого нельзя делать вывод, что задачи профильного уровня легче. Просто их решают более подготовленные школьники, для которых сложность не в задачах тестовой части.


Поэтому потребуется более комплексная модель. Первой рассмотрим рейтинговую модель, которую уже давно придумали в шахматах, адаптировали к олимпиадному программированию, баскетболу и многим другим областям.


Введём обозначения:


  • $U=\{u_1,u_2,...,u_n\}$ множество пользователей;
  • $T=\{t_1,t_2,...,t_m\}$ множество задач;
  • $X=\{x_1,x_2,...,x_N\}$, где $x_k = (u_{i_k}, t_{j_k}, a_k)$, множество решений.

Каждая тройка $(u_{i_k}, t_{j_k}, a_k)$ из множества $X$ трактуется так, что пользователь $u_{i_k}$ решал задачу $t_{j_k}$ и дал верный ответ, если $r_k = 1$ и неверный, если $a_k = 0$.


Сопоставим каждому пользователю и каждой задаче рейтинг некоторое вещественное число. Точнее, определим функцию $r:U \cup T \rightarrow \mathbb{R}$, значения которой и будем называть рейтингами. Скажем, что разница рейтингов пользователя и задачи должна предсказывать вероятность верного решения:


$P_r(a_k = 1) = \frac{1}{1 + \exp\Big(r(t_{j_k}) - r(u_{i_k})\Big)}$


Обозначим через $P_r(x_k)$ вероятность верной классификации:


$P_r(x_k) = a_k \cdot P_r(a_k = 1) + (1 - a_k) \cdot \Big(1 - P_r(a_k = 1)\Big)$


Выбирать значения рейтингов будем простым методом максимального правдоподобия:


$r = \arg \max_{r' : U \cup T \rightarrow \mathbb{R}} \prod_{k=1}^{N}P_{r'}(x_k)$


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


Конечно, можно строить отдельные рейтинги для пользователей в рамках различных тематик. Скажем, школьник может очень хорошо справляться со стереометрическими задачами и при этом плохо с задачами по теории вероятностей. Описанный метод вполне подходит и для этого.


Приведу пример результата вычисления рейтингов для отдельных номеров задач ЕГЭ по матетатике базового уровня и пользователей Яндекс.Репетитора. Чтобы он был насколько-то обозрим, я оставил только четыре группы задач: две самых сложных и две самых простых.


Я привожу три характеристики для каждой темы:


  • сложность величину рейтинга этой темы;
  • долю верных решений среди всех решений всех задач, относящихся к этой теме;
  • средний рейтинг пользователей, решавших задачи из этой темы.


Например, в среднем стереометрические задачи решают верно чаще, чем задачи на смекалку (64% и 61% верных ответов соответственно), но именно стереометрия оказывается наиболее сложной темой. Причём задания в ней решают более сильные школьники: средний рейтинг пользователей, решающих задачи по стереометрии, оказался равен 0,32, тогда как задачи на смекалку решают пользователи со средним рейтингом -0,25. Таким образом, анализ сложности заданий требует анализа способностей пользователей, и это очень ценный вывод.


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



Хорошо видно, что с точки зрения доли верных ответов есть две группы задач: более сложные (70-75% верных решений) и более простые (85-90% верных решений). Рейтинги в этом смысле выглядят обеспечивающими больший разброс и большее разнообразие значений.


Последнее, на что очень интересно взглянуть: распределение рейтингов пользователей. Я построил вариационный ряд рейтингов пользователей и увидел такую картину:



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


5. Контекстные модели сложности


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


Например, можно в качестве признаков использовать слова в условии задачи. К словам относятся не только cfvb слова, но и различные специальные термы, такие как математические символы и части формул.


Обучение будет производиться тем же методом максимизации правдоподобия, а модель для простоты используем линейную. То есть фактически будет обучена модель, которая умеет оценивать априорную сложность задачи по её тексту.


Если чуть формальнее, в терминах пункта 4 необходимо переопределить функцию рейтинга для задачи:


$r(t) = \sum_{term \in t} \omega(term)$


Здесь $\omega(term)$ вес терма $term$. Эти веса будут оптимизироавться в процессе обучения.


Затем рейтинг задачи будет уже линейной функцией по термам, входящим в формулировку задачи. Модель сложности задач будет свободна от смещений, вызванных разными характеристиками пользователей: оптимизация весов этой модели производится одновременно с оптимизацией рейтингов пользователей.


Анализируя веса различных термов, можно понимать, какие части заданий вызывают у школьников сложности. Например, при обучении подобной модели для базовой математики получилась следующая картина:



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


Ещё интереснее добавлять в такие модели персональные свойства пользователей. Скажем, пользователи, склонные пропускать задачи (оставлять поле ответа пустым), в среднем добиваются результатов аж на треть реже других. Склонность решать варианты, напротив, является показателем качества: в среднем такие пользователи справляются с задачами на 37% успешнее.


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


6. Рекомендации


Я хочу, чтобы развитие идей из пунктов 4 и 5 привело к созданию модели, которая бы хорошо предсказывала полезность действий на сервисе (в том числе полезность решения тех или иных задач).


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


Сейчас я не могу похвастаться всем этим, зато могу поделиться первыми результатами, дающими надежду на итоговый успех.


Для начала посмотрим на график априорной сложности самостоятельно решаемых задач. По горизонтали номер задачи, которую решает пользователь (например, это 100-я задача, которую он решает на сервисе), по вертикали сложность в простейшем её понимании: какая доля всех решений этой задачи является успешной.



Здесь видны две важные проблемы самостоятельной подготовки. Первая: школьники решают задачи одной и той же сложности. Вторая: они решают слишком сложные задачи, с априорной вероятностью успеха всего 50%.


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


Синяя линия показывает предсказание априорной вероятности решить задачу, зелёная предсказание персональной вероятности решения (априорная не зависит от пользователя, персональная зависит).



Хорошо видно, что поначалу мы предлагаем достаточно простые задачи, которые решаются с вероятностью 80-90%. Затем сложность постепенно нарастает, так что после нескольких сотен решённых задач их априорная вероятность решения снижается до 50%. Одновременно вероятность, что пользователь решит рекомендованную ему задачу, вырастает с 65% почти до 80%. Таким образом, пользователи наших умных рекомендаций всё лучше решают всё более сложные задачи!


Здесь я обязан сделать методологическое замечание: сказанное не доказывает, что наши рекомандации являются причиной роста успешности пользователей. Для такого вывода нужно провести корректное A/Б-тестирование. Например, возможен такой случай: более успешные школьники решают большее количество рекомендованных задач и график показывает только это, хотя при построении персональной модели сложности применялись различные методы для минимизации этого смещения. Тем не менее, приведённый график оставляет возможность того, что причиной являются именно рекомендации.


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



Эти графики устроены так: по горизонтали число решённых рекомендованных задач, по вертикали число пользователей, решивших не менее выбранного числа рекомендованных задач.


Хорошо видно, что умные рекомендации намного сильнее вовлекают пользователей. Некоторые особенности графиков вызваны тем, что на сервисе рекомендации выдаются блоками по несколько десятков задач в день.


Что дальше


В статье я попытался показать, какого рода данные можно собирать, анализировать и использовать во благо общества при помощи сервисов, подобных Яндекс.Репетитору.


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


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

Подробнее..

Перевод Производительность современной Java при работе с большим объёмом данных, часть 2

19.06.2020 00:04:04 | Автор: admin

FYI: Первая часть.

Бенчмарк пакетного конвейера


Пакетный конвейер обрабатывает конечный объём сохранённых данных. Здесь нет потока результатов обработки, выходные данные агрегирующей функции нужно применить ко всему набору данных. Это меняет требования к производительности: задержка ключевой фактор при потоковой обработке здесь отсутствует, потому что мы обрабатываем данные не в реальном времени. Единственная важная метрика общее время работы конвейера.

Поэтому мы выбрали Parallel. На первом этапе тестирования, при работе на одной ноде, этот сборщик действительно показал лучшую пропускную способность (но только после настройки). Однако это было получено ценой длительных пауз. Если одна из нод кластера останавливается на сборку мусора, это стопорит весь конвейер. А поскольку ноды собирают мусор в разное время, общее время сборки увеличивается с добавлением каждой ноды к кластеру. Мы проанализировали этот эффект, сравнив результаты тестирования на одной ноде и на кластере из трёх нод.

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

Тестирование на одной ноде: конвейер


Для пакетного бенчмарка на одной ноде мы использовали простой конвейер. Полный код здесь.

p.readFrom(longSource) .rebalance() // Introduced in Jet 4.2 .groupingKey(n -> n % NUM_KEYS) .aggregate(summingLong(n -> n)) .filter(e -> (e.getKey() & 0xFF_FFFFL) == 0) .writeTo(Sinks.logger())

Источником является заглушка, которая генерирует последовательность чисел типа long. Ключевая функция определена так, что groupingKey циклически проходит по пространству ключей: 0, 1, 2, ..., NUM_KEYS, 0, 1, 2, Это означает, что в течение первого цикла конвейер видит все ключи и создаёт фиксированную структуру данных для хранения результатов агрегирования. А в течение следующих циклов система лишь обновляет имеющиеся данные. Это полностью соответствует гипотезе о сборке мусора с учётом разных поколений: объекты либо проходят через все вычисления, либо существуют недолго и становятся мусором вскоре после своего создания.

Наш источник сгенерировал 400 млн элементов, и мы создали 100 млн отдельных ключей, то есть прошли четыре раза по всем ключам.

Оператор .rebalance() заменяет используемое по умолчанию в Jet двухэтапное агрегирование на одноэтапное. Это сделало поведение движка в наших бенчмарках более предсказуемым.

Также мы протестировали вариант, при котором операция агрегирования использует в качестве состояния экземпляр объекта типа Long и генерирует мусор при каждом обновлении текущего счёта. В этом случае многие объекты умирают после того, как просуществуют приличное время в старом поколении. В этой ситуации нам пришлось уменьшить количество ключей до 70 млн, потому что при 100 млн нагрузка на сборщик была слишком высокой.

Мы не ориентировались на сборщики с низкой задержкой, потому что они ничего не могут предложить в случае с пакетным конвейером. Поскольку мы уже видели, что JDK 14 работает почти как JDK 11, то прогнали один тест для подтверждения этого. А затем сосредоточились на JDK 8 и JDK 11. И также сравнили с G1 используемый в JDK 8 по умолчанию сборщик Parallel.

Тестирование на одной ноде: результаты


Мы прогнали бенчмарк на ноутбуке с 16 Гб ОЗУ и 6-ядерным Intel Core i7. Размер кучи был 10 Гб.

Сначала из-за Parallel производительность была очень плохой, и нам пришлось настраивать сборку мусора. Поэтому мы очень рекомендуем использовать VisualVM и плагин Visual GC. Если задать максимальную частоту кадров (10 к/с.), то можно насладиться очень подробной визуализацией взаимосвязи между выделением памяти вашего приложения и работой сборщика мусора. Понаблюдав за анимацией, мы поняли, что главной проблемой были слишком большие фрагменты памяти, выделяемые для нового поколения. По умолчанию отношение старого поколения к новому равно всего 2:1, и в течение исполнения оно не меняется динамически. Поэтому мы решили применить настройку -XX:NewRatio=8, и это изменило всю картину. Теперь Parallel работал лучше всего. Также мы применили -XX:MaxTenuringThreshold=2 для уменьшения копирования данных между пространствами survivor spaceами, потому что временные объекты быстро умирают в конвейере.

Теперь о результатах. Единственной подходящей метрикой пакетного конвейера является длительность выполнения задачи. Чтобы визуализировать результаты, мы взяли их обратные величины, поэтому на графике показана пропускная способность в элементах в секунду. Для одной ноды:



Агрегирование без сборки мусора работает примерно на 30-35 % быстрее, несмотря на более крупный набор ключей. Хуже всего отработала связка G1 и JDK 8, а лучше всего настроенный Parallel и JDK 11. Не сильно уступила связка G1 и JDK 11. Обратите внимание, что мы не трогали конфигурацию G1, это важное замечание. Настройка сборки мусора сильно зависит от ситуации. Результаты могут сильно меняться, например, при увеличении количества данных. И настраивать нужно для всего кластера, под конкретный вид нагрузки.

Вот производительность используемого по умолчанию сборщика Parallel по сравнению с настроенной версией, которую мы применяли при тестировании:


При куче размером 10 Гб результаты очень плохие. Система застревала на полных паузах на сборку, каждая из которых занимала около 7 с. При увеличении кучи ситуация улучшилась, но всё равно циклы полной сборки происходили очень часто. Обратите внимание, что эти результаты получены для самого частого случая агрегирования без сборки.

Тестирование на трёх нодах: конвейер


Для правильного тестирования кластера пришлось использовать более сложный конвейер:

p.readFrom(longSource()) .rebalance() .flatMap(n -> {     Long[] items = new Long[SOURCE_STEP];     Arrays.setAll(items, i -> n + i);     return traverseArray(items); }) .rebalance() .groupingKey(n -> n % NUM_KEYS) .aggregate(AggregateOperations.summingLong(n -> n)) .filter(e -> e.getKey() % 1_000_000 == 0) .writeTo(Sinks.logger());

Поскольку источник работает не параллельно, мы сделали некоторые оптимизации, чтобы он не превратился в узкое место системы. Источник генерирует числа 0, 10, 20,, а мы распараллелили этап flatMap, на котором интерполируются недостающие числа. Также между источником и flatMap мы использовали rebalance(), распределяя данные по кластеру. А перед началом основного этапа (агрегирования по ключу) мы снова сделали перебалансировку. После агрегирования мы сначала оставляем только каждую миллионную пару ключ-значение, а затем передаём их в логгер. Применялся миллиард элементов данных и набор из 500 млн ключей.

Как и в случае с одной нодой, мы протестировали конвейер с агрегированием без мусора и с ним.

Тестирование на трёх нодах: результат


Мы прогнали этот бенчмарк на кластере AWS из трёх экземпляров c5d.4xlarge. У них было 16 виртуализированных процессорных ядер и 32 Гб памяти. Пропускная способность канала 10 Гбит/с. Результат:



Вскользь отметим примерно трёхкратное общее увеличение пропускной способности по сравнению с одной нодой. Это последствие распределённой обработки. А что касается сборщиков, то победителем обоих тестов стала связка G1 и JDK 11. Другой поразительный результат почти неработоспособная связка G1 и JDK 8. Однако у этого есть более глубокие причины, которые влияют и на другие измерения. Например, очевидное преимущество Parallel на JDK 8 и JDK 11. Это связано с эффектом, который мы отметили в самом начале: как только любая нода встаёт на паузу для сборки мусора, останавливается обработка на всём кластере. А G1 на JDK 8 встаёт на очень длинные паузы, больше минуты. Этого достаточно, чтобы детектор сбоев в кластере сработал и решил, что нода умерла. Задача сбоит, кластер переформирует себя, и задача запускается заново уже на двух нодах. Это ещё быстрее приводит к новому сбою, потому что каждая нода теперь обрабатывает больше данных. В то же время выброшенная нода присоединяется снова, и задача снова начинается на двух нодах, но уже других. Возникает бесконечная петля перезапуска задач.

Паузы Parallel не такие длинные, чтобы развалить кластер, но он сработал гораздо хуже на в тестах на одной ноде. На трёх нодах он уступил связке G1 и JDK 11 на 30 %. А на более крупных кластерах ситуация будет ещё хуже.

Если посмотреть на все тесты, то удивительно, что Parallel на JDK 8 работает быстрее, чем на JDK 11. Однако это связано с очень удачным совпадением: в этих тестовых прогонах полные паузы начинались синхронно на всех узлах, что распараллелило работу сборщика. Очевидно, что на этот эффект нельзя полагаться.

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

С другой стороны, связка G1 и JDK 11 работала с достаточно короткими паузами, поэтому конвейер не останавливался. В нём есть механизм, который смягчает короткие простои, и пока паузы не превышают 150 мс, сборка мусора оказывает только локальное влияние.
Подробнее..

Recovery mode Вебинар Создание пользовательского проекта в редакторе динамических приложений Winnum

23.06.2020 20:12:31 | Автор: admin
image

Компания Winnum приглашает всех желающих посетить бесплатный вебинар Создание пользовательского проекта в редакторе динамических приложений Winnum. Мероприятие состоится 30 июня в 13:00 по московскому времени.

В рамках вебинара мы расскажем вам о редакторе динамических приложений Winnum, покажем, как с ним работать и создадим собственный пользовательский проект. Мероприятие проведет Сергей Соловьев, специалист Winnum по Интернету Вещей.

Динамическое приложение в Winnum это приложение, которое создано пользователем в редакторе динамических приложений в Winnum Platform.
Редактор динамических приложений используется для создания и развития собственных пользовательских проектов, он позволяет конструировать приложения и их мобильные версии на HTML5 c помощью инструментов drag-and-drop.
Данный редактор ускоряет процесс создания новых пользовательских приложений, а также дает возможность быстрого внесения в них изменений.

Вебинар будет полезен


  • IT-специалистам;
  • руководителям проектов;
  • инженерам;
  • техническим и сетевым специалистам;
  • руководителям предприятий;
  • руководителям структурных подразделений, производств, цехов;
  • специалистам по развитию производственных систем;
  • научным сотрудникам.

Регистрация


https://winnum.timepad.ru/event/1342864/

Участие в вебинаре бесплатное. Для получения ссылки на подключение, заполните форму регистрации.
Подробнее..

Перевод Мониторинг качества воздуха c помощью данных TROPOMI в Google Earth Engine

01.07.2020 20:13:32 | Автор: admin


Доступ к воздуху, безопасному для дыхания, очень важен для планеты и её жителей. Однако сейчас во многих частях света люди и хрупкие экосистемы страдают от воздействия загрязнённой атмосферы. В одних только США плохое качество воздуха ежегодно становится причиной около 60,000 случаев преждевременной смерти и обходится государству более чем в 150 млн. долларов, которые тратятся на лечение связанных с этим недугов.


Сейчас, в период социального дистанцирования и перекрытых границ, во многих регионах происходит снижение выбросов загрязняющих веществ. Фактически мы наблюдаем новое состояние качества воздуха, связанное с отсутствием характерных выбросов от транспорта и иных источников. Атмосфера очищается, и спутники NASA и ESA регистрируют снижение концентрации NO2 над многими городами и транспортными коридорами.



Средняя континентальная концентрация диоксида азота в тропосфере, март 2019. Концентрация увеличивается вдоль градиента от пурпурного к жёлтому.


Контролируя качество воздуха, метеорологи могут прогнозировать и предупреждать периоды его ухудшения, когда людям следует оставаться внутри помещений. Кроме того, учёные отслеживают историю изменений качества воздуха, чтобы понять влияние антропогенных и природных процессов на выбросы загрязняющих веществв атмосферу. Для некоторых веществ такие изменения в концентрации фиксируются спутниками. Одним из устройств, которые собирают такие замеры, является прибор для изучения тропосферыTROPOMI (Tropospheric Monitoring Instrument),установленный на борту космического аппаратаSentinel-5 Precursor (S5P), который в настоящее время находится на орбите.


СпутникS5P был запущен в октябре 2017 года для обеспечения непрерывности сбора данных после вывода из эксплуатации аппаратов Envisat (ESA) и Aura (NASA), а также в преддверии запуска Sentinel-5. S5Pимеет на борту многоспектральный датчик TROPOMI, который регистрирует отражательную способность длин волн, взаимодействующих с различными составляющими атмосферы, включая аэрозоли, моноокисьуглерода, формальдегид, диоксид азота, озон, диоксид серы и метан. S5P также позволяет оценивать некоторые характеристики облачности. Цель этой статьи предоставить краткий обзор данных о выбросах, которые регистрирует TROPOMI, а также продемонстрировать возможности использования платформы Earth Engine для анализа и отображения этой информации. Приведённые ниже сведения следует рассматривать как общее руководство для практического использования данных и платформы, но не как источник выводов о последствиях социального дистанцирования и его влиянии на качество воздуха.


Атмосферные выбросы от лесных пожаров


Горение биомассы в результате пожара может привести к выбросу большого количества дымовых аэрозолей. Отслеживать перенос такого аэрозольного шлейфа в течение дней и даже недель позволяет ежедневная частота и глобальный охват измерений с S5P. На рисунке нижеанимация временного ряда изображений, отражающихциркуляцию аэрозолей, вызванных мощными пожарами австралийских кустарников 20192020 годов, которые в итоге повлияли на качество воздуха в городах Южной Америки. Результаты измерений УФ-аэрозольного индекса, которые использовались в этом случае, применяются и для отслеживания других аэрозольных выбросов, таких как песчаные бури и вулканический пепел.



Аэрозольный шлейф от мощных австралийских кустарниковых пожаров 20192020 годов, распространяющийся на восток через Тихий океан. Анимация по мотивам исследований Сары Апарисио (Sara Aparcio).


Анимация отличное средство визуализации данных, но для количественной оценки временных изменений в загрязнении воздуха зачастую целесообразно использовать растровую алгебру (image math). В следующем примере вычитаются данные на две даты, характеризующие концентрацию угарного газа (CO) до и во времяпожаров в лесах Амазонки в 2019 году. Цель выделить те регионы, где концентрация увеличилась в два и более раз, в результате чего Всемирная организация здравоохранения выпустила предупреждение о чрезмерном загрязнении воздуха.



Разница в концентрациях оксида углерода до и во время пожаров в Амазонке в 2019 году. На картах до (Before) и во время (During) концентрация увеличивается вдоль градиента от фиолетового к жёлтому, а для карты разница (Difference) от чёрного к белому (карта отмаскирована для выделения областей, в которых во время пожаров произошло как минимум удвоение концентрации угарного газа).


Антропогенные атмосферные выбросы


Сжигание ископаемого топлива для нужд промышленности, транспорта и генерации тепла способствует загрязнению воздуха. Слой с данными о концентрации диоксида азота (NO2) хорошо подходит для анализа подобных типов выбросов, поскольку этот газ имеет короткий срок существования, и, как следствие, регистрируется вблизи источника выбросов. К примеру, визуализируя плотность населения (Gridded Population of World dataset) и высокие концентрации NO2 относительно друг друга, можно выявить пространственную корреляцию между плотностью населения и концентрациями NO2 на восточном побережье США.



Пространственная корреляция между точками высокой плотности населения и высокой концентрацией тропосферного диоксида азота в восточной части Соединённых Штатов. Плотность населения увеличивается вдоль градиента от белого к пурпурному, концентрация диоксида азота от тёмно-фиолетового к жёлтому.


На сдвоенной карте сверху и на диаграмме снизу показано, что с увеличением плотности населения усиливается и концентрация NO2 (подробнеео построении графиков в Earth Engine читайте в соответствующем разделе документации).



Связь между плотностью населения и концентрацией тропосферного диоксида азота (NO2) в зимний период в США к востоку от р. Миссисипи. Интерполированные графики NO2 для среднего и межквартального диапазона представлены для интервалов плотности населения от 0 до 20,000 человек/км2 с шагом 2,000 человек/км2, где последний интервал представляет районы с плотностью более 20 000 человек / км2.


В настоящее время большая часть мира практикует социальное дистанцирование с целью снижения воздействия нового типа коронавируса. С уменьшением числа людей, которые ездят на работу, снижаются и атмосферные выбросы диоксида азота (см. интерпретацию от NASA). Использование данных TROPOMI и платформы Earth Engine позволяет учёным исследовать подобные взаимосвязи и закономерности практически в режиме реального времени, а также в региональном и глобальном масштабах. Один из пользователей, Кристина Вринчану (Cristina Vrinceanu), создала приложение Earth Engine, в котором реализован виджет-слайдер для визуализации снижения концентрации диоксида азота в регионах, находящихся на карантине. Так, в приложении Кристины и сопутствующей статье в Medium исследуется регион севера Италии, который в борьбе с распространением вируса применяет в том числе и карантинные ограничения.



Приложение Earth Engine демонстрирует применение виджета-слайдера для сравнения концентрации NO2 за два различных периода времени. (Приложение от Кристины Вринчану).


Ещё один наглядный способ визуализации изменений концентрации загрязняющих веществ в воздухе с течением времени это годовой график. Следующая диаграмма демонстрирует и этот подход, сравнивая по дням концентрацию диоксида азота в период с 2019 по 2020 год в северной Италии.



Среднегодовые временные ряды NO2 в сравнении со значениями концентрации 2020 года и 2019 года, представленные для Паданской низменности на севере Италии (включает Милан, Болонью и Венецию).


Важные дополнения


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


В некоторых регионах мира определённые сочетания экологии, климата, погоды, географии и выбросов приводят к вариациямконцентрации загрязняющих веществ. Так, для китайской провинции Хубэй характерны сезонные тренды концентраций NO2, что видно на следующем рисунке, на котором изображена серия наблюдений за последний 21 месяц, подкреплённая гармонической линией тренда. Линия трендаполезна для выделения регулярных сезонных колебаний, а также для обособления высокой дисперсии в зимние месяцы, вызваннойсменой погоды. Для того, чтобы не делать выводов на основе отдельных измерений, которые могут представлять аномальные наблюдения, связанные с погодой, рекомендуется использовать линии тренда и вычислять скользящие средние за недели или месяцы наблюдений. Ламсай и др (Lamsai et al., 2010) приводят подробный анализ сезонных тенденций в отношении NO2.



Концентрация NO2 в южной провинции Хэбэй, Китай. Точками представлены результаты измерений; линия представляет собой функцию гармонического тренда для иллюстрации сезонных колебаний.


Точно так же сезонные колебания характеры и для концентраций озона, что показано на следующем графике, который отражает фактические и гармонически интерполированные данные наблюдений атмосферы над районом Великих озёр в Соединённых Штатах (подробнее о гармоническом моделировании в Earth Engine читайте в соответствующем разделе документации).



Временные ряды концентрации озона для района Великих озер в США. Точками представлены результаты измерений; линия представляет собой функцию гармонического тренда для иллюстрации сезонных колебаний.


Важнейшим фактором является облачный покров, который может исказить результаты наблюдений, ограничив вклад нижней части атмосферы в полученные датчиком замеры. Ниже демонстрируется высокая изменчивость облачного покрова на пиксель изображения в районе северной Италии для продукта NO2. Обратите внимание на высокую долю облаковконце января 2019 года в сравнении с тем же периодом год спустя, когда облачный покров был намного меньше. В связи с этимпри сравнении разновременных наблюдений рекомендуется фильтровать данные таким образом, чтобы они включали только пиксели с низким облачным покровом. Подробная информация о свойствахоблачного покрова приведена в соответствующей статье программы Copernicus.



Динамика изменений среднего и межквартального диапазона облачной фракции для продукта NO2, представленная для региона северной Италии. Доля облачности может значительноварьироваться по времени, поэтому,чтобы обеспечить надёжную оценку изменений качества воздуха, рекомендуется ограничивать данные наблюдений S5P выборкой безоблачных или малооблачных условий.


Приложение TROPOMI Explorer


Чтобы обеспечить пользователям удобство и оперативность при работе с данными S5P TROPOMI, а также предоставить платформу для дальнейшего анализа, специалисты Google создали интерактивное приложение, которое позволяет просматривать изменения концентрации загрязняющих веществ с течением времени, используя визуализацию в виде сдвоенных карт или карты-шторки, а также графики временных изменений. Приложение доступно по ссылке.



Интерактивное приложение для исследования данных TROPOMI, созданное с использованием Google Earth Engine Apps.


Хотя многие сейчас находятся на самоизоляции, сообщество пользователей и разработчиков платформы Earth Engine продолжает активно обмениваться идеями. Посмотрите, как другие анализируют и изучают данные S5P TROPOMI с помощью Earth Engine:



Пользователи Earth Engine мотивируют разработчиков развивать платформу и создавать новые инструменты для понимания нашего воздействия на планету, а также решения других глобальных проблем. Надеемся, что читателю понравился этот краткий обзор данных S5P TROPOMI. Начать самостоятельные эксперименты с данными S5P можно со знакомство с соответствующим каталогом данных в Earth Engine).


Перевод подготовлен преподавателями Инженерной академии Российского университета дружбы народов Василием Лобановым и Ярославом Васюниным.


Эта работа лицензируется в соответствии с Creative Commons Attribution 4.0 International License (CC BY 4.0)

Подробнее..

Перевод Интерактивная визуализация данных при помощи Plotly строим красивые графики с Express и Cufflinks

25.06.2020 22:10:00 | Автор: admin
image


Если Вы все еще используете Matplotlib для создания графиков в Python, самое время взглянуть на мир с высоты альтернативной библиотеки интерактивной визуализации.

Plotly позволяет создавать красивые, интерактивные, экспортируемые графики с помощью всего нескольких строк кода. Однако без карты подъем в гору Plotly может быть медленным и мучительным.

Вот камни преткновения, которые могут появиться на пути авантюристов, решивших покорить эту гору:

  • непонятная начальная настройка для работы оффлайн без аккаунта;
  • неимоверное количество строк кода;
  • устаревшая документация;
  • множество различных инструментов Plotly, в которых можно заблудиться (Dash, Express, Chart Studio и Cufflinks).

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

Plotly


Данная программа была создана одноименной компанией, владеющей множеством программ с открытым исходным кодом для создания интерактивных графиков и чартов. Зарабатывает компания за счет предоставления расширенного пакета функций своих программ. Также за отдельную плату она предлагает настроить Ваш собственный хостинг. Компания базируется в Монреале с офисом в Бостоне.

Plotly.py основывается на JavaScript-библиотеке D3.js. Также в Plotly есть API-обертки для R, Julia и многих других языков программирования. Стоит отметить, что документация представлена не на всех языках.

image

Примеры библиотек от Plotly

В этой статье мы остановимся на опциях, которые используют Python. Я использую Python 3.7 и последующие версии библиотеки в данном руководстве.

cufflinks                0.15jupyterlab             0.35.5plotly                   3.8.1     plotly-express       0.1.7


Убедитесь, что используется cufflinks 0.15 (0.13 не очень дружит с последними обновлениями Plotly).
ПРАВКА (май 2020): самая свежая версия Plotly 4.7.1. Большая часть представленных ниже инструкций все так же применима к последней версии программы. Обратите внимание, что экспресс-модуль импортируется как часть пакета Plotly.

plotly.py


Несмотря на то что написано в некоторых инструкциях, создавать аккаунт для пользования Plotly не нужно, как и не нужно работать в онлайн-режиме.

Установите простой модуль plotly.py с conda или воспользуйтесь pip install plotly.

Импортируйте модуль и сконфигурируйте его для использования в оффлайн-режиме:

import plotly.offline as pypy.init_notebook_mode(connected=False)


Теперь программа не будет требовать у Вас создать аккаунт. Так мы и преодолели первую преграду на пути к вершине горы Plotly.

Вот пример интерактивного Plotly-графика с земным шаром, которая позволяет изменять тип проекции и расположение с помощью слайдеров. Вы можете сами оценить возможность взаимодействия с данной схемой здесь.

image

Ниже представлено объемное описание кода, адаптированного из документации, необходимой для создания такого витиеватого графика.

import pandas as pdimport numpy as npimport plotly.offline as pyimport plotly.graph_objs as goimport jsonpy.init_notebook_mode(connected=False)izip = zipdf = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/globe_contours.csv')df.head()contours = []scl = ['rgb(213,62,79)','rgb(244,109,67)','rgb(253,174,97)',\       'rgb(254,224,139)','rgb(255,255,191)','rgb(230,245,152)',\       'rgb(171,221,164)','rgb(102,194,165)','rgb(50,136,189)']def pairwise(iterable):    a = iter(iterable)    return izip(a, a)i=0for lat, lon in pairwise(df.columns):    contours.append( dict(        type = 'scattergeo',        lon = df[lon],        lat = df[lat],        mode = 'lines',        line = dict(            width = 2,            color = scl[i]        )    ) )    i = 0 if i+1 >= len(df.columns)/4 else i+1    layout = dict(        margin = dict( t = 0, l = 0, r = 0, b = 0 ),        showlegend = False,                 geo = dict(            showland = True,            showlakes = True,            showcountries = True,            showocean = True,            countrywidth = 0.5,            landcolor = 'rgb(230, 145, 56)',            lakecolor = 'rgb(0, 255, 255)',            oceancolor = 'rgb(0, 255, 255)',            projection = dict(                 type = 'orthographic',                rotation = dict(lon = 0, lat = 0, roll = 0 )                        ),            lonaxis = dict(                 showgrid = True,                gridcolor = 'rgb(102, 102, 102)',                gridwidth = 0.5            ),            lataxis = dict(                 showgrid = True,                gridcolor = 'rgb(102, 102, 102)',                gridwidth = 0.5            )        )    )sliders = []lon_range = np.arange(-180, 180, 10)lat_range = np.arange(-90, 90, 10)sliders.append(     dict(        active = len(lon_range)/2,        currentvalue = {"prefix": "Longitude: "},        pad = {"t": 0},        steps = [{                'method':'relayout',                 'label':str(i),                'args':['geo.projection.rotation.lon', i]} for i in lon_range]    )      )sliders.append(     dict(        active = len(lat_range)/2,        currentvalue = {"prefix": "Latitude: "},        pad = {"t": 100},        steps = [{                'method':'relayout',                 'label':str(i),                'args':['geo.projection.rotation.lat', i]} for i in lat_range]    )      )projections = [ "equirectangular", "mercator", "orthographic", "natural earth","kavrayskiy7",                "miller", "robinson", "eckert4", "azimuthal equal area","azimuthal equidistant",                "conic equal area", "conic conformal", "conic equidistant", "gnomonic", "stereographic",                "mollweide", "hammer", "transverse mercator", "albers usa", "winkel tripel" ]buttons = [ dict( args=['geo.projection.type', p], label=p, method='relayout' ) for p in projections ]annot = list([ dict( x=0.1, y=0.8, text='Projection', yanchor='bottom',                     xref='paper', xanchor='right', showarrow=False )])# Update Layout Objectlayout[ 'updatemenus' ] = list([ dict( x=0.1, y=0.8, buttons=buttons, yanchor='top' )])layout[ 'annotations' ] = annotlayout[ 'sliders' ] = slidersfig = dict( data=contours, layout=layout )py.iplot( fig)

Не уверена, как этот пример сюда запихнуть, не размазав его по нескольким страницам.

Главное, почему стоит избегать работы с ванильным модулем plotly.py, громоздкость данных. Процесс вбивания кода выходит очень длительным и часто приводит к ошибкам. К счастью, из данной ситуации есть два выхода.

Если нам все же не удалось свернуть с тропинки ploty.py, то придется порыться в конструкторе. Официальная документация выглядит красиво, но часто все равно приходится часами копаться на других сайтах в поисках подходящего способа пофиксить код. У Plotly есть свой форум с неплохими советами, но многие образцы кодов не обновлены и не работают в версии 3.0. Поэтому ищите сразу образцы, совместимые с последней версией, или придется переводить их вручную.

Следующие два продукта от Plotly, на которые мы обратим внимание, предлагают высокоуровневые обертки, упрощающие программный интерфейс plotly.py. Они помогут сэкономить время, если вы работаете с библиотекой Pandas. Давайте рассмотрим их поподробнее.

Express


Модуль Plotly Express был выпущен в марте 2019 года и находится в процессе активной разработки. Компания работает над созданием условий поддержки новых графиков и собирается выпустить Plotly 4.0 летом 2019 года.

Express позволяет уменьшить код, необходимый для создания датафреймов Pandas в 10 раз. Загружать свою таблицу нужно в виде опрятных данных, где каждый столбец соответствует одной переменной, а каждая строка одному наблюдению.

Установите Express с помощью pip install plotly_express.

Чтобы использовать эту библиотеку в записной книжке Jupyter, введите следующий код в командную строку:

jupyter labextension install @jupyterlab/plotly-extension

Данный код позволит создать гистограмму из таблицы с традиционным Express импортом:

import plotly_express as px         px.bar(my_df, x='my_x_column', y='my_y_column')


Вуаля! Вы получили гистограмму по данным таблицы (вставьте свои значения там, где у меня в коде дано my_.

Вы можете настроить множество значений. Например, добавьте заголовок, изменив свое определение следующим образом:

px.bar(my_df, x='my_x_column', y='my_y_column', title='My Chart Title")


Если Вы хотите поработать с конкретным параметром, то стоит вернуться к исходному графику Plotly. Допустим, Вы хотите добавить текстовые значения к столбцам в гистограмме. Для этого Вам нужно сохранить оригинальную диаграмму и указать свойства данных. Вот как это сделать:

_my_fig = px.bar(my_df, x='my_x_column', y='my_y_column', title='My Chart Title')_my_fig.data[0].update(    text=my_df['my_y_column'],      textposition='inside',    textfont=dict(size=10))_my_fig.iplot()


Внимание: я нашел документацию Express! Она не отобразилась у меня на первой странице поиска в гугле, поэтому я не сразу смог ее прикрепить. Теперь она есть. Всегда пожалуйста!
Express позволяет быстро создавать разного вида диаграммы, но доступны могут быть не те, что Вам требуются. Например, нормальную гистограмму с накоплением вы сейчас врядли сможете собрать. А если очень надо, то придется подниматься в гору по другой тропинке в этот раз с Cufflinks.

Cufflinks


Cufflinks очень похож на Express тем, что является оберткой интерфейса Plotly, позволяющей упростить работу с Pandas. Cufflinks сторонняя программа с открытым исходным кодом, которая существует уже более четырех лет.

Установите ее с помощью pip install cufflinks.

Импортируйте модуль и настройте файл для автономного использования.

import cufflinks as cfcf.set_config_file(offline=True)


С Cufflinks для создания многих видов диаграмм нужна лишь одна строчка кода. К примеру, сделать гистограмму с накоплением с этой библиотекой проще простого.

image

Пример гистограммы с накоплением, созданной с помощью Cufflinks.

А вот и сам код:

df = pd.DataFrame(np.random.rand(6, 3), columns=['A', 'B', 'C'])df.iplot(kind='bar', barmode='stack', title='Stacked Bar Chart with Random Data')


Обратите внимание, что для создания диаграмм с помощью Cufflinks Вам нужно использовать .iplot().

Как и Express, Cufflinks возвращает исходные данные, чтобы Вы могли вносить мелкие поправки. Но в отличие от Cufflinks, Вам нужно уточнить переменную asFigure=True, чтобы вернуть информацию. После этого можно обновить график точно так же, как в Express. Вот как это будет выглядеть, если Вы захотите изменить название и диапазон осей.

my_fig = df.iplot(kind='bar', barmode='stack', title='Stacked Bar Chart with Random Data', asFigure=True)_fig.layout.yaxis = dict(title='Members', range=[0, 600])

Вот документация Cufflinks.

К сожалению, Cufflinks тоже имеет свои лимиты. Например, с помощью этой библиотеки нельзя создать график рассеяния с географическими координатами.

Сравнение трех вариантов


Далее Вы можете наблюдать сравнение кода со схожей структурой для графиков, созданных с помощью plotly.py, Express и Cufflinks.

plotly.py


image

Пример диаграммы рассеяния, выполненной с plotly.py

fig = {    'data': [        {            'x': df2007.gdpPercap,             'y': df2007.lifeExp,             'text': df2007.country,             'mode': 'markers',             'name': '2007'},    ],    'layout': {        'title': "Example Scatter Plot with Vanilla plotly.py"    }}py.iplot(fig)


Express


image

Пример диаграммы рассеяния, выполненной с Plotly Express

px.scatter(    df2007,     x="gdpPercap",     y="lifeExp",     title='Example Scatter Plot with Plotly Express')


Выглядит просто и лаконично! Форматирование по умолчанию немного отличается, а названия осей генерируются автоматически. Теперь предлагаю взглянуть на тот же график в Cufflinks.

Cufflinks


image

Пример диаграммы рассеяния, выполненной с Cufflinks

df2007.iplot(    kind='scatter',     mode='markers',     x='gdpPercap',     y='lifeExp',     title='Example Scatter Plot with Cufflinks')


Код похож на Express, но у графика немного другие значения по умолчанию. Определенно, с Express и Cufflinks Вам не придется часами выстукивать коды, что особенно важно при создании более сложных графиков.

Давайте посмотрим, как можно вернуть и обратиться к основной информации.

Обновление графиков Cufflinks и Express


Давайте перейдем к макету графика, созданного с Cufflinks, и добавим названия осей.

image

Пример диаграммы рассеяния, выполненной с Cufflinks Доступ к исходному графику

fig = df2007.iplot(    kind='scatter',     mode='markers',     x='gdpPercap',     y='lifeExp',     asFigure=True,    title='Example Scatter Plot with Cufflinks - Access Underlying Figure')fig.layout.xaxis.title = "GDP per Capita"fig.layout.yaxis.title = "Life Expectancy"fig.iplot()


Вот как сделать то же самое с Express. Не забывайте, что в данной библиотеке не нужно уточнять asFigure=True.

image

Пример диаграммы рассеяния, выполненной с Plotly Express Доступ к исходному графику

fig = px.scatter(    df2007,     x="gdpPercap",     y="lifeExp",     title='Example Scatter Plot with Plotly Express - Access Underlying Figure')fig.layout.xaxis.title = "GDP per Capita"fig.layout.yaxis.title = "Life Expectancy"fig.iplot()


Вы можете обратиться к исходным данным, чтобы добавить текстовые метки следующего вида:

fig.data[0].update(text=df2007['gdpPercap'],textposition=inside,textfont=dict(size=10))


Что выбрать: Plotly.py, Express или Cufflinks


Выбирать всегда сложно. Один раз я думал, что работал над частью проекта в Express, а потом понял, что это был Cufflinks!

Мне очень нравится выражение из Zen of Python: Должен существовать один и, желательно, только один очевидный способ сделать это. Как только появляются варианты появляются и необходимость долгого поиска информации, и усталость от необходимости выбирать, и ошибки.

К сожалению, ни один высокоуровневый API на данный момент не дает возможность создавать графики любого типа. Однако лично я точно постараюсь максимально избегать использования ванильного python.py и предпочту Cufflinks или Express.

Советую лишний раз заглянуть в документацию Express и Cufflinks, прежде чем создавать диаграмму. Не забывайте, что Express использует опрятные датафреймы, в то время как Cufflinks в этом плане более гибкий. Пользуйтесь той библиотекой, которая отвечает Вашим потребностям и обладает предпочтительным для Вас форматом.

Форматирование по умолчанию у двух библиотек может сильно отличаться. Например, создав датафрейм со случайными данными для столбцов X, Y и Z и используем следующий код, в Cufflinks мы получим следующую диаграмму:

df.iplot(kind=scatter, mode=markers, x=X, y=Y, title=Random Data, categories=Z)


image

Диаграмма рассеяния по умолчанию с Cufflinks

А вот что мы получим с Express-кодом:

px.scatter(df, x=X, y=Y, color=Z, title=Random Data)


image

Другие пресеты с Express

Заметная разница!

Сохранение файлов


Закончив работы с диаграммой, Вы можете навести на нее мышку и щелкнуть по значку камеры, чтобы экспортировать ее в формате .png, или нажать Экспортировать в plot.ly, чтобы сохранить интерактивное изображение на сервер Plotly. Помимо этого, Вы можете скачать файлы в интерактивном HTML-формате следующим образом:

py.offline.plot(my_fig, filename=my_example_file.html)


Если нужны другие форматы изображения, Вы можете воспользоваться пакетом orca и скачивать файлы в форматах .png, .jpg и .pdf. Данный пакет на данный момент недоступен на pypi.org, поэтому установить его с помощью pip не получится. Вы можете управлять пакетом с помощью conda или установить ОС-специфичную версию orca со страницы GitHub. После этого Вам не нужно будет импортировать библиотеку orca. Узнать больше о программе orca можно здесь.

Вот код для создания png-файла после установки orca:

import plotly as plotlyplotly.io.write_image(fig, file='my_figure_file.png', format='png')


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

Dash


С Plotly Dash Вы можете создавать дашборды для своей команды или для других людей. Есть версия с открытым кодом доступа, у которой к 1 мая 2019 года насчитывалось практически 9000 звезд GitHub. Plotly также предлагает целый ряд дополнений. Может, в будущем я напишу статью и об этом. Подписывайтесь, чтобы не пропустить.

Chart Studio


Plotly Chart Studio позволяет легко создавать и редактировать графики в браузере. Plotly рекламирует данную программу как самый умный редактор для создания D3.js- и WebGL-диаграмм. Не надо ничего кодировать вручную. Есть бесплатная версия, но если хотите сохранить свои графики, то придется отдать 99$ за год использования.

А теперь, когда мы уже добрались до вершины Plotly, давайте быстро пробежимся по другим горам визуализации данных в диапазоне Python.

Бонус: другие варианты библиотек визуализации данных от Python


Я не собирался в этой статье рассказать обо всех на свете программах для визуализации данных, но все же хочу упомянуть несколько довольно важных программ, о которых специалисты по работе с данными должны знать. Так Вы сможете максимально полно познакомиться с территориями, с которыми, возможно, придется работать.

image

Хотите делать графики по старинке обратитесь к ванильной библиотеке Matplotlib API.

image

Pandas Matplotlib позволяет создавать неплохие простенькие графики. Может создавать стандартные Matplotlib объекты.

image

Seaborn отличная высокоуровневая обертка, основанная на Matplotlib, которая позволяет создавать различные графики визуализации статистических данных. К сожалению, из-за довольно старой базы Matplotlib, использовать ее не очень удобно.

image

Bokeh конкурент Plotly. Программа с открытым исходным кодом, интерактивная, работает с Python.

image

Holoviews высокоуровневая обертка, работающая с Matplotlib, Bokeh, а теперь и с Plotly. Знаю ребят, которые пользуются именно ей.

image

Специалистам, работающим с языком R, нравится использовать Shiny от RStudio. Оно позволяет пользователям R создавать интерактивные визуализации для веб-приложений.

image

Tableau и Microsoft PowerBI две популярные опции с системой перетаскивания данных визуализации, которые работают с Python. Tableau очень даже хорошая библиотека, но за нее придется заплатить, если не хотите, чтобы Ваша работа была в открытом доступе.

image

На мой взгляд, PowerBI обладает менее интуитивно понятным интерфейсом, но программа все равно очень мощная и популярная.

Большинство ПО для создания интерактивных графиков используют библиотеку D3.js. Она очень популярна.

Выводы и полезные ресурсы


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

Возможно, когда-нибудь появится универсальная библиотека, позволяющая создавать все, что захотите, используя высокоуровневые API-опции Plotly. А пока, если хотите сэкономить время и сделать крутые графики, предлагаю обращаться к Pandas с Cufflinks или Express.



Совет: когда используете в графиках цвет, не забывайте про людей с дальтонизмом. Воспользуйтесь палитрой, удобной для дальтоников. Я использую палитру от ggplot.

image

Образец цветов

color_list = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#D55E00", "#0072B2",  "#CC79A7"]


image

Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:



Читать еще


Подробнее..

Почему меня разочаровали результаты Kaggle ARC Challenge

23.06.2020 14:06:23 | Автор: admin
Кто-то с ужасом, а кто-то с нетерпением ждет ИИ как в произведениях фантастов. С личностью, эмоциями, энциклопедическими знаниями и главное с интеллектом, то есть способностями к логическим выводам, оперированию абстрактными понятиями, выделению закономерностей в окружающем мире и превращению их в правила. Как мы знаем, именно такой ИИ теоретики называют сильным или ещё AGI. Пока это далеко не мейнстримное направление в машинном обучении, но руководители многих больших компаний уже считают, что сложность их бизнеса превысила когнитивные способности менеджеров и без настоящего ИИ двигаться вперёд станет невозможно. Идут дискуссии, что же это такое, каким он должен быть, как сделать тест чтобы уж точно понять, что перед нами AGI, а не очередной blackbox, который лучше человека решает локальную задачу например, распознавание лица на фотографии.

Три недели назад на каггле прошло первое в истории платформы соревнование по сильному ИИ Abstraction and Reasoning Challenge. Чтобы проверить способность моделей к обобщению и решению абстрактных задач, все участники суммарно решили только чуть менее половины задач. Решение-победитель справляется приблизительно с 20% из них и то девятичасовым перебором вручную захардкоженных правил (ограничение в девять часов установили организаторы).

В посте я хочу напомнить о сложностях работы с AGI, рассказать о самых интересных идеях участников, топовых решениях и поделиться мнением, что не так с текущими попытками создать AGI.

Вызов


В ноябре 2019 года создатель Keras Франсуа Шолле написал статью Об оценке интеллекта. На хабре краткий пересказ уже выложила Rybolos. Ключевой практический элемент статьи датасет для проверки способности алгоритмов к абстрактному мышлению в человеческом смысле. Просто поглядеть на него можно здесь.

Примеры задач из датасета; наверху вход, внизу ответ





Для человека эти задачи легко решаемы и напоминают блок из теста на IQ они сводятся к набору трансформаций над картинками от 30x30 до 1x1: продолжить узор, восстановить удаленный кусок, обрезать, закрасить замкнутые области, найти лишний объект и т.д.

Соревнование


Не заставило себя долго ждать и само соревнование на Kaggle на основе этого датасета, призы в котором были не самые большие в зависимости от скора $5K-8K за первое место. Для сравнения в проходившем параллельно соревновании DFDC победивший Селим Сефербеков получил полмиллиона долларов.

Тем не менее, соревнование привлекло несколько грандмастеров Kaggle: rohanrao (H20), kazanova (H20, кстати третье место в глобальном рейтинге Kaggle), boliu0 (NVIDIA), titericz (NVIDIA), tarunpaparaju, много очень сильных ребят из ODS, в том числе Влада Голубева и Илью Ларченко, которые взяли третье место. Всего до LeaderBoard дошли 914 команд.

Участникам предлагалось обучить модель на 400 задачах, в каждой из которых есть train (три-пять картинок), ответ и тест (одна-две картинки и соответственно один-два ответа). Этот датасет вручную разметил Davide Bonin на комбинации из 192 элементарных трансформаций.

Такой же по объему датасет (400 задач) предлагался для валидации (eval), впрочем, на нем можно было и обучаться особенно с учетом того, что задачи на нем отличались от обучающего. То есть сочетание трансформаций на тесте могли не встречаться на трейне, например вместо операции crop crop + resize. В лидерборде было 100 задач, при этом на каждое задание можно было выдавать три варианта ответа, достаточно чтобы хотя бы один был верным.

Интересные идеи


CNN c TensorFlow Lattice


Не попали в лидерборд.TensorFlow Lattice позволяет накладывать достаточно жесткие ограничения на фичи при обучении сеток: монотонность, взаимную важность, выпуклость, взаимное доверие, унимодальность. Это существенно увеличивает способности сеток к экстраполяции и сглаживает разделяющие поверхности. Для привлечения внимания картинка про сравнение разделяющих поверхностей разных моделей на одной задаче из блога TensorFlow Core.



В решении предлагалось взять сверточную сеть, так как CNN широко применяется для решения задач на картинках вроде выделения объектов. Идея была любопытная, но решение сработало на тесте ровно никак:



Вариационные автоэнкодеры


Заняли 131 место из 914 в лидерборде. Похожая идея наложить ограничения, но не на пространство признаков как в TF Lattice, а на пространство скрытых переменных, то есть использовать вариационные автоэнкодеры. О них на хабре есть отличная статья.

Это решение было доработано и дошло до LeaderBoard.На картинке в первой строке входное изображение, во второй правильный ответ, в третьей результат работы модели.



Генетический алгоритм



Занял 631 место из 914 в лидерборде. В этом кейсе в качестве генов реализовано одиннадцать трансформаций DSL генетического алгоритма. В ходе селекции по стратегии элитизма отбираются наиболее сильные гены:


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

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

Графовый подход


Занял 165 место из 914 на лидерборде. Одна из наиболее человекообразных идей
выделить на исходных изображениях объекты и далее работать с их трансформациями. Для выделения объектов применялся алгоритм k-clique-communities algorithm графовой библиотеки networkx, и справился он на отлично:







К сожалению, ноутбук с трансформациями автор не оставил, есть только выделение объектов, однако автор вошел в топ-19 на лидерборде.

Языковая модель


Заняла 592 место из 914 на лидерборде. На начало 2019 года BERT state-of-the-art языковая модель. За последние месяцы было множество её усовершенствований: RoBERTa, DistilBERT, ALBERT и другие. Здесь идея решения основывается на двух фактах:
  • Способности BERT работать с последовательностями.
  • Механизме attention, который можно научить вычленять связи даже между достаточно удаленными элементами последовательности в противовес идее о влиянии на элемент только нескольких соседних.

В некоторых задачах идея сработала, пример ниже.
Обучающие примеры: слева входная картинка, справа правильный ответ.





А вот результат работы обученной модели (справа):

Жаль, что на других задачах результаты не были такими хорошими.

Работающие решения


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

Например, задание про изменение цветов при сохранении размера изображения: ноутбук Zoltan, занявшего в итоге шестое место, вошел в решение Влада Голубева и Ильи Ларченко, которые заняли третье место. Решение по сути представляет объединение нескольких, в том числе публичных. Так, идеи Ильи описаны в его репозитории, он декомпозировал задачи на абстракции (цвета, блоки, маски), в терминах которых для которых реализовал трансформации, решающие 32 задания. К этому добавляются решения Влада как с похожим подходом на правилах и трансформациях, так и модель xgboost.

Пример работы решения


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



А вот результат работы решения:

Достаточно похожим выглядит решение , взявшее второе место:
  1. Определить на входе тип задания (из шести по классификации автора) и параметры входных изображений.
  2. Иногда упростить задание например, поменять один цвет или повернуть объекты.
  3. Перебирать в цикле различные трансформации (реализовано 51) и их комбинации чтобы выбрать три максимально близкие к ответу картинки.
  4. Выполнить преобразования, обратные тем, что были на шаге 2, к трем кандидатам.
  5. Иногда имеет смысл сделать аугментацию например, из исходных примеров сделать задачи монохромными или только с одной формой.

Чемпион и 10 000 строк кода


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



Что в итоге?


На фоне вала статей и выступлений на конференциях A* об успехах в задачах создания сложных моделей по нескольким примерам результаты соревнования оказались совершенно неожиданными и обескураживающими.

В ноябре 2019 мне посчастливилось посетить ICCV2019 в высокотехнологичном Сеуле, где каждый второй доклад был посвящен задаче ZSL. Были ожидания, что в соревновании ARC достаточно применить одну из раскрученных в научном сообществе техник. Может, я был невнимателен, но, к своему разочарованию, не увидел среди решений участников такого подхода.

Так как уже в процессе соревнований участники делятся идеями и наработками, участие в челлендже казалось отличным способом узнать, какие подходы сейчас на переднем крае в области создания сложных моделей с минимальной обучающей выборкой или без таковой: zero-shot learning (ZSL), one-shot learning, few-shot learning, prototype learning и domain shift. Конечно, перечисленные проблемы подразумевают изменение доменной области, а не самой задачи классификация остается классификацией. Но это самое проработанное направление в части обобщения моделей.

Сами мы решили попробовать GAN-архитектуру поверх feature extractor, которая у нас так и не зашла. Однако, примерно за три-четыре недели до конца соревнования стало понятно, что выигрывают решения на правилах. Обсудив внутри, мы пришли к выводу что, потратив кучу времени на написание, мы вряд ли повысим свои компетенции в современных методах, поэтому направили энергию на другие задачи.

В тысячный раз подтвердился тезис о прикладном характере машинного обучения это набор инструментов, который надо уметь применять четко понимая задачу. В то же время бессмысленно применять даже самые крутые инструменты к непонятной задаче. Можно провести аналогию со станком, ЧПУ и 3D-принтером: несмотря на то, что область применения на каждом этапе растет, пока даже близко нет волшебной палочки, способной создать абсолютно любой предмет.

Чтобы обучить машину, мало придумать ей абстрактный язык (DSL или набор трансформаций), придумать функцию потерь и показать пару примеров. Челлендж прошёл, но осталось разочарование: то, что маркетологи до сих пор продают как AI, на поверку оказывается набором инженерных хитростей. Флёр волшебства окончательно растаял.
Подробнее..

Из песочницы 9 ключевых алгоритмов машинного обучения простым языком

03.07.2020 20:16:17 | Автор: admin
Привет, Хабр! Представляю вашему вниманию перевод статьи 9 Key Machine Learning Algorithms Explained in Plain English автора Nick McCullum.

Машинное обучение (МО) уже меняет мир. Google использует МО предлагая и показывая ответы на поисковые запросы пользователей. Netflix использует его, чтобы рекомендовать вам фильмы на вечер. А Facebook использует его, чтобы предложить вам новых друзей, которых вы можете знать.

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

Эта статья познакомит вас с фундаментальными концепциями в области машинного обучения. А конкретнее, мы обсудим основные концепции 9ти самых важных алгоритмов МО на сегодняшний день.

Система рекомендаций(Recommendation system)


Для построения полноценной системы рекомендаций с 0, требуются глубокие знания в линейной алгебре. Из-за чего, если вы никогда не изучали эту дисциплину, вам может быть сложно понять некоторые концепции этого раздела.

Но не беспокойтесь scikit-learn библиотека Python позволяет довольно просто построить СР. Так что вам не потребуется таких уж глубоких познаний в линейной алгебре, чтобы построить рабочую СР.

Как работает СР?


Существует 2 основных типа система рекомендаций:

  • Основанная на контенте(Content-based)
  • Коллаборативная фильтрация(Collaborative filtering)

Основанная на контенте система дает рекомендации, которые базируются на схожести элементов, уже использованных вами. Эти системы ведут себя абсолютно так, как вы ожидаете СР будет себя вести.

Коллаборативная фильтрация СР предоставляет рекоммендации, основанные на знаниях о том как пользователь взаимодействует с элементами(*примечание: за основу взяты взаимодействия с элементами других пользователей, схожих по поведению с данным пользователем). Другими словами, они используют мудрость толпы(отсюда и коллаборативный в названии метода).

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

Коллаборативная фильтрация СР также обладает уникальной особенностью, которой нет в основанной на контенте ситстеме. А именно, у них есть способность обучаться фичам самостоятельно.

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

Существует 2 подкатегории коллаборативной фильтрации:

  • Основанная на модели
  • Основанная на соседстве

Хорошая новость: вам не обязательно знать разницу в этих двух типах коллаборативной фильтрации СР, чтобы быть успешным в МО. Достаточно просто знать, что существует несколько типов.

Подведем итог


Вот краткое резюме того, что мы узнали о системе рекомендаций в данной статье:

  • Примеры системы рекомендаций из реального мира
  • Разные типы системы рекомендаций и почему коллаборативная фильтрация используется чаще, чем основанная на контенте система
  • Связь между системой рекомендаций и линейной алгеброй

Линейная регрессия (Linear Regression)


Линейная регрессия используется для предсказаний некоторого значения y основываясь на некотором множестве значений x.

История линейной регрессии


Линейная регрессия(ЛР) была изобретена в 1800 году Френсисом Гальтоном. Гальтон был ученым, изучающим связь между родителями и детьми. А конкретнее, Гальтон исследовал связь между ростом отцов и ростом их сыновей. Первым открытием Гальтона стал тот факт, что рост сыновей, как правило, был приблизительно таким же как рост их отцов. Что не удивительно.

Позднее, Гальтон открыл нечто более интересное. Рост сына, как правило, был ближе к средне-общему росту всех людей, чем к росту его собственного отца.

Гальтон даль этому феномену название регрессия. В частности, он сказал: " Рост сына имеет тенденцию к регрессии(или к смещению в направлении) среднего роста".

Это привело к целой области в статистике и машинном обучении под названием регрессия.

Математика линейной регрессии


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

Типичный пример такого подхода метод наименьших квадратов линейной регрессии, с помощью которого рассчитывают близость линии в направлении верх-низ.

Пример для иллюстрации:



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

Логистическая регрессия (Logistic Regression)


Логистическая регрессия схожа с линейной, за исключением того факта, что вместо вычисления значения у, она оценивает к какой категории принадлежит данная точка данных.

Что такое логистическая регрессия?


Логистическая регрессия это модель машинного обучения, использующаяся для решения задач классификации.

Ниже представлено несколько примеров классификационных задач МО:

  • Спам электронной почты(спам или не спам?)
  • Претензия по страховке автомобиля (выплата компенсации или починка?)
  • Диагностика болезней

Каждая из этих задач имеет четко 2 категории, что делает их примерами задач двоичной классификации.

Логистическая регрессия хорошо подходит для решения задач двоичной классификации мы просто назначаем разным категориям значения 0 и 1 соответственно.

Зачем нужна логистическая регрессия? Потому что вы не можете использовать линейную регрессию для прогнозов по двоичной классификации. Она просто не будет подходить, так как вы будете пытаться провести прямую линию через набор данных с двумя возможными значениями.

Это изображение может помочь понять почему линейная регрессия плохо подходит для двоичной классификации:



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

Вот почему логистическая регрессионная модель полезна. У нее есть изгиб к линии лучшего соответсвия, что делает ее(модель) гораздо более подходящей для предсказаний качественных(категорийных) данных.

Вот пример, который иллюстрирует сравнение линейной и логистической регрессионых моделей на одних и техже данных:



Сигмоида (The Sigmoid Function)


Причина по которой логистическая регрессия имеет изгиб это тот факт, что для её вычисления не используетя линейное уравнение. Вместо него логистическая регерссионная модель строится на использовании сигмоиды (также называемой логистической функцией, т.к. она используется в логистической регрессии).

Для вас не обязательно досконально запоминать сигмоиду, чтобы преуспеть в МО. Но все-таки иметь некоторое представление об этой функции будет полезно.

Формула сигмоиды:



Главная характеристика сигмоиды, которая стоит того, чтобы с ней разобраться не важно какое значение вы передадите этой функции, она всегда вернет значение в промежутке 0-1.

Использование логистической регрессионной модели для предсказаний


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

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

Использование матрицы ошибок для измерения эффективности логистической регрессии


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

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



В этой таблице TN означает истинно отрицательно, FN ложно отрицательно, FP ложно положительно, TP истинно положительно.

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

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

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

Подведем итог


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

  • Типы задач классификации, которые подходят для решения с помощью логистической регрессии
  • Логистическая функция (сигмоида) всегда дает значение от 0 до 1
  • Как использовать точки отсечения для предсказания с помощью модели логистической регрессии
  • Почему матрица ошибок полезна для измерения эффективности модели логистической регрессии

Алгоритм k-ближайших соседей (K-Nearest Neighbors)


Алгоритм k-ближайших соседей может помочь решить задачу классификации, в случае, когда категорий больше, чем 2.

Что из себя представляет алгоритм k-ближайших соседей?


Это классификационный алгоритм, который базируется на простом принципе. На самом деле, принцип настолько прост, что лучше его продемонстрировать на примере.

Представьте, что у вас есть данные по высоте и весу футболистов и баскетболистов. Алгоритм k-ближайших соседей может быть использован для предсказания является ли новый игрок футболистом или баскетболистом. Чтобы это сделать, алгоритм определяет К точек данных, ближайших к объекту исследования.

Данное изображение демонстрирует этот принцип с параметром К = 3:



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

Как построить алгоритм К-ближайших соседей


Основные шаги для построения данного алгоритма:

  1. Соберите все данные
  2. Вычислите Евклидово расстояние от новой точки данных х до всех остальных точек в множестве данных
  3. Отсортируйте точки из множества данных в порядке возрастания расстояния до х
  4. Спрогнозируйте ответ, используя ту же категорию, что и большинство К-ближайших к х данных

Важность переменной К в алгоритме К-ближайших соседей


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

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

Представленная ниже иллюстрация отлично показывает этот эффект:



Плюсы и минусы алгоритма К-ближайших соседей


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

Плюсы:

  • Алгоритм прост и его легко понять
  • Тривиальное обучение модели на новых тренировочных данных
  • Работает с любым количеством категорий в задаче классификации
  • Легко добавить больше данных в множество данных
  • Модель принимает только 2 параметра: К и метрика расстояния, которой вы хотели бы воспользоваться (обычно это Евклидово расстояние)

Минусы:

  • Высокая стоимость вычисления, т.к. вам требуется обработать весь объем данных
  • Работает не так хорошо с категорическими параметрами

Подведем итог


Краткое содержание того, что вы только что узнали о алгоритме К-ближайших соседей:

  • Пример задачи на классификацию(футболисты или баскетболисты), которую может решить алгоритм
  • Как данный алгоритм использует Евклидово расстояние до соседних точек для прогнозирования к какой категории принадлежит новая точка данных
  • Почему значения параметра К важно для прогнозирования
  • Плюсы и минусы использования алгоритма К-ближайших соседей

Дерево решений и Случайный лес (Decision Trees and Random Forests)


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

Что такое древовидный метод?


Перед тем, как мы нырнем в теоретические основы древовидного метода в МО, будет нелишним начать с примера.

Представьте, что вы играете в баскетбол каждый понедельник. Более того, вы всегда приглашаете одного и того же друга пойти поиграть с вами. Иногда друг действительно приходит, иногда нет. Решение приходить или нет зависит от множества факторов: какая погода, температура, ветер и усталость. Вы начинаете замечать эти особенности и отслеживать их вместе с решением вашего друга играть или нет.

Вы можете использовать эти данные для предсказания придет ли ваш друг сегодня или нет. Одна из техник, которой вы можете воспользоваться это дерево решений. Вот как это выглядит:



У каждого дерева решений есть 2 типа элементов:

  • Узлы (Nodes): места, где дерево разделяется в зависимости от значения определенного параметра
  • Грани (Edges): результат разделения, ведущий к следующему узлу

Вы можете видеть, что на схеме есть узлы для прогноза (outlook), влажности (humidity) и ветра
(windy). И также грани для каждого потенциального значения каждого из этих параметров.

Вот еще парочка определений, которые вы должны понимать перед тем, как мы начнем:

  • Корень (Root) узел, с которого начинается разделение дерева
  • Листья (Leaves) заключительные узлы, которые предсказывают финальный результат

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

Как построить дерево решений с нуля


Построение дерева решений сложнее, чем может показаться. Это происходит потому что решение на какие разветвления (характеристики) делить ваши данные (что является темой из области энтропии и получения данных) это математически сложная задача.

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

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

Выгоды использования случайного леса


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

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

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

Подведем итог


Итак, краткое содержание того, что вы только что узнали о деревьях решений и случайных лесах:

  • Пример задачи, решение которой можно спрогнозировать с помощью дерева решений
  • Элементы дерева решений: узлы, грани, корни и листья
  • Как использование случайного набора характеристик позволяет нам построить случайный лес
  • Почему использование случайного леса для декорреляции переменных может быть полезным для уменьшения дисперсии полученной модели

Метод опорных векторов(Support Vector Machines)


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

Что такое метод опорных векторов?


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

Как МОВ работает?


Давайте капнем поглубже в то, как действительно работает МОВ.

Нам дан набор тренировочных примеров, какждый из которого промаркирован как принадлежащий к одной из 2х категорий, и с помощью этого набора МОВ строит модель. Эта модель распределяет новые примеры в одну из двух категорий. Это делает МОВ невероятностным двоичным линейным классификатором.

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

Вот пример визуализации, который поможет вам понять интуицию МОВ:



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

Давайте посмотрим следующее визуальное представление МОВ:



На этой диаграмме гиперплоскость обозначена как оптимальная гиперплоскость (optimal hyperplane). Теория метода опорных векторов дает такое определение оптимальной гиперплоскости это гиперплоскость, которая максимизирует поле между двумя ближайшими точками данных из разных категорий.

Как вы видите, граница поля действительно затрагивает 3 точки данных 2 из красной категории и 1 из синей. Эти точки, которые соприкасаются с границей поля, и называются опорными векторами откуда и пошло название.

Подведем итог


Вот краткий очерк того, что вы только что узнали о методе опорных векторов:

  • МОВ это пример алгоритма МО с учителем
  • Опорный вектор может быть использован для решения как задач классификации, так и для регрессионного анализа.
  • Как МОВ категоризирует данные с помощью гиперплоскости, которая максимизирует поле между категориями в наборе данных
  • Что точки данных, которые затрагивают границы разделяющего поля, называются опорными векторами. От чего и пошло название метода.

Метод К-средних (K-Means Clustering)


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

  • Сегментация клиентов для маркетинговых групп
  • Классификация документов
  • Оптимизация маршрутов доставки для таких компаний, как Amazon, UPS или FedEx
  • Выявление и реагирование на криминальные локации в городе
  • Профессиональная спортивная аналитика
  • Прогнозирование и предотвращение киберпреступлений

Главная цель метода К-средних разделить множество данных на различимые группы таким образом, чтобы элементы внутри каждой группы были схожи между собой.

Вот визуальное представление того, как это выглядит на практике:



Мы изучим математическую составляющую метода К-средних вследующем разделе этой статьи.

Как работает метод К-средних?


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

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

  • Вычисление центроида (центр тяжести) каждого кластера взяв средний вектор точек в этом кластере
  • Переотнести каждую точку данных к кластеру, центроид которого ближе всего к точке

Выбор подходящего значения К в методе К-средних


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

Для использования этого метода, первое, что вам необходимо сделать, это вычислить сумму квадратов отклонений(sum of squared errors) СКО для вашего алгоритма для группы значений К. СКО в методе К-средних определена как сумма квадратов расстояний между каждой точкой данных в кластере и центром тяжести этого кластера.

В качестве примера этого шага, вы можете вычислить СКО для значений К 2, 4, 6, 8 и 10. Далее вы захотите сгенерировать график СКО и этих значений К. Вы увидите, что отклонение уменьшается с увеличением значения К.

И это имеет смысл: чем больше категорий вы создадите на основе множества данных тем более вероятно, что каждая точка данных окажется близко к центру кластера этой точки.
С учетом сказанного, основная идея метода локтя это выбрать значение К при котором СКО резко замедлит темпы снижения. Это резкое снижение образует локоть на графике.

Как пример, вот график СКО относительно К. В этом случае, метод локтя предложит использовать значение К примерно равное 6.



Важно, что К=6 просто оценка приемлемого значения К. Не существует лучшего значения К в методе К-средних. Как и многие вещи в области МО, это очень зависящее от ситуации решение.

Подведем итог


Вот краткий очерк того, что вы только что узнали в этом разделе:

  • Примеры задач МО без учителя, которые возможно решить методом К-средних
  • Базовые принципы метода К-средних
  • Как работает метод К-средних
  • Как использовать метод локтя для выбора подходящего значения параметра К в данном алгоритме

Метод главных компонент (Principal Component Analysis)


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

Что такое метод главных компонентов?


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

На основании этого описания вы можете подумать, что МГК очень схож с линейной регрессией. Но это не так. На самом деле, эти 2 техники имеют несколько важных отличий.

Различия линейной регрессии и МГК


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

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

Взгляните на метки осей на этом изображении. Главный компонент оси х объясняет 73% дисперсии в этом наборе данных. Главный компонент оси у объясняет около 23% дисперсии набора данных.

Это означает, что 4% дисперсии остается необъясненными. Вы можете уменьшить это число добавляя больше главных компонент в ваш анализ.

Подведем итог


Краткое содержание того, что вы только что узнали о методе главных компонент:

  • МГК пытается найти ортогональные факторы, которые определяют изменчивость в наборе данных
  • Разницу между линейной регрессией и МГК
  • Как выглядит ортогональные главные компоненты, визуализированные в наборе данных
  • Что добавление дополнительных главных компонент может помочь объяснить дисперсию более точно в наборе данных
Подробнее..

FAISS Быстрый поиск лиц и клонов на многомиллионных данных

02.07.2020 12:23:15 | Автор: admin


Однажды в преддверии клиентской конференции, которую ежегодно проводит группа DAN, мы размышляли над тем, что интересного можно придумать, чтобы у наших партнеров и клиентов остались приятные впечатления и воспоминания о мероприятии. Мы решили разобрать архив из тысяч фотографий с этой конференции и нескольких прошлых (а всего их к тому моменту было 18): человек отправляет нам свою фотографию, а мы ему через пару секунд отправляем подборку фотографий с ним за несколько лет из наших архивов.

Велосипед мы не придумывали, взяли всем известную библиотеку dlib и получили эмбеддинги (векторные представления) каждого лица.

Добавили Telegram-бота для удобства, и всё было отлично. С точки зрения алгоритмов распознавания лиц всё работало на ура, но конференция завершилась, а расставаться с опробованными технологиями не хотелось. От нескольких тысяч лиц хотелось перейти к сотням миллионов, но конкретной бизнес-задачи у нас не было. Через некоторое время у наших коллег появилась задача, которая требовала работы с такими большими объемами данных.

Вопрос был в том, чтобы написать умную систему мониторинга ботов внутри сети Instagram. Тут наша мысль породила простой и сложный подходы:

Простой путь: Рассматриваем все аккаунты, у которых подписок гораздо больше, чем подписчиков, нет аватарки, не заполнено full name и т.д. В итоге получаем непонятную толпу полумертвых аккаунтов.

Сложный путь: Так как современные боты стали намного умнее, и теперь они выкладывают посты, спят, да еще и контент пишут, встаёт вопрос: как таких поймать? Во-первых, внимательно следить за их друзьями, так как часто они тоже бывают ботами, и отслеживать дублирующие фотки. Во-вторых, редко какой бот умеет генерировать свои фотки (хотя и такое возможно), а значит, дубли фото людей в разных аккаунтах в Инстаграме являются хорошим триггером для поиска сети ботов.

Что дальше?


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

  1. Скорость и точность поиска
  2. Размер занимаемого данными места на диске
  3. Размер используемой RAM памяти.

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

Существуют известные и зарекомендовавшие себя технологии, такие как Annoy, FAISS, HNSW. Быстрый алгоритм поиска соседей HNSW , доступный в библиотеках nmslib и hnswlib, показывает state-of-the-art результаты на CPU, что видно по тем же бенчмаркам. Но его мы отсекли сразу, так как нас не устраивает количество используемой памяти при работе с действительно большими объемами данных. Мы стали выбирать между Annoy и FAISS и в итоге выбрали FAISS из-за удобства, меньшего использования памяти, потенциальной возможности использования на GPU и бенчмарков по результативности (посмотреть можно, например, здесь). К слову, в FAISS алгоритм HNSW реализован как опция.

Что такое FAISS?


Facebook AI Research Similarity Search разработка команды Facebook AI Research для быстрого поиска ближайших соседей и кластеризации в векторном пространстве. Высокая скорость поиска позволяет работать с очень большими данными до нескольких миллиардов векторов.

Основное преимущество FAISS state-of-the-art результаты на GPU, при этом его реализация на CPU незначительно проигрывает hnsw (nmslib). Нам хотелось иметь возможность вести поиск как на CPU, так и на GPU. Кроме того, FAISS оптимизирован в части использования памяти и поиска на больших батчах.

Source

FAISS позволяет быстро осуществлять операцию поиска k ближайших векторов для данного вектора x. Но как же этот поиск устроен под капотом?

Индексы


Главное понятие в FAISS это index, и, по сути, это просто набор параметров и векторов. Наборы параметров бывают совершенно разные и зависят от нужд пользователя. Векторы могут оставаться неизменными, а могут перестраиваться. Некоторые индексы доступны для работы сразу после добавления в них векторов, а некоторые требуют предварительного обучения. Имена векторов хранятся в индексе: либо в нумерации от 0 до n, либо в виде числа, влезающего в тип Int64.

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

Пример:

import numpy as npdim = 512  # рассмотрим произвольные векторы размерности 512nb = 10000  # количество векторов в индексеnq = 5 # количество векторов в выборке для поискаnp.random.seed(228)vectors = np.random.random((nb, dim)).astype('float32')query = np.random.random((nq, dim)).astype('float32')

Создаем Flat индекс и добавляем векторы без обучения:

import faissindex = faiss.IndexFlatL2(dim)print(index.ntotal)  # пока индекс пустойindex.add(vectors)print(index.ntotal)  # теперь в нем 10 000 векторов

Теперь найдем 7 ближайших соседей для первых пяти векторов из vectors:

topn = 7D, I = index.search(vectors[:5], topn)  # Возвращает результат: Distances, Indicesprint(I)print(D)

Output
[[0 5662 6778 7738 6931 7809 7184] [1 5831 8039 2150 5426 4569 6325] [2 7348 2476 2048 5091 6322 3617] [3  791 3173 6323 8374 7273 5842] [4 6236 7548  746 6144 3906 5455]][[ 0.  71.53578  72.18823  72.74326  73.2243   73.333244 73.73317 ] [ 0.  67.604805 68.494774 68.84221  71.839905 72.084335 72.10817 ] [ 0.  66.717865 67.72709  69.63666  70.35903  70.933304 71.03237 ] [ 0.  68.26415  68.320595 68.82381  68.86328  69.12087  69.55179 ] [ 0.  72.03398  72.32417  73.00308  73.13054  73.76181  73.81281 ]]


Видим, что самые близкие соседи с расстоянием 0 это сами векторы, остальные отранжированы по увеличению расстояния. Проведем поиск по нашим векторам из query:

D, I = index.search(query, topn) print(I)print(D)

Output
[[2467 2479 7260 6199 8640 2676 1767] [2623 8313 1500 7840 5031   52 6455] [1756 2405 1251 4136  812 6536  307] [3409 2930  539 8354 9573 6901 5692] [8032 4271 7761 6305 8929 4137 6480]][[73.14189  73.654526 73.89804  74.05615  74.11058  74.13567  74.443436] [71.830215 72.33813  72.973885 73.08897  73.27939  73.56996  73.72397 ] [67.49588  69.95635  70.88528  71.08078  71.715965 71.76285  72.1091  ] [69.11357  69.30089  70.83269  71.05977  71.3577   71.62457  71.72549 ] [69.46417  69.66577  70.47629  70.54611  70.57645  70.95326  71.032005]]


Теперь расстояния в первом столбце результатов не нулевые, так как векторов из query нет в индексе.

Индекс можно сохранить на диск и затем загрузить с диска:

faiss.write_index(index, "flat.index")index = faiss.read_index("flat.index")

Казалось бы, всё элементарно! Несколько строчек кода и мы уже получили структуру для поиска по векторам высокой размерности. Но такой индекс всего с десятком миллионов векторов размерности 512 будет весить около 20Гб и занимать при использовании столько же RAM.

В проекте для конференции мы использовали именно такой базовый подход с flat index, всё было замечательно благодаря относительно маленькому объему данных, однако сейчас речь идет о десятках и сотнях миллионов векторов высокой размерности!

Ускоряем поиск с помощью Inverted lists



Source

Основная и наикрутейшая особенность FAISS IVF index, или Inverted File index. Идея Inverted files лаконична, и красиво объясняется на пальцах:

Давайте представим себе гигантскую армию, состоящую из самых разношерстных воинов, численностью, скажем, в 1 000 000 человек. Командовать всей армией сразу будет невозможно. Как и принято в военном деле, нужно разделить нашу армию на подразделения. Давайте разделим на $\sqrt{1 000 000} = 1000$ примерно равных частей, выбрав на роли командиров по представителю из каждого подразделения. И постараемся отправить максимально похожих по характеру, происхождению, физическим данным и т.д. воинов в одно подразделение, а командира выберем таким, чтобы он максимально точно представлял свое подразделение был кем-то средним. В итоге наша задача свелась от командования миллионом воинов к командованию 1000-ю подразделениями через их командиров, и мы имеем отличное представление о составе нашей армии, так как знаем, что из себя представляют командиры.

В этом и состоит идея IVF индекса: сгруппируем большой набор векторов по частям с помощью алгоритма k-means, каждой части поставив в соответствие центроиду, вектор, являющийся выбранным центром для данного кластера. Поиск будем осуществлять через минимальное расстояние до центроид, и только потом искать минимальные расстояния среди векторов в том кластере, что соответствует данной центроиде. Взяв k равным $\sqrt{n}$, где $n$ количество векторов в индексе, мы получим оптимальный поиск на двух уровнях сначала среди $\sqrt{n}$ центроид, затем среди $\sqrt{n}$ векторов в каждом кластере. Поиск по сравнению с полным перебором ускоряется в разы, что решает одну из наших проблем при работе с множеством миллионов векторов.


Пространство векторов разбивается методом k-means на k кластеров. Каждому кластеру в соответствие ставится центроида

Пример кода:

dim = 512k = 1000  # количество командировquantiser = faiss.IndexFlatL2(dim) index = faiss.IndexIVFFlat(quantiser, dim, k)vectors = np.random.random((1000000, dim)).astype('float32')  # 1 000 000 воинов

А можно это записать куда более элегантно, воспользовавшись удобной штукой FAISS для построения индекса:

index = faiss.index_factory(dim, IVF1000,Flat)Запускаем обучение:print(index.is_trained)   # False.index.train(vectors)  # Train на нашем наборе векторов # Обучение завершено, но векторов в индексе пока нет, так что добавляем их в индекс:print(index.is_trained)  # Trueprint(index.ntotal)   # 0index.add(vectors)print(index.ntotal)   # 1000000

Рассмотрев такой тип индекса после Flat, мы решили одну из наших потенциальных проблем скорость поиска, которая становится в разы меньше по сравнению с полным перебором.

D, I = index.search(query, topn) print(I)print(D)

Output
[[19898 533106 641838 681301 602835 439794 331951] [654803 472683 538572 126357 288292 835974 308846] [588393 979151 708282 829598  50812 721369 944102] [796762 121483 432837 679921 691038 169755 701540] [980500 435793 906182 893115 439104 298988 676091]][[69.88127  71.64444  72.4655   72.54283  72.66737  72.71834  72.83057] [72.17552  72.28832  72.315926 72.43405  72.53974  72.664055 72.69495] [67.262115 69.46998  70.08826  70.41119  70.57278  70.62283  71.42067] [71.293045 71.6647   71.686615 71.915405 72.219505 72.28943  72.29849] [73.27072  73.96091  74.034706 74.062515 74.24464  74.51218  74.609695]]


Но есть одно но точность поиска, как и скорость, будет зависеть от количества посещаемых кластеров, которое можно задать с помощью параметра nprobe:

print(index.nprobe)  # 1  заходим только в один кластер и ведем поиск только в нёмindex.nprobe = 16  # Проходим по топ-16 центроид для поиска top-n ближайших соседейD, I = index.search(query, topn) print(I)print(D)

Output
[[ 28707 811973  12310 391153 574413  19898 552495] [540075 339549 884060 117178 878374 605968 201291] [588393 235712 123724 104489 277182 656948 662450] [983754 604268  54894 625338 199198  70698  73403] [862753 523459 766586 379550 324411 654206 871241]][[67.365585 67.38003  68.17187  68.4904   68.63618  69.88127  70.3822] [65.63759  67.67015  68.18429  68.45782  68.68973  68.82755  69.05] [67.262115 68.735535 68.83473  68.88733  68.95465  69.11365  69.33717] [67.32007  68.544685 68.60204  68.60275  68.68633  68.933334 69.17106] [70.573326 70.730286 70.78615  70.85502  71.467674 71.59512  71.909836]]


Как видно, после увеличения nprobe имеем совсем другие результаты, топ наименьших расстояний в D стал лучше.

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

Ведем поиск по диску On Disk Inverted Lists


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

Конкретно для нашей задачи основное преимущество FAISS в возможности хранить Inverted Lists IVF индекса на диске, загружая в RAM только метаданные.

Как мы создаем такой индекс: обучаем indexIVF с нужными параметрами на максимально возможном объеме данных, который влезает в память, затем в обученный индекс по частям добавляем векторы (побывавшие в обучении и не только) и записываем на диск индекс для каждой из частей.

index = faiss.index_factory(512, ,IVF65536, Flat, faiss.METRIC_L2)

Обучение индекса на GPU осуществляем таким образом:

res = faiss.StandardGpuResources()index_ivf = faiss.extract_index_ivf(index)index_flat = faiss.IndexFlatL2(512)clustering_index = faiss.index_cpu_to_gpu(res, 0, index_flat)  #  0  номер GPUindex_ivf.clustering_index = clustering_index

faiss.index_cpu_to_gpu(res, 0, index_flat) можно заменить на faiss.index_cpu_to_all_gpus(index_flat), чтобы использовать все GPU вместе.

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

train_vectors = ...  # предварительно сформированный датасет для обученияindex.train(train_vectors)# Сохраняем пустой обученный индекс, содержащий только параметры:faiss.write_index(index, "trained_block.index") # Поочередно создаем новые индексы на основе обученного# Блоками добавляем в них части датасета:for bno in range(first_block, last_block+ 1):    block_vectors = vectors_parts[bno]    block_vectors_ids = vectors_parts_ids[bno]  # id векторов, если необходимо    index = faiss.read_index("trained_block.index")    index.add_with_ids(block_vectors, block_vectors_ids)    faiss.write_index(index, "block_{}.index".format(bno))

После этого объединяем все Inverted Lists воедино. Это возможно, так как каждый из блоков, по сути, является одним и тем же обученным индексом, просто с разными векторами внутри.

ivfs = []for bno in range(first_block, last_block+ 1):    index = faiss.read_index("block_{}.index".format(bno), faiss.IO_FLAG_MMAP)    ivfs.append(index.invlists)    # считать index и его inv_lists независимыми    # чтобы не потерять данные во время следующей итерации:    index.own_invlists = False# создаем финальный индекс:index = faiss.read_index("trained_block.index")# готовим финальные invlists# все invlists из блоков будут объединены в файл merged_index.ivfdatainvlists = faiss.OnDiskInvertedLists(index.nlist, index.code_size, "merged_index.ivfdata")ivf_vector = faiss.InvertedListsPtrVector() for ivf in ivfs:     ivf_vector.push_back(ivf)ntotal = invlists.merge_from(ivf_vector.data(), ivf_vector.size())index.ntotal = ntotal  # заменяем листы индекса на объединенныеindex.replace_invlists(invlists)  faiss.write_index(index, data_path + "populated.index")  # сохраняем всё на диск

Итог: теперь наш индекс это файлы populated.index и merged_blocks.ivfdata.

В populated.index записан первоначальный полный путь к файлу с Inverted Lists, поэтому, если путь к файлу ivfdata по какой-то причине изменится, при чтении индекса потребуется использовать флаг faiss.IO_FLAG_ONDISK_SAME_DIR, который позволяет искать ivfdata файл в той же директории, что и populated.index:

index = faiss.read_index('populated.index', faiss.IO_FLAG_ONDISK_SAME_DIR)

За основу был взят demo пример из Github проекта FAISS.

Мини-гайд по выбору индекса можно посмотреть в FAISS Wiki. Например, мы смогли поместить в RAM тренировочный датасет из 12 миллионов векторов, поэтому выбрали IVFFlat индекс на 262144 центроидах, чтобы затем масштабироваться до сотен миллионов. Также в гайде предлагается использовать индекс IVF262144_HNSW32, в котором принадлежность вектора к кластеру определяется по алгоритму HNSW с 32 ближайшими соседями (иными словами, используется quantizer IndexHNSWFlat), но, как нам показалось при дальнейших тестах, поиск по такому индексу менее точен. Кроме того, следует учитывать, что такой quantizer исключает возможность использования на GPU.

Спойлер:
Даже при использовании on disk inverted lists FAISS по возможности загружает данные в оперативную память. Так как RAM памяти на этапах тестов нам хватало, пусть и с трудом, а для масштабных тестов было необходимо иметь значительно больший запас данных здесь и сейчас, тесты на объемах свыше объема RAM не проводились. Но FAISS wiki и обсуждения данного подхода на Github говорят, что всё должно работать корректно.


Значительно уменьшаем использование дискового пространства с Product Quantization


Благодаря методу поиска с диска удалось снять нагрузку с RAM, но индекс с миллионом векторов всё равно занимал около 2 ГБ дискового пространства, а мы рассуждаем о возможности работы с миллиардами векторов, что потребовало бы более двух ТБ! Безусловно, объем не такой большой, если задаться целью и выделить дополнительное дисковое пространство, но нас это немного напрягало.

И тут приходит на помощь кодирование векторов, а именно Scalar Quantization (SQ) и Product Quantization (PQ). SQ кодирование каждой компоненты вектора n битами (обычно 8, 6 или 4 бит). Мы рассмотрим вариант PQ, ведь идея кодирования одной компоненты типа float32 восемью битами выглядит уж слишком удручающе с точки зрения потерь в точности. Хотя в некоторых случаях сжатие SQfp16 до типа float16 будет почти без потерь в точности.

Суть Product Quantization состоит в следующем: векторы размерности 512 разбиваются на n частей, каждая из которых кластеризуется по 256 возможным кластерам (1 байт), т.е. мы представляем вектор с помощью n байт, где n обычно не превосходит 64 в реализации FAISS. Но применяется такая квантизация не к самим векторам из датасета, а к разностям этих векторов и соответствующих им центроид, полученным на этапе генерации Inverted Lists! Выходит, что Inverted Lists будут представлять из себя кодированные наборы расстояний между векторами и их центроидами.

index = faiss.index_factory(dim, "IVF262144,PQ64", faiss.METRIC_L2)

Выходит, что теперь нам не обязательно хранить все векторы достаточно выделять n байт на вектор и 2048 байт на каждый вектор центроиды. В нашем случаем мы взяли $n = 64$, то есть $\frac{512}{64} = 8$ длина одного субвектора, который определяется в один из 256 кластеров.



При поиске по вектору x сначала обычным Flat квантайзером будут определяться ближайшие центроиды, а затем x так же разделяется на суб-векторы, каждый из которых кодируется номером одной из 256 соответствующей центроиды. И расстояние до вектора определяется как сумма из 64 расстояний между суб-векторами.

Что в итоге?


Мы остановили свои эксперименты на индексе IVF262144, PQ64, так как он полностью удовлетворил все наши нужды по скорости и точности поиска, а также обеспечил разумное использование дискового пространства при дальнейшем масштабировании индекса. Если говорить конкретнее, на данный момент при 315 миллионах векторов индекс занимает 22 Гб дискового пространства и около 3 Гб RAM при использовании.

Еще одна интересная деталь, которую мы не упоминали ранее, метрика, используемая индексом. По умолчанию расстояния между любыми двумя векторами считаются в евклидовой метрике L2, или более понятным языком, расстояния считаются как квадратный корень из суммы квадратов покоординатных разностей. Но задать метрику можно и другую, в частности, мы тестировали метрику METRIC_INNER_PRODUCT, или метрику косинусных расстояний между векторами. Косинусная она потому, что косинус угла между двумя векторами в Евклидовой системе координат выражается как отношение скалярного (покоординатного) произведения векторов к произведению их длин, а если все векторы в нашем пространстве имеют длину 1, то косинус угла будет в точности равен покоординатному произведению. В таком случае чем ближе расположены векторы в пространстве, тем ближе к единице будет их скалярное произведение.

Метрика L2 имеет непосредственный математический переход к метрике скалярных произведений. Однако при экспериментальном сравнении двух метрик сложилось впечатление, что метрика скалярных произведений помогает нам анализировать коэффициенты похожести изображений более удачным образом. К тому же эмбеддинги наших фотографий были получены с помощью InsightFace, в котором реализована архитектура ArcFace, использующая косинусные расстояния. Также есть и другие метрики в индексах FAISS, о которых можно почитать здесь.

пару слов о GPU
Обучение и использование индексов FAISS на GPU весьма ограничено в выборе параметров индекса, а при работе с гигантскими объемами данных высокой размерности использование если и будет возможным, то вызовет трудности, несопоставимые с полученным результатом. К тому же на GPU реализована только метрика L2.

Однако, стоит заметить, что для использования индекса с PQ квантилизацией на GPU требуется ограничить размер кода 56-ю байтами, либо в случае большего размера сменить float32 на float16, связано это с ограничениями на используемую память.

В итоге о FAISS на GPU мы думать перестали, потому что CPU реализация нас полностью устроила по скорости, и хотелось сохранить работу с метрикой скалярных произведений, что на GPU недоступно. Чтобы регулировать нагрузку на процессоры при работе с индексами, можно задать максимальное число используемых процессоров:

faiss.omp_set_num_threads(N)


Заключение и любопытные примеры


Итак, вернемся же к тому, с чего всё начиналось. А начиналось, напомним, с мотивации решить задачу поиска ботов в сети Instagram, а конкретнее искать дубликаты постов с людьми или аватарок в определенных множествах юзеров. В процессе написания материала стало понятно, что подробное описание нашей методологии поиска ботов тянет на отдельную статью, о чем мы расскажем в следующих публикациях, а пока ограничимся примерами наших экспериментов с FAISS.

Векторизовать картинки или лица можно по-разному, мы выбрали технологию InsightFace (векторизация изображений и выделение n-мерных фичей из них это отдельная долгая история). В ходе экспериментов с полученной нами инфраструктурой были обнаружены довольно интересные и забавные свойства.

Например, заручившись разрешением коллег и знакомых, мы загрузили в поиск их лица и быстро нашли фотографии, на которых они присутствуют:


Наш коллега попал на фотографию посетительницы Comic-Con, оказавшись на заднем фоне в толпе. Источник


Пикник в многочисленной компании друзей, фотография из аккаунта подруги. Источник


Просто проходили мимо. Неизвестный фотограф запечатлел ребят для своего тематического профиля. Они не знали, куда попала их фотография, а спустя 5 лет и вовсе забыли, как их фотографировали. Источник


В этом случае и фотограф неизвестен, и сфотографировали тайно!
Сразу вспомнилась подозрительная девушка с зеркальным фотоаппаратом, сидевшая в тот момент напротив:) Источник


Таким образом, путём нехитрых действий FAISS позволяет собрать на коленке аналог всем известного FindFace.

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


Некоторые из клонов автора.
Источники фото: 1, 2,3


Вообще говоря, FAISS открывает огромное поле для реализации каких-либо творческих идей. Например, по тому же принципу векторной близости похожих лиц можно было бы строить пути от одного лица к другому. Или в крайнем случае сделать из FAISS фабрику по производству подобных мемов:


Source

Благодарим за внимание и надеемся что этот материал будет полезен читателям Хабра!

Статья написана при поддержке моих коллег Артёма Королёва (korolevart), Тимура Кадырова и Арины Решетниковой.

R&D Dentsu Aegis Network Russia.
Подробнее..

Датасеты для automotive

23.06.2020 22:21:05 | Автор: admin

1. A2D2 dataset от Audi


image

Наш набор данных включает в себя более 40 000 кадров с семантической сегментацией изображений и метками облака точек, из которых более 12 000 кадров также имеют аннотации для 3D-боксов. Кроме того, мы предоставляем немаркированные данные датчиков (прибл. 390 000 кадров) для последовательностей с несколькими циклами, записанных в трех городах.

Сегментация данных
Набор данных содержит 41 280 кадров с семантической сегментацией по 38 категориям. Каждому пикселю изображения присваивается метка, описывающая тип объекта, который он представляет, например пешехода, автомобиль, растительность и т. д.

Облако точек
Сегментация облака точек производится путем слияния семантической пиксельной информации и лидарных облаков точек. Таким образом, каждой 3D-точке присваивается метка типа объекта. Это зависит от точной регистрации камеры-лидара.

Рамки
3D-боксы предусмотрены для 12 499 кадров. Лидарные точки в поле зрения фронтальной камеры помечены 3D-рамками. Мы аннотируем 14 классов, имеющих отношение к вождению, например автомобили, пешеходы, автобусы и т. д.

2. Ford Autonomous Vehicle Dataset


image

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

Мы представляем сезонные изменения погодных условий, освещения, строительства и дорожного движения, наблюдаемые в динамичных городских условиях. Этот датасет может помочь в разработке надежных алгоритмов для автономных транспортных средств и мультиагентных систем. Каждый лог в наборе данных помечен временем и содержит необработанные данные со всех датчиков, калибровочные значения, pose trajectory, ground truth pose и 3D-карты. Все данные доступны в формате Rosbag, который может быть визуализирован, изменен и применен с помощью операционной системы робота с открытым исходным кодом (ROS).

Датасетх содержит данные с отметкой времени полного разрешения от следующих датчиков:

  • Четыре HDL-32E Velodyne 3D-лидара
  • 6 градаций серого 1.3 MP камеры
  • 1 градация серого 5 MP Dash камера
  • Applanix POS-LV IMU


Датасет также включает в себя:

  • 3D Ground Reflectivity Maps
  • 3D Point Cloud Maps
  • 6 DoF Ground-truth Pose
  • 3 DoF Localized Pose
  • Преобразование и калибровка датчиков


3. Waymo Open Dataset


image

Waymo Open Dataset в настоящее время содержит 1 950 сегментов. Мы планируем увеличить этот набор данных в будущем. Вот что в настоящее время включено:

1950 сегментов по 20 секунд каждый, собранных на частоте 10 Гц (200 000 кадров) в различных географических условиях и условиях

Данные сенсоров

  • 1 лидар среднего радиуса действия
  • 4 лидар ближнего действия
  • 5 камер (передняя и боковые)
  • Синхронизированные данные лидара и камеры
  • Лидар к проекциям камеры
  • Калибровка датчиков и позиции транспортных средств


Размеченные данные

  • Маркировки для 4 классов объектов транспортные средства, пешеходы, велосипедисты, знаки
  • Высококачественные маркировки для лидарных данных в 1200 сегментах
  • 12.6M 3D-боксы с маркировкой с отслеживающими идентификаторами на лидарных данных
  • Высококачественные маркировки для данных камеры в 1000 сегментах
  • 11.8M 2D-боксы с маркировкой с идентификаторами отслеживания на данных камеры

Исходники
github.com/waymo-research/waymo-open-dataset

4. nuTonomy


image

Датасет nuScenes это крупномасштабный автономный набор данных для вождения. Он имеет следующие особенности:

  • Полный набор датчиков (1X лидар, 5X радар, 6X камера, IMU, GPS)
  • 1000 сцен по 20 секунд каждая
  • 1 400 000 изображений камеры
  • 390 000 лидарных проходов
  • Два разных города: Бостон и Сингапур
  • Левостороннее и правостороннее движение
  • Подробная информация о карте
  • Ручные аннотации для 23 классов объектов
  • 1.4M 3D-боксы аннотированные на частоте 2 Гц
  • Атрибуты, такие как видимость, активность и поза


5. Dataset | Lyft Level 5


image

Все данные собираются автопарком автомобилей Ford Fusion. У нас есть две версии транспортных средств. Они указаны в их калибровочных данных как BETA_V0 и BETA_PLUS_PLUS. Каждый автомобиль оснащен следующими датчиками в зависимости от версии автомобиля:

image
BETA_V0 LiDARS:

  • Один 40-лучевой лидар на крыше и два 40-лучевых лидара на бампере.
  • Каждый лидар имеет разрешение по азимуту 0,2 градуса.
  • Все три лидара совместно производят ~216 000 точек при частоте 10 Гц.
  • Направления зондирования всех лидаров синхронизированы, чтобы быть одинаковыми в любой момент времени.


BETA_V0 Cameras:

  • Шесть камер с широким полем зрения (WFOV) равномерно охватывают поле зрения на 360 градусов (FOV). Каждая камера имеет разрешение 1224x1024 и FOV 70x60.
  • Одна камера с большим фокусным расстоянием установлена немного вверх, главным образом для обнаружения светофоров. Камера имеет разрешение 2048x864 и FOV 35x15.
  • Каждая камера синхронизирована с лидаром таким образом, что Луч лидара находится в центре поля зрения камеры, когда камера захватывает изображение.


image

BETA_PLUS_PLUS LiDARS:

Единственное различие в лидарах между Beta-V0 и Beta++ это лидар на крыше, который является 64-лучевым для Beta++.
Синхронизация лидаров такая же, как и у Beta-V0.

BETA_PLUS_PLUS Cameras:

  • Шесть камер с широким полем зрения (FOV) с высоким динамическим диапазоном равномерно охватывают 360-градусное поле зрения (FOV). Каждая камера имеет разрешение 1920х1080 и FOV 82x52.
  • Одна камера с большим фокусным расстоянием установлена немного вверх, главным образом для обнаружения светофоров. Камера имеет разрешение 1920х1080 и FOV 27x17.
  • Каждая камера синхронизирована с лидаром таким образом, что Луч лидара находится в центре поля зрения камеры, когда камера захватывает изображение.


Этот датасет включает в себя высококачественную семантическую карту. Семантическая карта предоставляет контекст для принятия решений о присутствии и движении агентов в сценах. Предоставленная карта содержит более 4000 сегментов полос движения (2000 дорожных сегментов и около 2000 перекрестков), 197 пешеходных переходов, 60 стоп-знаков, 54 парковочных зоны, 8 лежачих полицейских, 11 лежачих полицейских.

Все элементы карты регистрируются в базовой геометрической карте. Это одна и та же система отсчета для всех сцен в наборе данных.

6. UC Berkeley open-sources self-driving dataset


image

Video Data
Исследуйте 100 000 HD-видеопоследовательностей более чем 1100-часового опыта вождения в разное время суток, погодных условий и сценариев вождения. Наши видеопоследовательности также включают в себя местоположение GPS, данные IMU и временные метки.

Road Object Detection
2D-боксы аннотированы на 100 000 изображениях для автобуса, светофора, дорожного знака, человека, велосипеда, грузовика, мотора, автомобиля, поезда и всадника.

Instance Segmentation
Исследуйте более 10 000 разнообразных изображений с аннотациями на уровне пикселей и rich instance-level.

Driveable Area
Изучите сложное решение по управлению автомобилем из 100 000 изображений.

Lane Markings
Multiple types of lane marking annotations on 100,000 images for driving guidance.
Многотипное аннотирование разметки полосы движения на 100 000 изображениях для навигации.

7. The Cityscapes Dataset от Daimler


image

The Cityscapes Dataset focuses on semantic understanding of urban street scenes. In the following, we give an overview on the design choices that were made to target the datasets focus.

Cityscapes Dataset фокусируется на семантическом понимании городских уличных сцен. Ниже мы дадим обзор вариантов дизайна, которые были сделаны для того, чтобы достичь целей датасета.

Полигональные аннотации

  • Плотная семантическая сегментация
  • Сегментация экземпляров для транспортных средств и людей


Сложность



Разнообразие

  • 50 городов
  • Несколько месяцев (весна, лето, осень)
  • Дневное время
  • Хорошие / средние погодные условия
  • Выбранные вручную кадры
    • Большое количество динамических объектов
    • Различные сцены макет
    • Изменение фона



Размер

  • 5 000 аннотированных изображений с прекрасными аннотациями (примеры)
  • 20 000 аннотированных изображений с грубыми аннотациями (примеры)


Метаданные

  • Предшествующие и конечные видеокадры. Каждое аннотированное изображение является 20-м изображением из 30-кадровых фрагментов видео (1,8 с)
  • Соответствующие правые стерео виды
  • координаты GPS
  • Данные эго-движения из одометрии транспортного средства
  • Наружная температура от датчика автомобиля


Расширения, сделанные другими исследователями

  • Ограничивающая коробка аннотации людей
  • Изображения дополненные туманом и дождем


Benchmark suite и оценочный сервер

  • Семантическая маркировка пиксельного уровня
  • Семантическая маркировка на уровне экземпляра
  • Паноптическая семантическая маркировка


8. The KITTI Vision Benchmark Suite


image

Наша записывающая платформа оснащена четырьмя видео высокого разрешения камеры, лазерный сканер Velodyne и современная система локализации. Наши бенчмарки составляют 389 пар стерео и оптических потоков, стереовизуальные одометрические последовательности длиной 39,2 км и более 200 тысяч 3D-аннотаций объектов, снятых в захламленных сценариях (до 15 автомобилей и 30 пешеходов на изображении).



image

О компании ИТЭЛМА
Мы большая компания-разработчик automotive компонентов. В компании трудится около 2500 сотрудников, в том числе 650 инженеров.

Мы, пожалуй, самый сильный в России центр компетенций по разработке автомобильной электроники. Сейчас активно растем и открыли много вакансий (порядка 30, в том числе в регионах), таких как инженер-программист, инженер-конструктор, ведущий инженер-разработчик (DSP-программист) и др.

У нас много интересных задач от автопроизводителей и концернов, двигающих индустрию. Если хотите расти, как специалист, и учиться у лучших, будем рады видеть вас в нашей команде. Также мы готовы делиться экспертизой, самым важным что происходит в automotive. Задавайте нам любые вопросы, ответим, пообсуждаем.

Читать еще полезные статьи:

Подробнее..

Перевод Алгоритм MADDPG OpenAI

29.06.2020 14:12:48 | Автор: admin
Начинаем неделю с продолжения серии статей, подготовленных специально для базового и продвинутого курсов Математика для Data Science.

В конце статьи, поделимся с вами списком самых интересных материалов по этой теме.




Новый подход


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

  • Нестационарности между независимыми агентами;
  • Экспоненциального роста пространств действий и состояний.


Исследователи нашли множество способов уменьшить воздействие этих факторов. Большая часть этих методов попадает под понятие централизованного планирования с децентрализованным выполнением.

Централизованное планирование


У каждого агента есть прямой доступ к локальным наблюдениям. Эти наблюдения могут быть самыми разнообразными: изображения окружающей среды, положения относительно определенных ориентиров или даже положения относительно других агентов. Помимо этого, во время обучения все агенты управляются центральным модулем или критиком.

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

Децентрализованное выполнение


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

OpenAI


Исследователи из OpenAI, Калифорнийского университета в Беркли и Университета Макгилла, представили новый подход к мультиагентным настройкам с помощью Multi-Agent Deep Deterministic Policy Gradient. Такой подход, вдохновленный своим одноагентным аналогом DDPG, использует обучение вида актер-критик и показывает очень многообещающие результаты.

Архитектура


Данная статья предполагает, что вы знакомы с одноагентной версией MADDPG: Deep Deterministic Policy Gradients или DDPG. Чтобы освежить память, вы можете прочитать замечательную статью Криса Юна.

У каждого агента есть пространство наблюдений и непрерывное пространство действий. Также у каждого агента есть три компонента:

  • Сеть актеров, который использует локальные наблюдения для детерминированных действий;
  • Целевая сеть актеров с аналогичным функционалом для стабильного обучения;
  • Сеть критиков, которая использует совместные пары состояние-действие для оценки Q-значений.


По мере того, как критик с течением времени изучает совместные Q-значения функции, он отправляет соответствующие приближения Q-значения актеру, чтобы помочь в обучении. В следующем разделе мы рассмотрим это взаимодействие подробнее.

Помните, что критик может быть общей сетью между всеми N агентами. Другими словами, вместо того чтобы обучать N сетей, которые оценивают одно и то же значение, просто обучите одну сеть и используйте ее, чтобы она помогла обучению всех остальных агентов. То же самое относится и к сетям актеров, если агенты однородные.


Архитектура MADDPG (Lowe, 2018)

Обучение


Во-первых, MADDPG использует воспроизведение опыта (experience replay) для эффективного off-policy обучения. На каждом промежутке времени агент хранит следующий переход:



Где мы храним совместное состояние, следующее совместное состояние, совместное действие и каждое из вознаграждений, полученных агентом. Затем мы берем набор таких переходов из experience replay для обучения нашего агента.

Обновления критика


Для обновления центрального критика агента мы используем lookahead TD-ошибку:



Где это актер. Помните о том, что это центральный критик, то есть он использует общую информацию для обновления своих параметров. Основная идея заключается в том, что если знать действия, которые предпринимают все агенты, то окружающая среда будет стационарной даже при изменении политики.

Обратите внимание на правую часть выражения с расчетом Q-значения. Несмотря на то, что мы никогда не сохраняем наши следующие совместные действия, мы используем каждого целевого актера агента для вычисления следующего действия во время обновления, чтобы сделать обучение более стабильным. Параметры целевого актера периодически обновляются, чтобы соответствовать параметрам актера агента.

Обновления актеров


Подобно одноагентной DDPG мы используем deterministic policy gradient для обновления каждого параметра актера агента.



Где это актер агента.

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

Выводы из политик и ансамбли политик


Мы можем сделать еще один шаг в вопросе децентрализации. В предыдущих обновлениях мы предполагали, что каждый агент автоматически узнает действия других агентов. Однако, MADDPG предлагает делать выводы из политики других агентов, чтобы сделать обучение еще более независимым. Фактически каждый агент будет добавлять N-1 сетей для оценки истинности политики всех других агентов. Мы используем вероятностную сеть, чтобы максимизировать логарифмическую вероятность вывода наблюдаемого действия другого агента.



Где мы видим функцию потерь для i-ого агента, оценивающего политику j-ого агента с помощью регуляризатора энтропии. В результате, наше целевое Q-значение становится немного другим, когда мы заменяем действия агента своими прогнозируемыми действиями!



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

Ансамбли политик


В вышеописанном подходе есть одна большая проблема. Во многих мультиагентных настройках, особенно в конкурентных, агенты могут создавать политики, которые могут переобучиться на поведении других агентов. Это сделает политику хрупкой, нестабильной и, как правило, неоптимальной. Чтобы компенсировать этот недостаток, MADDPG обучает коллекцию из K подполитик для каждого агента. На каждом временном шаге агент случайным образом выбирает одну из подполитик для выбора действия. А затем выполняет его.

Градиент политики немного изменяется. Мы берем среднее значение по K подполитикам, используем линейность ожидания и распространяем обновления с помощью функции Q-значения.



Вернемся на шаг назад


Вот так в общих чертах и выглядит весь алгоритм. Сейчас нужно вернуться назад и осознать, что именно мы сделали и интуитивно понять, почему это работает. По сути, мы сделали следующее:

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


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

Результаты


MADDPG был апробирован во многих средах. Полный обзор его работы можно найти в статье [1]. Здесь мы поговорим только о задаче кооперативной коммуникации.

Обзор среды


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

Сравнение


Для решения этой задачи в статье противопоставляются MADDPG и современные одноагентные методы. С использованием MADDPG видны значительные улучшения.

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

Наконец, ансамбли политик показали очень многообещающие результаты. В статье [1] исследуется влияние ансамблей в конкурентной среде и демонстрируется значительное улучшение производительности по сравнению с агентами с одной политикой.

Заключение


Вот и все. Здесь мы рассмотрели новый подход к мультиагентному обучению с подкреплением. Конечно, существует бесконечное количество методов, относящихся к MARL, однако MADDPG обеспечивает прочный фундамент для методов, которые решают самые глобальные проблемы мультиагентных систем.

Источники


[1] R. Lowe, Y. Wu, A. Tamar, J. Harb, P. Abbeel, I. Mordatch, Multi-Agent Actor-Critic for Mixed Cooperative-Competitive Environments (2018).



Список полезных статей






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


Подробнее..

Avito Analytics meetup

18.06.2020 14:14:33 | Автор: admin

Привет, Хабр! 30 июня в18:00 поМоскве мы проведём онлайн-митап дляаналитиков. Спикеры расскажут прорегиональные A/B-тесты, управление выдачей товаров винтернет-магазине, предсказание профита отновых фичей и data science вдоставке товаров.


Подкатом, как и всегда, тезисы докладов и все нужные ссылки.



Доклады


Региональные A/B-тесты. Зачем нужны и как устроены Игорь Красовский, Авито


image


Что делать, если тестовая группа вA/B-тесте точно неизвестна, а воздействие напользователя производится оффлайн, например, врегиональной ТВ-рекламе? Как сформировать контрольную группу длясмещённой тестовой? Как измерить эффект и отличить его отслучайной ошибки? Расскажу, как мы ответили наэти вопросы вАвито и скакими проблемами столкнулись.

О спикере: ВАвито чуть более 2лет, доэтого успел поработать вeCommerce и IT-консалтинге. Сейчас работаю вкоманде Core Analytics, которая отвечает затакие направления как Data Management, Strategic Analytics, Core Analytics Platform, Key Account Analytics.



Лучшие data-продукты рождаются вполях Марина Калабина, Леруа Мерлен


image


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

Из-завысокой скорости оборота товаров вмагазинах и сложности систем управления стоком возникают ошибки, которые можно обнаруживать автоматически. Опираясь нанаши знания систем и используя социальный инжиниринг, мы предложили решение, которое позволяло бы автоматически находить проблемные товары и корректировать их сток перед публикацией насайте.

О спикере: 9лет работы вЛеруа Мерлен. Сначала открывала магазины, потом вних работала, а сейчас навожу порядок втоварных запасах. Собрала команду и запустила data-продукт за6недель.



Модель роста предсказываем профит от фич для приоритизации Павел Михайлов, Ostrovok.ru


image


  • Строим модель роста фреймворк наоснове когорт и ключевых метрик, который среднесрочно моделирует выручку.
  • Переводим продуктовые и бизнесовые метрики вденьги спомощью модели.
  • Оцениваем потенциальный профит отфичей напримерах.


О спикере: Head of growth вEmerging Travel Group (Ostrovok.ru) саналитическим бэкграундом. Генерирую, разрабатываю и тестирую гипотезы роста.



Как data science Авито Доставке помогал Дима Сергеев, Авито


image


Или история отом, как перестать предлагать пользователям купить Кабину Камаза сДоставкой. НаАвито уже более 60млн. товаров. Не для каждого изних удаётся слёгкостью определить, сможет ли продавец положить его вкоробку размером 1208050 и отправить покупателю вдругой город.

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

О спикере: Последний год занимаюсь аналитикой вАвито Доставке. Доэтого на протяжении трёх лет занимался аналитикой вOZON.



Задавайте вопросы вчате трансляции насамые интересные ответим вэфире. После каждого доклада можно будет отдельно пообщаться соспикером.


Пароли и явки


Трансляция нанашем ютуб-канале стартует вовторник 30июня в18:00. Планируем закончить к20:40. Натрансляции можно сразу нажать кнопку напомнить, чтобы ничего не пропустить.


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


Увидимся в онлайне!

Подробнее..

Материалы с митапа для аналитиков модель роста, AB-тесты, управление стоком и доставкой товаров

03.07.2020 12:17:33 | Автор: admin

Хабр, привет! Впоследний день июня прошёл наш митап дляаналитиков. Нанём выступали спикеры изЛеруа Мерлен, Ostrovok.ru и, конечно же, Авито. Обсуждали региональные A/B-тесты, управление выдачей товаров вбольшом интернет-магазине, предсказание профита отновых фичей и data science вдоставке.


Под катом видеозаписи выступлений стаймкодами и ссылки напрезентации.



Региональные A/B-тесты. Зачем нужны и как устроены Игорь Красовский, Авито


На примере задач изАвито Игорь рассказал, что такое региональные А/В-тесты, когда они нужны аналитику, какие алгоритмы и математика лежат вих основе и как измерить точность этих алгоритмов.



00:00 Представление спикера и темы
00:44 Длякаких задач можно применять региональные A/B-тесты
04:21 Омодели региональных А/B-тестов: этапы проведения теста, метрика близости контрольной и тестовой групп
09:51 Алгоритм подбора тестовой группы и оценка его точности
18:03 Что можно улучшить впредложенном процессе: точки роста


Посмотреть презентацию Игоря

Модель роста предсказываем профит отфич дляприоритизации Павел Михайлов, Ostrovok.ru


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


Скачать эксельку спримером модели роста.



00:00 Представление спикера и темы
01:10 Фреймворк ICE (impact, confidence, ease)
02:26 Что такое модель роста и как с её помощью измерить влияние фичи
05:55 Как построить простую модель роста снуля
18:55 Примеры гипотез, которые можно оценить спомощью модели роста
25:22 Как можно улучшать базовую модель и зачем вообще этим заниматься


Посмотреть презентацию Павла

Лучшие data-продукты рождаются вполях Марина Калабина, Леруа Мерлен


Большая часть интернет-заказов вЛеруа Мерлен собираются вторговых залах магазинов. Из-завысокой скорости оборота товаров это нередко приводило ктому, что заказ не получалось собрать. Тогда команда Data Accelerator придумала инструмент, который позволил автоматически находить проблемные артикулы и корректировать их количество передпубликацией насайте.



00:00 Представление спикера и темы
01:37 Леруаизмы термины длялучшего погружения вконтекст доклада
02:40 Как собирают заказы изинтернет-магазина, и какие проблемы могут возникнуть усборщика
04:07 Запуск подразделения Data Accelerator, чтобы принимать data-driven решения
04:46 Продукт гарантированный сток: его цели и процесс реализации
13:34 Итоги внедрения гарантированного стока


Посмотреть презентацию Марины

Как data science Авито Доставке помогал Дима Сергеев, Авито


Ежедневно наАвито продаётся несколько миллионов самых разных товаров. Не длякаждого изних можно слёгкостью определить, сможет ли продавец положить его вкоробку размером 1208050 и отправить покупателю. Временами мы такие ошибки допускаем и предлагаем доставку там, где её быть заведомо не должно и наоборот. Дима рассказал отом, как мы сэтой проблемой справляемся и каких результатов получилось достичь.



00:00 Представление спикера и темы
01:11 История появления доставки вАвито и первые проблемы
06:32 Оценка масштабов неправильного определения возможности доставить товар
11:29 Классификация товаров как способ решить проблему: data science SWAT спешит напомощь
17:44 Первые успехи и побочные эффекты
25:47 Ближайшие планы


Посмотреть презентацию Димы

До встречи на новых митапах!

Подробнее..

Что посмотреть на (почти уже не) карантине? Подборка материалов от Технострима (часть 7)

19.06.2020 20:14:58 | Автор: admin


Продолжаем нашу подборку интересных материалов (1, 2, 3, 4, 5, 6). На этот раз предлагаем послушать курс об алгоритмах интеллектуальной обработки больших объёмов данных и два новых выпуска ток-шоу для айтишников Oh, my code с Павлом Dzirtik Щербининым.

Алгоритмы интеллектуальной обработки больших объемов данных (Data Mining), осень 2019


Цель курса познакомить с классическими и современными подходами к решению задач Data Mining с помощью алгоритмов машинного обучения. Кроме того, вы изучите методы построения, преобразования и отбора признаков, научитесь оценивать качество построенных моделей и визуализировать результаты анализа.

Программа лекций:

  • Задачи Data Mining. Постановка задачи машинного обучения. Какие бывают признаки. Типы задач машинного обучения. Разбор прикладных задач. Сравниваем алгоритмы. Переобучение и обобщающая способность. Как обнаружить и бороться с переобучением?
  • Метрики классификации и регрессии. Метод ближайшего соседа. Базовые понятия. Пример переобучения. Гипотеза компактности. Гипотеза непрерывности. Метрические алгоритмы. Примеры классификации и регрессии. Структурные параметры. Скользящий контроль. Оценка качества классификации и регрессии. Метрики алгоритмов. Нормировка признаков. Расстояния на категориальных признаках. Изучение метрик. Уменьшение размерности. Отбор признаков. Сложность алгоритмов. Приближенный поиск ближайших соседей.
  • Линейные модели регрессии. Параметризация. Представление. Оценка. Оптимизация. Нормализация данных. Регуляризация. Разреженные данные.
  • Логистическая регрессия. Линейные модели классификации. Построение разделяющей поверхности. Отступ. Функционал эмпирического риска. Аппроксимация логистической регрессии. Сигмоида. Логистическая регрессия. Math Recap: Метод Максимального Правдоподобия. Recap: Метрическая логика. Порождающая модель p(x). Метрики оценки. Как подобрать порог.
  • Задачи классификации. SVM. Многоклассовая классификация: one-vs-all. Как предсказать класс? Многоклассовая классификация: softmax. Метрики многоклассовой оценки. Геометрическая интерпретация. Построение разделяющей поверхности. Отступ. Функционал эмпирического риска. Аппроксимация SVM, Hinge Loss. SVM: Неразделимый случай. Штрафы за ошибки. SVM: переход к двойственной задаче. Условия Куна-Таккера (ККТ). Нелинейная классификация SVM ядра. Kernel Trick.
  • Решающие деревья. Определение бинарного решающего дерева. Варианты разделяющих функций. Как строить деревья. Критерии информативности для классификации. Как выглядят меры неопределенности. Критерии информативности для регрессии. Критерии останова. Обработка пропущенных значений. Обработка категориальных признаков. Специальные алгоритмы построения деревьев. Композиции деревьев. Бэггинг. Random Forest. Extra Trees (Extremely Randomized Trees).
  • Обработка естественного языка. Применение NLP в Почте Mail.ru. Предобработка: токенизация, лемматизация, стемминг. Признаковое описание текста: BOW, TF-IDF, CountVectorizer, HashingVectorizer. Дистрибутивная семантика: word2vec, fastText. Поиск околодубликатов: minhash, simhash, LSH.
  • Байесовские методы машинного обучения. Оптимальное байесовское правило. Вероятностное описание моделей. Байесовский подход. Оптимальный байесовский классификатор. Преобразовываем оптимальное байесовское правило. Как оценить p(y). Смысл формулы оптимального байесовского классификатора. Методы восстановления плотности. Наивный байесовский классификатор. Сглаживание. ММП vs Bayes. Логистическая регрессия. Регуляризация. Предсказание.
  • Задача кластеризации. Какая бывает кластеризация? Метрики качества кластеризации. Алгоритм k-means. Выбор числа кластеров. Начальная инициализация. K-medoids. Основные положения иерархических алгоритмов. Расстояния между кластерами: Алгоритм k-means ++. Формулы Ланса-Вильямса. Плотностные алгоритмы. Кластер моего кластера мой кластер.
  • ЕМ-алгоритм. Метод максимума правдоподобия. Экспоненциальный класс. Распределения из экспоненциального класса. Модели со скрытыми переменными. Тематические модели. Вариационная нижняя оценка. ЕМ-алгоритм. Дивергенция Кульбака-Лейблера. E-шаг. М-шаг. Метод Ньютона. Многомерное нормальное распределение. Смесь распределений. Правдоподобие. EM для смеси нормальных распределений. GMM как генеративная модель. Байесовский классификатор как генеративная модель.

Ссылки на видеозаписи.

Будущее голосовых помощников


Вадим Пуштаев руководитель разработки инфраструктуры голосового помощника Маруся расскажет о настоящем и будущем голосовых помощников. Наступят ли времена и как скоро когда с голосовым помощником можно будет общаться, как с полноценным собеседником? К тому же Вадим поделится опытом разработчика и преподавателя.


Егор Толстой человек и Подлодка


Егор Толстой Product manager в Kotlin и ведущий подкаста Podlodka расскажет про язык программирования как продукт. Как сегментируются программисты, как язык продвигается и растет. Как устроены процессы разработки в команде Kotlin. И зачем тут продакт-менеджеры.


Напомним, что актуальные лекции и мастер-классы о программировании от наших IT-специалистов по-прежнему публикуются на канале Технострим. Подписывайтесь, чтобы не пропустить новые лекции!
Подробнее..

Искусственный интеллект для анализа изображений и видео. Вебинар от Инфосистемы Джет

23.06.2020 12:07:45 | Автор: admin

Интересуетесь темой ML? Тогда вам сюда Зарегистрироваться
26 июня в 15:00 в прямом эфире ведущий эксперт Центра машинного обучения расскажет об опыте разработки собственных решений в компании, а также о применении IBM Visual Insights и возможностях по совмещению обоих подходов.

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

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

Вы узнаете, как работают дата-сайнтисты Инфосистемы Джет в таких проектах, что требуется для разработки внедрения распознавания изображений или видео с точки зрения науки о данных, если для задачи нет готового решения или не устраивает его качество.
Немного поговорим и об общих задачах сферы и том, как мы видим текущие потребности рынка.

На вебинаре речь пойдет также об инструментах, которые можно использовать для задач машинного обучения. В частности, мы расскажем о возможностях создания и внедрения моделей с помощью инструмента IBM Visual Insights, а также обсудим, как реализуется поиск конкретных объектов / распознавание произведенного действия на видео и классификация изображений.

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

Кому будет интересно


  • Всем, кому интересна наука о данных и ее практическое применение
  • Руководителям отдела IT, CDO
  • Руководителям отделов аналитики и математического моделирования
  • Руководителям отдела маркетинга (ритейл)

Спикер


Александра Царева, ведущий эксперт Центра машинного обучения Инфосистемы Джет
Регистрируйтесь и присылайте вопросы!
Подробнее..

В поисках обеда распознавание активности по данным фитнес-трекера

22.06.2020 10:10:48 | Автор: admin
Мне посчастливилось участвовать в проекте SOLUT, который стартовал в ЛАНИТ около года назад. Проект развивается благодаря активному участию Центра компетенции больших данных ЛАНИТ (ЦК Дата), и главное технологическое новшество проекта заключается в использовании машинного обучения для мониторинга человеческой активности. Основным источником данных для нас являютсясенсоры фитнес-трекеров, закрепленные на руках работников. В первую очередь, результаты распознавания помогают поднять производительность труда и оптимизировать производственные процессы на стройке. Также анализ поведения рабочих позволяет отслеживать самочувствие человека, соблюдение техники безопасности и напоминает строителям про обед.

Источник

Строители на объекте используют наручные датчики, фиксирующие движения рук работников. Раз в день накопленные показания датчики переносят на сервер, расположенный на строительной площадке. На этапе сбора данных помимо сенсоров используются также видеокамеры, в процессе опытной эксплуатации используются только датчики. Полученные данные идут на разметку нашим профессиональным асессорам, используя которую мы работаем над моделями распознавания деятельности человека. Когда модель прошла тестирование и показала метрики качества высокого уровня, мы внедряем ее и распознаем ежедневный поток данных. У заказчика появляется возможность смотреть регулярные отчеты о деятельности сотрудников. Несмотря на простоту схемы, нам пришлось столкнуться с множеством подводных камней и неожиданных попутных задач, про которые и пойдет рассказ.

Проверка на коллегах



Проект начался с тестового стенда, организованного в офисе ЛАНИТ рядом со столовой. Он работал три месяца. У нас был большой поток добровольцев, готовых забить гвоздь, просверлить отверстие дрелью или закрутить пару гаек. Все эти действия человек совершал с браслетом на руке за импровизированным верстаком.

Источник

Мы перепробовали несколько вариантов фитнес-трекеров, позволяющих извлечь сырые данные, и остановились на одном из известных брендов. В первую очередь в нашей работе использовались показания акселерометра и гироскопа. Дополнительно мы используем данные GPS, барометра и пульсометра. Кстати, для измерения пульса используется прибор с интригующим названием фотоплетизмограф.

Источник

Акселерометр и гироскоп позволяли нам получать сырые показания в трёх осях координат с частотой 50 Гц, соответствующей периоду 0.02 с. Таким образом, для распознавания мы располагаем шестью временными рядами, однако по техническим причинам полученные ряды оказываются с пропусками и высоким уровнем шума. Если мы построим график, отражающий зазоры между последовательными измерениями, то получим следующую картину:

На графике видно, что в данных систематически проскакивает зазор в 0.13 с.

Проблема заполнения пропусков и шумов часто возникает в задачах, связанных с временными рядами и имеет множество решений. Решить проблему пропусков и шумов, при этом максимально сохранив информацию, нам помогли модели Гауссовского процесса. Этот подход хорошо себя зарекомендовал, в том числе и в работе с временными рядами в астрофизике (arxiv.org/abs/1908.06099, arxiv.org/abs/1905.11516).

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

Пример подбора подходящего ядра гауссовского процесса. Чёрным цветом показаны исходные данные, красным средняя Гауссовского процесса, а голубым цветом обозначен доверительный интервал.

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

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

Естественно, что качество распознавания действий с помощью нейронной сети на данных с предварительной обработкой и без обработки данных будет отличаться. Так, например, в нашем случае взвешенная f1-мера вырастает с 0.62 до 0.84.

Добровольцы на нашем стенде могли видеть демонстрацию распознавания действий в реальном времени. Распознавание выглядело, как сегментация временного ряда с визуализаций показаний сенсоров фитнес-трекеров. Как видно, периоды бездействия чередуются с закручиванием гаек и, например, забиванием гвоздя.


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

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

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

Ошибки людей


В данных ожидаемо присутствует человеческий фактор, например, надевание часов вверх ногами. Бороться с этим фактором оказывается легко: модель классификации с точностью более 90% определяет, правильно ли надеты часы на рабочем. В случае неправильно надетых браслетов линейное преобразование сырых данных дает возможность использовать те же самые модели распознавания активности.

Другим человеческим фактором в данных оказывается результат разметки асессоров: они также подвержены ошибкам. В этом случае помогают различные приемы и эвристики по чистке разметки.

Иерархия действий


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

  • Нижний уровень, состоящий из элементарных действий. Пример: удар молотком, движение гаечным ключом. Характерный масштаб для интервалов нижнего уровня составляет около 5 секунд.
  • Верхний уровень, состоящий из действий работника с точки зрения цели деятельности. Пример: подготовка к работе, работа штукатура, сварка и т. п. Характерный временной масштаб для интервалов верхнего уровня составляет около 30-60 секунд.

В итоге получается картина последовательных действий работника на протяжении всего трудового дня с детализацией до элементарных движений.


Примерный интервал работы 5 минут

Поиск бездействия и обеда


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

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

Асессоры не могут разметить обеденное время, так как оно не снимается на камеру. Было сделано следующее наблюдение: в начале и конце обеденного перерыва рабочие тратят некоторое время на перемещение от рабочего места до бытовки и обратно. Можно принять эти перемещения за границы обеденного времени.

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

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


Поскольку задача сегментации решается поверх модели верхнего уровня, входные данные для Unet были выбраны в виде вектора 1024 * (кол-во классов). 1024 так как интервалы ВУ модели 30 секунд и рабочий день порядка 8-9 часов.

На выходе вектор 1024 * 1 с бинарными значениями, (0 интервал не относится к обеду, 1 относится к обеду).


Так как данных немного (порядка 40 рабочих дней), была сгенерирована синтетическая выборка. День реальных рабочих разбивался на n-частей, и каждая часть относилась к одному из пяти классов: до обеда, начало обеда, обед, конец обеда, после обеда. Генерировался новый рабочий день набором случайных интервалов: сперва несколько интервалов из первого класса, затем один из второго, несколько из третьего, один из четвертого и несколько из пятого.

Схема разбиения временных интервалов на утренние (синие), обеденные (красные) и послеобеденные (зеленые). Из фрагментов распознанных действий на интервалах комбинируются синтетические данные для обогащения тренировочной выборки.

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


Все ли действия можно классифицировать?


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

  • ошибки асессоров;
  • нетипичное поведение рабочих;
  • появление новых элементов в техническом процессе;
  • выявление подозрительных работников.

Подозрительные работники

Если вы начинаете свое знакомство с методами детекции аномалий, то скорее всего придете к следующим наиболее популярных и простым моделям, реализованным в sklearn: OneClassSVM, Isolation Forest, Local Outlier Factor. Есть и более сложные способы (подробнее на эту тему писал ранее мой коллега).


В реализации Local Outlier Factor есть возможность напрямую провести проверку на присутствие новых объектов в данных (Novelty detection). Если использовать метод Isolation Forest на тех же самых признаках, которые рассчитываются для основной модели классификации, то возможно получить рейтинг нормальности для каждого объекта: численную величину, характеризующую степень типичности для каждого объекта в выборке. Чем выше рейтинг, тем более типичным объектом в выборке является его обладатель. Распределение рейтинга нормальности выглядит следующим образом:


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

Важным моментом является следующее наблюдение: поиск аномалий удается продуктивно применять для каждого класса деятельности по отдельности, иначе редкие классы действий выделяются как аномалия.

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

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

У работы каменщика были зафиксированы следующие аномалии:

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

В ходе экспериментов с поиском аномалий нам удалось выявить один случай пьянства на рабочем месте: аномалии возникали у нетрезвого рабочего в интервалах времени, связанных с передвижением. Другим источником аномалий была работа штукатура-мужчины, в то время как в тренировочной выборке присутствовали только штукатуры-женщины.

Заключение


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

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

  • При работе с физическими процессами необходимо обращать особое внимание на чистоту данных, так как в них могут быть всевозможные пропуски, выбросы и т.д. Одним из решений проблемы сырых данных может быть применение модели Гауссовского процесса.

  • Хорошая аугментация может помочь поднять метрики качества модели. В аугментации можно идти от простого метода к более сложному:


  • Если вы освоите один из инструментов поиска аномалий, то он может пригодиться на различных этапах Data Science проекта:

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

Буду рад обсудить в статью в комментариях и с удовольствием отвечу на ваши вопросы.

Статья написана в соавторстве с olegkafanov.
Подробнее..

Перевод Распределенное обучение XGBoost и параллельное прогнозирование с Apache Spark

24.06.2020 14:16:49 | Автор: admin
Привет, хабр! Уже в конце июля Otus запускает новый курс Промышленный ML на больших данных. Традиционно, в преддверии старта нового курса, мы подготовили для вас перевод полезного материала.



Общие сведения


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



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

Слабые обучающие алгоритмы, созданные при градиентном бустинге во время обучения, обычно реализуются в виде деревьев решений. Самое неэффективное в градиентном бустинге это последовательный процесс создания деревьев, поскольку в таком случае создается всего одно дерево за раз.

Чтобы обойти это ограничение Тяньцзи Ченом и Карлосом Гестрином было предложено улучшение алгоритма градиентного бустинга, которое называется XGBoost, что расшифровывается как Extreme Gradient Boosting или экстремальный градиентный бустинг. Это своего рода градиентный бустинг на стероидах, который используется в основном для классификации, но также порой для регрессии и ранжирования.

По сравнению со стандартным градиентным бустингом, новый метод существенно увеличивает производительность за счет гиперпараметров, поддержки GPU, кроссвалидации и регуляризации алгоритмов. В целом модель получается более эффективной, быстрее обучается и менее подвержена переобучению.

В последнее время XGBoost обрел большую популярность и выиграл множество соревнований по машинному обучению в Kaggle. Считается, что он обладает большой вычислительной мощностью и точностью.



XGBoost и Apache Spark


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

В контексте этой статьи важно то, что в XGBoost есть распараллеливание процесса построения дерева, что позволяет производить между узлами распределенное обучение и прогнозирование. То есть если я, как пользователь Apache Spark MLlib, могу использовать его для расширения возможностей обучения XGBoost и работы на продакшене, то, по сути, я могу радоваться высокой производительности XGBoost и мощным механизмам работы Spark для инженерии признаков и построения ML-пайплайнов.

Встречайте XGBoost4J-Spark проект, который объединяет XGBoost и Apache Spark, добавляя XGBoost к фреймворку Apache Spark MLlib.

XGBoost4J-Spark дает возможность построить пайплайн MLlib, который предварительно обрабатывает данные перед обучением модели XGBoost, обучает ее и может использоваться для параллельного прогнозирования на продкшене. С помощью этой библиотеки каждый воркер XGBoost оборачивается в таск Spark, при этом обучающий датасет из памяти Spark отправляется воркерам XGBoost, которые невидимо существуют в исполнителях Spark.



Чтобы начать писать приложение с машинным обучением на XGBoost4J-Spark, вам нужно сначала добавить соответствующую зависимость:

<dependency>    <groupId>ml.dmlc</groupId>    <artifactId>xgboost4j-spark</artifactId>    <version>0.90</version></dependency>


Подготовка данных (пример с ирисами)


Как говорилось ранее, XGBoost4J-Spark позволяет подогнать данные под интерфейс XGBoost.

Как только мы считаем датасет Цветы Ириса в DataFrame, нам нужно будет:

  • Преобразовать столбцы из String к Double;
  • Объединить столбцы признаков в вектора, чтобы данные соответствовали интерфейсу фреймворка машинного обучения Spark.


import org.apache.spark.ml.feature.StringIndexerimport org.apache.spark.ml.feature.VectorAssemblerval stringIndexer = new StringIndexer().  setInputCol("class").  setOutputCol("classIndex").  fit(irisDF)val labelTransformed = stringIndexer.transform(irisDF).drop("class")val vectorAssembler = new VectorAssembler().  setInputCols(Array("sepal length", "sepal width", "petal length", "petal width")).  setOutputCol("features")val xgbInput = vectorAssembler.transform(labelTransformed).select("features", "classIndex")


В DataFrame выше в результате будут два столбца, features: вектор представляющий признаки ириса и classIndex: лейбл типа Double. Такой DataFrame можно спокойно скормить обучающему движку XGBoost4J-Spark.

Распределенное обучение


import ml.dmlc.xgboost4j.scala.spark.XGBoostClassifierval xgbClassifier = new XGBoostClassifier().      setFeaturesCol("features").      setLabelCol("classIndex").      setObjective("multi:softmax")      setMaxDepth(2).      setNumClass(3).      setNumRound(100).      setNumWorkers(10).


Полный список параметров XGBoost вы можете найти здесь. Обратите внимание, что в XGBoost4J-Spark вы также можете использовать camelСase, как в примере выше.

Заметки:


  1. multi:softmax означает, что мы делаем многоклассовую классификацию с помощью функции softmax. Для этого нужно задать количество классов с помощью параметра num_class.
  2. max_depth это максимальная глубина дерева, созданного на каждой итерации бустинга. Увеличение этого значения сделает модель сложной и склонной к переобучению. При обучении глубоких деревьев XGBoost потребляет много памяти.
  3. num_rounds количество раундов бустинга.
  4. Параметр num_workers определяет сколько параллельных воркеров нам нужно при обучении XGBoostClassificationModel. Позже этот параметр станет отложенными тасками в Spark, которые в перспективе будут обрабатываться менеджером кластера (в большинстве случаев YARN).

Ранняя остановка поддерживается с помощью параметров num_early_stopping_rounds и maximize_evaluation_metrics.
Теперь мы можем создать трансформер, обучив классификатор XGBoost на входном DataFrame. В результате процесса обучения мы получаем модель, которую можно использовать для получения прогнозов.

val xgbClassificationModel = xgbClassifier.fit(xgbInput)


Параллельное прогнозирование


XGBoost4j-Spark поддерживает пакетное прогнозирование и точечное прогнозирование.

Для пакетного прогнозирования модель берет DataFrame со столбцом, содержащим векторы признаков, делает прогноз для каждого вектора признаков и выводит новый DataFrame с результатами. В этом процессе XGBoost4J-Spark запускает таск Spark с воркером XGBoost для каждой части входного DataFrame для параллельного пакетного прогнозирования.

val predictionsDf = xgbClassificationModel.transform(inputDF)predictionsDf.show()+----------------+----------+-------------+-------------+----------+|       features |classIndex|rawPrediction| probability |prediction|+----------------+----------+-------------+-------------+----------+|[5.1,3.5,1.2,.. |       0.0|[3.4556984...|[0.9957963...|       0.0||[4.7,3.2,1.3,.. |       0.0|[3.4556984...|[0.9961891...|       0.0||[5.7,4.4,1.5,.. |       0.0|[3.4556984...|[0.9964334...|       0.0|+----------------+----------+-------------+-------------+----------+


Для точечного прогнозирования модель принимает один вектор.

val features = xgbInput.head().getAs[Vector]("features")val result = xgbClassificationModel.predict(features)


Точечное прогнозирование с помощью XGBoost не рекомендуется из-за больших накладных расходов, поскольку они будут сравнимы с единичным прогнозом.

На данный момент последняя версия (0.9) XGBoost4J-Spark требует Spark 2.4.x., в основном потому, что теперь в нем используются средства org.apache.spark.ml.param.shared, которые доступны не полностью в более ранних версиях Spark.

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

Узнать больше вы можете в документации XGBoost.

Источники:


XGBoost с CUDA
XGBoost в Spark c GPU и RAPIDS XGboost4J-Spark



Узнать о курсе подробнее.


Подробнее..

Перевод Тренды в Data Scienсe 2020

26.06.2020 18:17:05 | Автор: admin
image

Google Trends по запросу data science

Краткое изложение


  • По нашим оценкам, вакансии в advanced analytics насчитывают почти 1 миллион человек во всем мире, 291 тысяча из них в США.
  • За последние два года дефицит работ в области data science значительно сократился были наняты около 800 тысяч специалистов, однако на данный момент десятки вакансий так и остаются нетронутыми, причем подавляющее большинство из них в США.
  • Самый большой спрос на рабочих в области advanced analytics в области залива Сан- Франциско с самыми высокими зарплатами и самым большим количеством вакансий, за ней следуют крупные городские центры вроде Нью-Йорка, Бостона, Вашингтона и Сиэтла.
  • Средняя заработная плата по стране у data scientists остается выше $100,000 эта тенденция просматривается почти во всех штатах, удовлетворенность работой и престиж также остаются на высоком уровне.
  • Для подготовки специалистов в advanced analytics было создано больше ста образовательных программ.

image

Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:




Вступление


Вот уже последние несколько лет data science является одним из самых ярких трендов в бизнесе. В 2012 году Harvard Business Review назвали работу data scientists самой сексуальной работой 21-го века. Многочисленные отчеты (1, 2, 3, 4) писали, что мир сталкивается с огромным дефицитом data scientists. Создавались буткемпы и университетские программы, чтобы решить вопросы, связанные с огромным спросом на навыки в этой области.

К advanced analytics мы относим всех, кто сам относит себя к data scientist, специалистам по машинному обучению или ИИ-исследователю.

Спрос и предложение data scientists май 2020


Общее число рабочих в области advanced analytics



На сегодняшний день в мире насчитывается чуть менее одного миллиона рабочих в области advanced analytics (см. раздел методологии ниже), из которых 290 тысяч или же примерно 30% приходится на Соединенные Штаты Америки. На данный момент численность data scientists значительно превосходит численность инженеров по машинному обучению и исследователей ИИ как в США, так и во всем мире, однако и инженеры, и исследователи являются новыми на рынке труда и в будущем могут значительно вырасти.

image

Сравнение общего числа продвинутых аналитиков в мире в разбивке по должности, май 2020 г.

Открытые и дефицитные вакансии


На сегодняшний день на LinkedIn открыты около 86 тысяч вакансий в сфере advanced analytics, большая часть (53.4 тысячи) приходится на США. Интересно отметить, что США представляет собой непропорционально большое число открытых вакансий (62%) по сравнению с долей рабочих в advanced analytics во всем мире (30%), хоть это и можно списать на ложную методологию сбора данных (см. раздел методологии ниже).

image

Количество открытых ролей advanced analytics по сравнению с общим числом профессиональных сотрудников advanced analytics

Мы можем использовать число открытых вакансий (по сравнению с количеством имеющихся сотрудников) в качестве приблизительного показателя, чтобы понять сколько всего работников недостает. Из приведенного ниже графика видно, что открытых вакансий по всему миру на 9% больше, чем непосредственно сотрудников, в то время как в США это число достигает примерно 18.7%.


Сокращение дефицита


Сегодня в США насчитывают примерно 53 тысячи свободных рабочих мест в области advanced analytics. Однако, в августе 2018 года LinkedIn опубликовал отчет на тот момент дефицит составлял около 151 тысячи рабочих мест. За последние два года дефицит значительно сократился по всему миру была нанята примерно 831 тысяча профессионалов в области advanced analytics (см. ниже).

image

Apteo оценивает общее количество продвинутых аналитиков с течением времени

image

Дефицит продвинутых аналитиков в 2018 году по сравнению с 2020 годом

Распределение открытых вакансий и недостаток рабочих по городам США


Общее число специалистов и вакансий


Никого не удивит, что наибольшая часть работников в advanced analytics находятся в районе залива Сан-Франциско примерно 45.7 тысяч человек, как и наибольшее количество открытых вакансий около 8 тысяч. На втором месте идет Нью-Йоркская агломерация около 38.8 тысяч сотрудников и 5.9 тысяч вакансий. На третьем месте район Большого Бостона 15.9 тысяч сотрудников и 3.3 тысячи вакансий.

Самая высокая доля на душу населения


На первом месте район залива Сан-Франциско 5.9 тысячи человек на миллион. На втором месте идет Сиэтл 4.3 тысячи на миллион, завершает Бостон 3.2 тысячи на миллион.

Наибольшая нехватка рабочей силы


Наибольший процент (39.2%) открытых вакансий в городе Вашингтон.

image

Расширенная аналитика сотрудников и вакансий по городам

image

Заработная плата и удовлетворенность работой в США



Заработная плата в этой сфере варьируется по всей Америке. Основываясь на данных из различных источников, мы подсчитали, что средняя зарплата специалистов достигает примерно $114,000 в год, что соответствует примерно $14,000 в районе залива Сан-Франциско.

В 2020 году работа в data science заняла третье место по Америке по версии Glassdoor (сразу после Front End Engineer и Java Developer). С 2016 по 2019 года data scientists занимали первое место.

image

Образовательные программы и требуемые навыки


Для удовлетворения потребностей в бизнесе появилось множество новых образовательных программ. На данный момент существует как минимум 79 буткемпов, 62 программы бакалавриата и 111 магистерских программ, ориентированных на data science. Ниже мы перечислим наиболее упоминаемые программные средства и навыки для специалистов в области advanced analytics

Top Tools


  • Python
  • SQL
  • R
  • Spark
  • Cloud
  • AWS
  • Java
  • Tensorflow


Top Skills


  • Machine Learning / Regression
  • Statistics
  • Research
  • Prediction
  • Visualization
  • Recommendation
  • Optimization
  • Deep Learning
  • Natural Language Processing


image

Образовательные программы

Вывод


Очевидно, что data science продолжает быть крайне востребованной и на сегодняшний день. В то время как мир, судя по всему, быстро удовлетворяет этот спрос, по-прежнему существует острая нехватка рабочих в области advanced analytics. Интересно то, что возникают и новые должности типа инженера по машинному обучению (machine learning engineer) или ИИ-исследователя (A.I. researcher), и вполне вероятно, что для них потребуются дополнительные сотрудники, поскольку все больше компаний работают над внутренним продвижением data science.

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

Методология


Расчет занятости и дефицита


Для идентификации data scientists и открытых вакансий в data science, мы провели поиск по ключевым словам на LinkedIn по трем наиболее распространенным названиям вакансий, которые мы ассоциируем с математической, инженерной и аналитической работой, в которой, по нашему мнению, и заключается работа data scientist при помощи премиум аккаунта генерального директора и соучредителя Apteo Шанифа Дханани. Названия вакансий следующие data scientist, инженер по машинному обучению и исследователь искусственного интеллекта.

Data scientist и инженер по машинному обучению также могут быть связаны с такими ключевыми словами как data science и инженер МО, поэтому для предотвращения двойного подсчета мы использовали бинарный поиск искали ровно один термин за раз, исключая все остальные термины. Например, мы соединили результаты из следующих двух запросов для поиска data scientists:

data science -data scientist -machine learning engineer -ml engineer -ai researcher and data scientist -data science -machine learning engineer -ml engineer -ai researcher

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

Источники информации:

  • Данные поиска работ на LinkedIn, полученные 1-го мая 2020 года.
  • Google (численность населения)



Расчет заработной платы


Единого правдивого источника для расчета заработной платы просто не существует. Правительство США, рекрутинговые компании и независимые отчеты публикуют разные значения о заработной плате advanced analytics. Для наших отчетов мы собрали как можно больше независимых значений как на государственном, так и на национальном уровне и использовали среднее значение.

Источники информации:




Рост занятости


Как и в случае с расчетом заработной платы, за последние годы имеется крайне мало информации о количестве сотрудников в advanced analytics. Используя множество различных источников, мы вычислили наилучшую оценку количества работников за каждый год. В некоторых случаях мы использовали внешние данные в качестве наших, в других мы делали вывод на основе кривой с использованием имеющихся у нас данных.

Источники информации:




Образовательные программы и требуемые навыки



Следует снова проговорить, что было сложно оценить образовательные программы. В каждом университете свое название для программы по data science, поэтому нам приходилось субъективно определять, какие программы включать в список, а какие исключать из него. Мы попытались отобрать те программы, основанные на математической строгости, вычислительной работе и аналитике. Мы исследовали различные отчеты и агрегаторы для сбора данных по университетским программам, а также различные буткемпы для определения суммарных показателей для 2020-го года.

Источники информации:


Читать еще


Подробнее..

Из песочницы Побег от скуки процессы ETL

28.06.2020 18:15:43 | Автор: admin

В конце зимы и начале весны, появилась возможность поработать с новым для меня инструментом потоковой доставки данных Apache NiFi. При изучении инструмента, все время не покидало ощущение, что помимо официальной документации, нелишним были бы материалы "for dummies", с практическими примерами.


После выполнении задачи, решил попробовать облегчить вхождение в мир NiFi.


Предыстория, почти не связанная со статьей


В феврале этого года поступило предложение разработать прототип системы для обработки данных из разных источников. Источники предоставляют информацию не одновременно, в разных форматах. Нужно было ее преобразовывать в единый формат, собирать из источников информацию в одну структуру и передавать на обработку. При обработке использовались дополнительные справочники из внутренних баз данных для обогащения. После обработки данные должны были записываться в две базы данных и генерироваться суточный отчет.
Задача укладывалась в концепцию ETL. Поиск реализаций ETL привел на довольно большое количество ETL-систем, которые позволяют выстроить процессы обработки. В том числе opensource системы.


Система Apache NiFi была выбрана на удачу. Прототип был построен и сдан заказчику.


Первоначально заказчик хотел монолитное приложение, а использование NiFi рассматривал просто как инструмент прототипирование (где-то прочитал). Но после знакомства в вблизи NiFi остался в продукте.


А теперь собственно история


После сдачи работы заказчику, интерес к ETL не пропал. В апреле наступила самоизоляция с нерабочими днями и свободное время нужно было потратить с пользой.


Когда я начал разбираться с Apache NiFi выяснилось, что более-менее подробная информация есть только на сайте проекта. Русские статьи во многом просто переводы вводных частей официальной документации. Основной недостаток часто не понятно в каком формате параметры вводить. Гугл спасает, но не всегда.


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


И так, задача получать данные о распространении вируса, обрабатывать строить графики.
Источниками данных будет сайты стопкороновирус.рф и covid19.who.int. Первый сайт содержит данные по регионам России, сайт ВОЗ данные по странам мира.


Данные на сайте стопкороновирус.рф находятся прямо в html-коде страницы в виде почти готового json-массива. Нужно его только обработать. Но об этом в следующей статье.
Данные ВОЗ находятся в csv-файле, который не получилось автоматически скачивать (либо я был недостаточно настойчив). Поэтому, когда нужно было, файл сохранялся из браузера в специальную папку.


Если кратко сказать о NiFi система при выполнении процесса (pipeline), состоящего из процессоров, получает данные, модифицирует и куда-то сохраняет. Процессоры выполняют работу читают файлы, преобразовывают один формат в другой, обогащают данные из другой базы данных, загружают в хранилища и т.д. Процессоры между собой соединены очередями. У каждой очереди есть признак, по которому данные в нее загружаются из процессора. Например в одну очередь можно загрузить данные при удачной выполнении работы процессора, в другую при сбое. Это позволяет запустить данные по разным веткам процессов. Например, берем данные, ищем подстроку если нашли отправляем по ветке 1, у тех данных, в которых подстрока не найдена отправляем по ветке 2.


Каждый процессор может находиться в состоянии "Running" или "Stopped". Данные накапливаются в очереди перед остановленным процессором, после старта процессора, данные будут переданы в процессор. Очень удобно, можно изменять параметры процессора, без потери данных на работающем процессе.


Данные в системе называются FlowFile, потоковый файл. Процесс начинает работать с процессора, который умеет генерировать FlowFile. Не каждый процессор умеет генерировать потоковый файл в этом случае в начало ставится процессор "GenerateFlowFile", задача которого создать пустой потоковый файл и тем самым запустить процесс. Файл может создаваться по расписанию или событию. Файл может быть бинарным или текстовым потоком.


Файл состоит из контента и метаданных. Метаданные называются атрибутами. Например, атрибутом является имя файл, id-файла, имя схемы и т.д. Система позволяет добавлять собственные атрибуты, записывать значения. Значения атрибутов используются в работе процессоров.


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


В NiFi еще одна важная сущность контроллеры. Это объекты которые знают как сделать какую-то работу. Например, процессор хочет записать в базу данных, то контроллер будет знать, как найти и подключиться к базе данных, таблице.


Контролер, который знает как читать данные на входе в контроллер называется Reader. После обработки, на выходе процессора, данные форматируются согласно контроллеру RecordSetWriter.


Итак практическое применение вольного изложения документации чтение данных ВОЗ и сохранение в БД. Данные будем хранить в СУБД PostgreSQL.


Создаем таблицу:


CREATE TABLE public.who_outbreak (    dt timestamp NULL,    country_code varchar NULL,    country varchar NULL,    region_code varchar NULL,    died int4 NULL,    died_delta int4 NULL,    infected int4 NULL,    infected_delta int4 NULL);

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


Источником данных будет cvs-файл с сайта https://covid19.who.int/ по кнопке Download Map Data. Файл содержит информацию по заболевшим и погибшим по всем странам на каждый день примерно с конца января. Оперативная информация там задерживается на 1-2 дня. За это время в файле менялись наименования полей (были даже наименования с пробелами), менялся формат даты.


Файл сохраняется из браузера в определенный каталог, откуда NiFi забирает его на обработку.


image
Общий вид визуализации процесса в интерфейсе Apache NiFI


На рисунке большие прямоугольники процессы, прямоугольники поменьше очереди между процессами.


Обработка начинается с верхнего процесса, отходящие от процесса стрелочки показывают направление движения FlowFile (атрибутов и контента).


На визуализации процесса показывается его статус (работает или нет), данное имя процессу, его тип, количество и общий объем прошедших файлов на входе и на выходе за период времени, в данном случае за 5 мин.


Визуализация очереди показывает ее имя, и объем данных в очереди. По умолчанию имя очереди это тип связи success, failed и другие.


Тип первого процесса "GetFile". Этот процессор создает flowfile и запускает процесс. Контентом потокового файла будет содержимое файла если он будет найден. В настройках процессора на вкладке Scheduling указываем расписание запуска процесса 20 секунд.



Вкладка Scheduling запуск каждые 20 сек.


После старта процессора, каждые 20 секунд процессор будет запускаться. Если файл будет найден FlowFile будет создан и процесс запустится.


Как видно из рисунка, указываем каталог и имя файла. В имени файла можно использовать символы подстановки. Например *.csv приведет к обработке всех csv-файлов в каталоге. Указываем также, что после обработки файл можно удалить ("Keep Source File"). Также есть возможность указать максимальные и минимальные значения возраста и размера файла. Это позволяет обрабатывать, например, только не пустые файл, созданные за последний час.
На вкладке Settings указываются базовые параметры процесса, такие как имя процесса, максимальное время работы процесса, время между запусками, типы связей.


Результатом работы первого процесса "GetFile" с именем "Read WHO datafile" будет просто поток данных из файла. Поток будет передан в следующий процесс "ReplaceText".



Процессор поиска подстроки


В этом процессе обратим внимание сразу на вкладку параметров. Данный процессор ищет regex-выражение "Search Value" в входном потоке и заменяет на новое значение "Replacement Value". Обработка ведется построчно ("Evaluation Mode"). В данном случае идет замена в строке даты. Во входном файле, в какой-то момент дата формата YYYY-MM-DD стала указываться как YYYY-MM-DDThh:mm:ssZ, причем время было всегда 00:00:00, а временная зона не указывалась.
Простого способа преобразования в даты уже в записи не нашел, поэтому к проблеме подошел в лоб просто через процессор "ReplaceText" убрал символы T и Z. После этого строка стала конвертироваться в timestamp в avro-схеме без ошибок.


На выходе процессора будет поток текстовых данных, в которых уже поправили подстроку даты. Но пока это просто поток байтов без какой-то структуры.


Следующий процессор "Rename fields" читает поток уже как структурированные данные.



Переименование полей


Процессор содержит ссылку на Reader специальный объект-контроллер, который умеет читать из потока структурированные данные и в таком виде уже передает процессору на обработку. В данном случае "WHO CVS Reader просто читает поток и преобразует каждую строку cvs-файла в запись (record) которая содержит поля со значениями из строки. Имена полей берутся из заголовка cvs-файла.



Контроллер чтения записей из cvs-файла


Параметр "Schema Access Strategy" указывают, что структура записи формируется из заголовка cvs-файла. Если заголовков нет, то можно изменить стратегию доступа к схеме и в реестре схем данных создать схему, указать ее имя в параметре "Schema Name" или еще проще указать саму схему в параметре "Schema Text".


Но так как у нас есть заголовки в файле читаем по ним.


Итак, в процессоре данные уже структурированные их можно представить как таблицу базы данных поля и строки. И к этой таблице мы выполняем SQL запрос :


select    Date_reported dt,    Country_code country_code,    Country country,    WHO_region region_code,    New_deaths died_delta,    Cumulative_deaths died,    New_cases infected_delta,    Cumulative_cases infectedfrom FLOWFILE

Поля в запросе такие же как заголовки cvs-файла. Имя таблицы служебное FLOWFILE обозначает чтение структурированных данных их контента файла. Язык запроса SQL довольно гибкий, есть функции преобразований, агрегаций и т.д. В данном случае запрос выводит все данные, только имена полей результата будут другие они соответствуют полям таблицы who_outbreak в целевой БД.


Поток записей с новыми именами полей передается в контроллер RecordSetWriter, ссылка на который также указана в параметра контроллера "WHO AvroRecordSetWriter".



Контроллер RecordSetWriter


Контролер RecordSetWriter уже использует предопределенную схему данных. Схема находится в отдельном объекте регистре схем ("Schema Registry"). В контроллере есть только ссылка на реестр схем и имя схемы.



Регистр схем


Работать с регистром схем довольно просто. Добавляем новый параметр. Его имя будет именем схемы. Значение параметр определение схемы.


В регистре схем создана схема who_outbreak, определение схемы:


{"type" : "record","name" : "who_outbreak","fields": [  {"name": "dt", "type": { "type" : "long", "logicalType": "timestamp-millis"}},  {"name": "country_code", "type" : ["null", "string"], "default": "-"},  {"name": "country", "type" : ["null", "string"], "default": ""},  {"name": "region_code", "type" : ["null", "string"], "default": ""},  {"name" : "died", "type" : "int", "default": 0},  {"name" : "died_delta", "type" : "int", "default": 0},  {"name" : "infected", "type" : "int", "default": 0},  {"name" : "infected_delta", "type" : "int", "default": 0} ]}

Имена и типы атрибутов схемы соответствуют именам и типам полей записи, сформированной sql-запросом.


После выполнения контроллером sql-запроса и передачи данных на выход контроллера в формате схемы данных, структурированный поток передается в контроллер "Delete all records". Это контроллер типа "PutSQL", который может передавать на выполнение sql-команды.


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



delete from who_outbreak;


В параметрах контроллера указываем SQL Statement delete from who_outbreak; и ссылку на пул соединений "JDBC Connection Pool". Параметры JDBC стандартные. Пул содержит настройки подключения к конкретной БД, поэтому его можно использовать во всех контроллерах, которые будут работать с этой БД.


Данные или атрибуты FlowFile не обрабатываются в процессоре, поэтому вход и выход процессора идентичен.


Последний процессор "PutDatabaseRecord".



Запись в БД


В этом процессоре указываем Reader, в котором используется определенная схема who_outbreak. Так как мы удалили все записи в предыдущем процессоре, используем простой INSERT для добавления записей в таблицу. Указываем пул соединений DBCPConnectionPool, далее указываем БД и имя таблицы. Имена полей в схеме данных и БД совпадают, то больше никакой дополнительной настройки проводить не нужно.


Все процессоры, контроллеры и регистры схем нужно перевести в состояние Running (Start).
Процесс доставки данных готов. Если положить файл WHO-COVID-19-global-data.csv в каталог D:\input, то в течении 20 секунд он будет удален, а данные пройдя через процесс доставки данных будут сохранены в БД.


Сейчас вынашиваю планы на вторую часть статьи, в которой планирую описать второй процесс ETL чтение данных с сайта, обогащение, загрузка в БД, в файлы, расщепление потока на несколько потоков и сохранение в файлы. Если тема интересна пишите в комментарии, это мне прибавит стимула быстрее написать.


На рисунке изображение в интерфейсе Apache NiFi описанного процесса (справа) и, для затравки, процесса для второй статьи (слева).


Подробнее..
Категории: Big data , Bigdata , Apache nifi , Etl

Категории

Последние комментарии

© 2006-2020, personeltest.ru