Система відстеження ступеня заледенелости вулиць: машинне навчання + Microsoft Azure + Android

Привіт всім! Кожну зиму в російських (і не тільки) містах з'являється шкідливий ожеледь. Безліч людей підсковзується і травмує різні частини тіла. Скажете, ця проблема повинна вирішуватися комунальниками — так, так і є, але вони дуже часто не доглядывают за станом тротуарів і дворових стежок, а може бути і просто не знають, куди потрібно дивитися. Щоб хоч якось покращити ситуацію, рішення проблеми все більше повинні включатися сучасні технології. Отже, сьогодні поговоримо про створення системи оцінки ступеня заледенелости вулиць, заснованої на статистиці падінь людей. Під катом машинне навчання, хмари і мобільні додатки.
3 приклад використання системи

Де ще може бути корисно?
Дозвольте мені назвати ще два застосування майбутньої системи (при необхідних змін). Крім падінь, розглянутих глобально в міському середовищі, нам хочеться відстежувати стан наших близьких (особливо старих). Тут інформація про падіння (інфаркт, втрата свідомості тощо) та негайне повідомлення родичів дозволить зреагувати як можна швидше і викликати швидку допомогу бабусі/дідуся, не знаходячись безпосередньо поруч з ними.
Ще одним корисним застосуванням виявиться отримання тренером інформації про падіння своїх спортсменів на довгих трасах: лижників, бігунів і пр. Всі три галюцинації корисних думку автора випадку показано на картинці вище для більш повного усвідомлення проблем. Автор представляє розбір реалізації системи для міського випадку і називає її Sleet Monitor. Система буде реалізована у зв'язці мобільного Android програми та хмарної складової. Відразу скажу, що весь код знаходиться в репозиторії на GitHub
У чому складність?
В першу чергу потрібно вирішити питання з визначенням факту падіння. Начинка системи буде представлена класифікатором падінь. Складність його побудови полягає в основному в даних, які ми отримуємо зі смартфонів. Дані — це показання акселерометра по трьох осях, зібрані безперервно. На малюнку нижче показані два приклади півтора-секундних фреймів: лівий відповідає падінню, правий — не падіння.
Приклади даних

Через різних характеристик смартфонів дані можуть бути розрідженими, причому дозвіл за часом непостійно для одного і того ж пристрою (операційна система з певних причин не повертає дані з однієї і тієї ж частотою на багатьох пристроях). Також напрям осей акселерометра може варіюватися від пристрою до пристрою. Плюсом до перерахованого буде проблема «заморожування» додатка (в закритому режимі ОС може дуже рідко видавати показання акселерометра, а може несподівано принести цілу пачку даних).
На даний момент вирішена перша і частково остання проблема шляхом використання інтерполяції даних. Зважаючи перерахованих труднощів і того факту, що розробити класифікатор падінь, грунтуючись на деяких евристиках важко, погляд впав на підходи з машинним навчанням.
Збір даних
Скріншот додатка для збору даних, Щоб машину чомусь навчити, потрібно показати їй це щось, і ще краще вказати, що добре, а що погано. Для збору даних було написано окреме Android додаток, що збирає показання акселерометра з максимально можливою частотою і записує їх у файл. Розмір кадру не перевищує 1.5 сек (автор припустив, що в середньому людина падає протягом цього проміжку часу).

Дані являють собою рядки наступного формату:
time: x_value y_value _z_value ... time: x_value y_value _z_value is_fall
,
time
— час в мілісекундах з моменту початку запису стану,
x_value
,
y_value
,
z_value
— показання акселерометра по відповідним осям, нормовані максимально можливого для конкретного типу акселерометра значенням.
is_fall
значення
true
, якщо запис відповідає падінню,
false
— ні. Кількість кортежів
(time, x_value, y_value, z_value)
у рядку залежить від частоти надання даних операційною системою. Тут варто зауважити, що вся вибірка була зібрана на смартфоні LG Nexus 5, який видає стабільно дані разів 5 мсек при заблокованому екрані. Таким чином, за 1.5 секунди ми маємо 300 кортежів даних з позначкою часу.
Всі дані доводилося збирати шляхом самостійних падінь за допомогою свого друга Кручиніна Дмитра. Таким чином, зібраний датасет заснований на вибірці падінь двох людей. В інтерфейсі програми можна вказати, що в даний момент записується — падіння чи не падіння.
Додаткові функції програмиПередбачена також система позбавлення від некоректних даних — кнопки
1
,
2
,
3
призначені для додавання в кінець файлу теги
Label1
,
Label2
,
Label3
, що сигналізують про те, що останні вимірювання в кол-ве 1, 2 або 3 відповідно некоректні. Надалі дослідник видалить ці дані з файлу. Також існує окрема мітка
GOOD
, яку людина може поставити, щоб сказати, що всі попередні вимірювання гарантовано коректні.
на екрані є поля
Falls
та
Non-Falls
, відповідні кол-ву записаних вимірювань в даній сесії програми по кожному типу стану. При новому запуску програми система запише рядок у файл
DataWriter was initialized
, яка дозволить досліднику побачити нову сесію програми і у разі помилок у даних звузити область пошуку для їх видалення.

