- PVSM.RU - https://www.pvsm.ru -

Сколько нужно нейронов, чтобы распознать сводку моста?

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

После второго "опоздания" на мосты, я задумался об источниках информации о досрочной сводке мостов. Одним из пришедших в голову вариантов была информация с публичных веб-камер. Вооружившись этими данными и остаточными знаниями со специализации по ML от МФТИ [1] и Яндекса [2], я решил попробовать решить задачу "в лоб".

0, Дворцовый

 

Во-первых — камеры

С веб-камерами в Петербурге сейчас не густо, живых направленных на мосты камер у меня получилось найти только две: от vpiter.com [3] и РГГМУ [4]. Несколько лет назад были камеры от Skylink, но сейчас они не доступны. С другой стороны, даже информация по одному только Дворцовому мосту с vpiter.com может быть полезна. И она оказалась полезнее, чем я ожидал — товарищ-парамедик рассказал, что его экипаж "скорой" в том числе благодаря оперативной информации о мостах спас "плюс" двух петербуржцев и одного шведа за неделю. :-)

Ещё камеры имеют свойство отваливаться, отдавать видеопоток поток в мерзком формате flv, но всё это очень несложно обходится готовыми кубиками. Буквально в две строчки shell-скрипта из видеопотока получается набор кадров, поступающих на классификацию раз в 5 секунд:

while true; do
    curl --connect-timeout $t --speed-limit $x --speed-time $y http://url/to | 
    ffmpeg -loglevel warning -r 10 -i /dev/stdin -vsync 1 -r 0.2 -f image2 $(date +%s).%06d.jpeg
done

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

x = io.imread(fname)

1, frame [5]

Во-вторых — обработка изображений

Так или иначе, раскидав руками и методом деления пополам фотографии по папкам UP, MOVING, DOWN я получил размеченную выборку. Эндрю Ын в своём курсе [6] предлагал хорошую эвристику "если вы на картинке можете отличить объект A от объекта Б, то и у нейронной сети есть шанс". Назовём это эмпирическое правило наивным тестом Ына.

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

lambda x: x[40:360, 110:630]

2, bridge [7]

Я краем уха слышал, что настоящие специалисты берут OpenCV, извлекают фичи и получают пристойное качество. Но, начав читать документацию к OpenCV, мне стало печально — довольно быстро я понял, что в установленный лимит "сделать прототип за пару вечеров" я с OpenCV не уложусь. Но в используемой для чтения jpeg-ов библиотеке skimage по слову feature тоже кое-что [8] находилось. Чем отличается разведённый мост от сведённого? Контуром на фоне неба. Ну так и возьмём skimage.feature.canny, записав себе в блокнот задачу почитать после прототипа о том, как устроен оператор Кэнни [9].

lambdax x: feature.canny(color.rgb2gray(x[40:360, 110:630]))

3, canny [10]

Едущий над заштрихованной водой троллейбус выглядит довольно красиво. Быть может, скучая и по этой красоте, mkot [11] сожалеет, что переехал из Петербурга [12] :-) Но данная картинка плохо проходит наивный тест Ына — она визуально выглядит шумной. Придётся прочитать документацию [13] дальше первого аргумента функции. Кажется логичным, что если границ слишком много, то можно размазать картинку предлагаемым фильтром Гаусса. Значение по-умолчанию — 1, попробуем его увеличить.

lambdax x: feature.canny(color.rgb2gray(x[40:360, 110:630]), sigma=2)

4, sigma [14]

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

lambda x: transform.downscale_local_mean(feature.canny(color.rgb2gray(x[40:360, 110:630]), sigma=2), (20, 20))

5, features [15]