Тут ще варто відзначити інтерфейс зі звуковими сигналами у додатку. Він був розроблений спеціально для збору позитивних (падіння) прикладів. Коли людина здійснює падіння, йому не можна діставати смартфон з кишені щоб зупинити або почати запис, бо в такому випадку дані будуть зіпсовані (не відповідають реальності). Картинка знизу пояснює принцип роботи інтерфейсу зі звуковими сигналами.
Інтерфейс голосових сигналів

Детальне пояснення інтерфейсу з сигналамиПісля натискання на кнопку
PLAY
система чекає, коли колевания смартфона стануть незначними — людина тримає телефон в руці, або кладе його до кишені перед початком запису. Як тільки коливання стали незначними, система розуміє, що чоловік готовий до запису, і вона теж готова — видає короткий звук Beep. Далі йде стан Idle (безделие), яке триває до тих пір, поки людина не почне рухатися, або не почне коливатися смартфон в руці. Тоді система починає записувати дані (на малюнку ця стадія називається Failing). Запис відбувається на протязі 1.5 секунд і завершується довгим сигналом Beep (система записала дані в файл). Поки людина лежить, він не рухається (знову стадія Idle). Як тільки людина почала рухатися, а разом з ним і смартфон у кишені, система розуміє, що людина піднімається. З цього моменту цикл повторюється. Для запису не падіння все працює точно так само.

Архітектура
Оскільки система заснована на статистичних даних безлічі користувачів, їй необхідна підтримка з повітря центральна система, що обробляє дані. Вона представляє із себе кілька машин і сервісів, розгорнутих в хмарі Microsoft Azure, які діляться на три типи відповідно до їх завдань:

  1. Отримання даних зі смартфона
  2. Детектування падінь
  3. REST API отримання карти заледенелости вулиць

Всі машини знаходяться в одній мережі і «спілкуються» через базу даних Apache Cassandra. Ця NoSQL СУБД була обрана завдяки її головній властивості — вона ефективно працює з великим потоком даних, що надходять у реальному часі з безлічі пристроїв. Відразу тут варто згадати дизайн бази даних. В базі є дві таблиці з наступними схемами:

  • <b>sensor_data(user_id: varchar, x: float, y: float, z: float, lat: double, lon: double, timestamp: bigint, fall_status: int)</b>
    . Тут зберігаються всі кортежі даних, що надходять з Android пристроїв. Чому зберігаємо всі? Вважається, що ці дані можуть знадобитися в майбутньому, наприклад, для навчання будь-якого алгоритму без вчителя. Фізична зберігання рядків у таблиці розташоване за спаданням значення
    <b>timestamp</b>
    , щоб можна було ефективно працювати з більш свіжими кортежами даних.

  • <b>update_info(user_id: varchar, is_updated: boolean)</b>
    . Ця таблиця потрібна тільки для того, щоб додатком-детектору визначити, від яких користувачів прийшли нові дані. Додана, щоб не шукати у великій таблиці
    <b>sensor_data</b>
    свіжі записи по кожному користувачеві, а відразу знати, у кого є оновлення.

На картинці зображена повна архітектура системи, а за нею слід більш детальний опис кожної складової.
Архітектура

Трохи довідки за поточним станом хмарної інфраструктуриНа даний момент в Microsoft Azure розгорнута одна Linux-машина з пакетом DataStax Enterprise, що включає в себе встановлену Apache Cassandra. Характеристики машини: 4-х ядерний 2.4 GHz Intel Xeon® E5-2673 v3 (Haswell), 14 Гб RAM, 200 Гб SSD. Автор орендує машину на кошти, одержувані щомісяця за програмою Microsoft Bizspark.

Отримання даних зі смартфона
Для надсилання та отримання даних зі смартфона був використаний Azure Event Hub, спеціально призначений для великого потоку коротких повідомлень. На серверній стороні є машина із запущеним додатком Java, яке читає дані з черги Event Hub'а і записує їх в базу даних Cassandra.
Дані представлені у форматі JSON. Кожне повідомлення від клієнта, містить показання акселерометра, тимчасові мітки і GPS-координати для всіх вимірювань, отриманих в проміжку 1 хвилини.
ПриміткаЯкщо збираєтеся реалізовувати Azure Event Hub відправника на Андроїд, то автор може порадити відразу дивитися на HTTPS API, оскільки на Андроїд немає (чи автор не зміг знайти) підходящою реалізації AMQP протоколу, який використовується всіма Azure Event Hub SDK.

Детектор падінь
Для обробки потоку даних від користувача в хмарі запущена машина з Python додатком. Чому саме Python? Просто тому що дослідження з машинним навчанням проводилися на Python з використанням бібліотеки scikit-learn, а переписувати додаток з використанням інших технологій тільки для того, щоб запустити його на сервері на даному етапі було зайвим.
Принцип роботи детектора падінь

Детектор падінь працює за принципом ковзного вікна (англ. — sliding window). Вікно ковзає по интерполированным даними (так, кожен шматок свіжих даних, узятих з бази, що інтерполюється по причині проблеми, описаної спочатку) і запускає класифікатор для визначення факту падіння. Рішення класифікатора 1 (падіння) або -1 (не падіння) записується назад у базу даних для першого витягнутого кортежу в дослідженому шматку даних. Природно, вся ця процедура виконується незалежно для кожного користувача, який визначається за
user_id
в таблиці.
Класифікатор
Окремо варто поговорити про класифікатор. Він заснований на класичному (без використання нейронних мереж) алгоритм машинного навчання. Якість класифікації оцінюється за метрикою F1-score. У полі дослідження потрапило наступне:

  1. Алгоритм машинного навчання та його параметри. Кандидатами на звання кращого класифікатора падінь були виставлені Random Forest Classifier, Support Vector Classification/Regression і Linear Regression. Після проведення декількох запусків було виявлено, що Random Forest Classifier з кол-вом дерев 10 і іншими параметрами за замовчуванням (які установил scikit learn) показує найкращі результати.

  2. Датасет. Тут варіювалися і тренувальна тестова вибірки по співвідношенню <кількість позитивів>:<кількість негативів> і змінювався набір самих негативів. Фінальна тренувальна вибірка негативів включає приклади простих рухів смартфона в повітрі, ходінь по кімнаті, підкидань, а також приклади, на яких класифікатор давав помилкові спрацьовування в бойових умовах (тобто коли весь цикл системи був реалізований, а автор навмисно робив ходіння по кімнаті і стрибки без падінь). Разом датасет становив 84 позитивних прикладу і 400 негативних. З них 80% випадкових прикладів відводилося на навчання, решта 20% — на тестування.

  3. Набір осей акселерометра. Дослідження показали, що набір осей
    {x, z}
    дає найкращі результати в класифікації, що також позитивно впливає на скорочення інтернет-трафіку користувача. Але тут варто обмовитися. Справа в тому, що дані падінь збиралися автором при постійному положенні смартфона в кишені верхній його частиною вниз. Саме цей напрямок відповідає напрямку
    y
    на LG Nexus 5. Алгоритм переобучался на даних по осі
    y
    , і, незважаючи на те, що він показував непогані результати на тестовій вибірці, в бойових умовах він давав дуже багато помилкових спрацьовувань при простому повороті смартфона «вниз головою». Цю проблему можна вирішити шляхом створення більш репрезентативної вибірки. Але на даний момент результат з урахуванням тільки двох осей дуже навіть непоганий.

  4. Параметри інтерполяції. Як було сказано раніше, через велику зоопарку пристроїв на Android доводиться працювати з розрідженими даними. Тут допомагає лінійна інтерполяція. І раз вже ми беремося за інтерполяцію, непогано було б спробувати зменшити дозвіл даних для скорочення інтернет-трафіку з боку користувача та зменшення серверного навантаження на детектування падінь. Нагадаю, базовий датасет містить півтора-секундні кадри даних, розбиті на 300 кортежів
    (x, y, z, timestamp)
    (один кортеж у 5 мсек). При зменшенні здатності до одного кортежу в 50 мсек спостерігається все ще прийнятну якість класифікації, але обсяг даних скорочується в 10 разів!