Это всё ещё похоже на мосты, но и изображение теперь всего 16x26, 416 пикселей. Имея несколько тысяч кадров на таком множестве недо-фич уже не очень страшно учиться и заниматься кросс-валидацией. Теперь неплохо бы выбрать топологию нейронной сети. Когда-то Сергей Михайлович Добровольский, читавший нам лекции по мат. анализу, шутил, что для предсказания исхода выборов президента США достаточно одного нейрона. Кажется, мост — не намного более сложная конструкция. Я попробовал обучить модель логистической регрессии [16]. Как и ожидалось, мост устроен не намного сложнее выборов, и модель даёт вполне пристойное качество с двумя-тремя девятками на всяких разных метриках [17]. Хотя такой результат и выглядит подозрительно (наверняка в данных всё плохо с мультиколлинеарностью). Приятным побочным эффектом является то, что модель предсказывает вероятность класса, а не сам класс. Это позволяет нарисовать забавный график, как процесс разводки Дворцового моста выглядит для "нейрона" робота в реальном времени.

6, разводка [18]

Остаётся прикрутить к этой конструкцию push-уведомления и какой-нибудь интерфейс, позволяющий посмотреть на мост глазами, если классификатор дал сбой. Первое оказалось сделать проще всего с помощью Telegram-бота, который отправляет уведомления в канал @SpbBridge [19]. Второе — из костыликов, bootstrap и jquery сделать веб-мордочку с прямым эфиром [20].

Зачем я это всё написал?

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

И ещё, пока я писал этот текст, дождь, кажется, смысл в Неву камеру, которая смотрела на Дворцовый мост вместе с сервером vpiter.tv, о чём робот оперативно и сообщил.
7, nomorecam [21]
Я буду рад, если вы во имя отказоустойчивости захотите поделиться своей веб-камерой, которая смотрит на какой-нибудь разводной мост. Вдруг, например, вы работаете в СПб ГКУ «ГМЦ» [22] :-)

Автор: darkk

Источник [23]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/python/164934

Ссылки в тексте:

[1] специализации по ML от МФТИ: https://habrahabr.ru/company/mipt/blog/298544/

[2] и Яндекса: https://habrahabr.ru/company/yandex/blog/277427/

[3] vpiter.com: http://vpiter.com/

[4] РГГМУ: http://www.rshu.ru/

[5] Image: https://habrastorage.org/files/dd7/eb9/fe2/dd7eb9fe235a4cadabc3021df55111c6.jpeg

[6] в своём курсе: https://www.coursera.org/learn/machine-learning

[7] Image: https://habrastorage.org/files/6a8/67e/1cd/6a867e1cd0e64024bdc37e0d02813eef.jpeg

[8] кое-что: http://scikit-image.org/docs/dev/api/skimage.feature.html

[9] оператор Кэнни: https://ru.wikipedia.org/wiki/%D0%9E%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80_%D0%9A%D1%8D%D0%BD%D0%BD%D0%B8

[10] Image: https://habrastorage.org/files/166/27f/33f/16627f33f79b41e29229c6c3421a64ae.png

[11] mkot: https://habrahabr.ru/users/mkot/

[12] что переехал из Петербурга: https://habrahabr.ru/post/252837/#comment_8356703

[13] документацию: http://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.canny

[14] Image: https://habrastorage.org/files/ae0/3ed/143/ae03ed14321341919f234c8c1770c574.png

[15] Image: https://habrastorage.org/files/4b3/637/ce6/4b3637ce685748f7a2ad41af70502a23.png

[16] логистической регрессии: http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html

[17] всяких разных метриках: http://scikit-learn.org/stable/modules/classes.html#module-sklearn.metrics

[18] Image: https://habrastorage.org/files/06e/1c8/9fb/06e1c89fb85b4931bf6d537f39110f73.png

[19] канал @SpbBridge: https://telegram.me/SpbBridge

[20] веб-мордочку с прямым эфиром: http://darkk.net.ru/bridge/now.html

[21] Image: https://habrastorage.org/files/f30/db9/4ea/f30db94ea1814bd7a36c3546bf15764c.jpeg

[22] СПб ГКУ «ГМЦ»: http://spb112.ru/catalogue/4/

[23] Источник: https://habrahabr.ru/post/306798/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best