Підсумкове максимальне з кількох тренувальних епох значення F1-score при всіх зазначених найкращих параметрах і з урахуванням навмисного розрідження даних в 10 разів виявляється на рівні ~90%. Без розрідження — ~95%.
Зауваження по інтернет-трафікуОбсяг даних, надісланих з Android програми у двійковому поданні, невеликий. У самому справі,
2(кількість осей) * 4 байти(розмір значення по осі) + 4 байти(розмір timestamp) + 8 байт(розмір координат) = 20 байт
— розмір одного кортежу даних.
1000 мсек / 50 мсек = 20
— максимальна кількість кортежів за секунду.
20 байт * 20 = 400 байт
в секунду. Далі
400 байт * 60 * 60 * 24 * 30 = 1 036 800 000 байт
або
~980 Мб
в місяць. Це за умови, що користувач ходить 24 години в добу, і додаток безперервно відправляє дані. Але насправді в середньому користувач проводить не більше третини доби в русі. З урахуванням цього грубого допущення отримуємо навантаження на трафік в районі 300 Мб, що можна вважати досить адекватним.

REST API і відображення точок на карту
Для отримання оновлень всіма користувачами програми Sleet Monitor про ступінь заледенелости вулиць був написаний простенький REST API-Java з використанням бібліотеки spark-java. Додаток звертається все до тієї ж бази даних Cassandra і дістає свіжі координати тих точок, для яких значення
fall_status = 1
(в цьому місці було виявлено падіння). По-хорошому, тут можна провести деяку очищення даних кшталт перевірки на збіг координат декількох точок. На даний момент без додаткової обробки координати додаються в R-Tree для швидкого пошуку з прямокутної області, яка приходить в запиті від клієнта.
Щоб відобразити точки на карті моїм товаришем Бондарем Богданом був реалізований принцип heat map, запозичений з приклад Google для Android. Суть принципу полягає в тому, що при зміні масштабу карти в бік збільшення огляду відмальовані точки складаються так, що там, де чим більше щільність точок в околі, тим більше виглядає пляма на карті.
На малюнку нижче показаний приклад намальованих точок падінь. Це справжні падіння, «нападанные» автором на снігу спеціально для демонстрації роботи системи. У червоних областях автор навмисно падав кілька разів, щоб показати, що класифікатор падінь працює непогано, і при запису не було жодного помилкового спрацьовування, при тому що запис проводився безперервно з однаковою швидкістю обходу вулиць.
Скріншоти програми з реальними падіннями

Висновок
Отже, невелике поліпшення в міського життя людей зробити можливо. Система відстеження падінь людей реалізована. Природно, тут можна і потрібно зробити багато оптимізацій, щоб знизити як серверну навантаження, так і навантаження на інтернет-трафік користувача — натренувати модель відразу на більш розріджених даних, тим самим скоротивши обчислювальні витрати на детектор падінь; збільшити крок біжить вікна в детекторі; для скорочення трафіку передавати дані з Android пристрою в бінарному вигляді, а не як зараз в JSON; та ін
Поліпшення завжди можна робити, багато з них тривіальні, і при цьому можуть принести значне зниження витрат як на серверну частину, так і по трафіку користувача. Мета розробки полягала в тому, щоб отримати досвід запуску повного конвеєра, що включає мобільний додаток і высоконагруженную серверну частину, обробну величезний потік даних в реальному часі. Але щоб запустити цю систему в реальних умовах, потрібно значно розширити парк машин в хмарі і поширити мобільний додаток з досягненням високої концентрації користувачів хоча б в одному місті. А з монетизацією поки нічого не ясно.
Передбачаючи цю проблему на етапі зародження ідеї, відразу було вирішено робити проект відкритим. Нагадаю, весь код знаходиться в репозиторії на GitHub. Мета написання дебютною для автора статті на Хабрахабр полягала не тільки в тому, щоб розповісти про здобутий досвід побудови подібних систем, але і в тому, щоб отримати якусь зворотний зв'язок від спільноти. Тому дуже вітаються коментарі, так само як і пропозиції щодо подальшого розвитку системи. Дякую за увагу.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.