Всё началось с того, что жена захотела повесить кормушку для птиц. Идея мне понравилась, но сразу захотелось оптимизировать. Световой день зимой короткий — сидеть днём и смотреть на кормушку времени нет. Значит нужно больше Computer Vision!



Идея была простой: прилетает птичка — вжуууух — она оказывается на телефоне. Осталось придумать как это сделать и реализовать.
В статье:
  • Запуск Caffe на Raspberry Pi B+ (давно хотел это сделать)
  • Построение системы сбора данных
  • Выбор нейронной сети, оптимизация архитектуры, обучение
  • Оборачивание, выбор и приделывание интерфейса

Все исходники открыты + описан полный порядок развёртывания получившейся конструкции.

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

Комплектуха


  • Ядро системы: Raspberry Pi первой модели, B+. Лежала у меня в ящике полтора года практически без дела. Сейчас, конечно, логичнее будет брать RPi 3. Там и памяти больше и шустрее сильно. Цена RPi 3 — где-то 3-3.5 т.р.
  • SD-карточка для RPi. Вроде на 32 гига. Покупал давно, цену не помню. Где-то в окрестности 500-1000р
  • Блок питания (microUSB). Взял из своих запасов. Опять же, где-то 500-1000р.
  • Камера:
    • Изначально я планировал использовать самую базовую камеру от Rpi (Raspberry Pi Camera 1.3rev), которая у меня лежала в том же ящике. Но она не завелась. Судя по тестам умер либо разъём на RPi либо шлейф. Ещё вариант — дрова слетели. В ближайшее время пойму окончательно что там не так. Цена такой камеры, в зависимости от объектива и характеристик 1.5т.р — 2.5 т.р.
    • Так что в качестве стартового решения решил поставить вебку с компа. Обычную Creative, благо на Rpi B+ много USB портов. FaceCam100x. Покупал не прямо сейчас, стоит она где-то в окрестности 1т.р. Вариант плохой, так как качество убогое. Но набрать базу и затестить — сойдёт.

  • WiFi-донгл. Взял самый обычный — TP-Link TL-WN727N за 400р.
  • Собственно кормушка. Самому было делать лень, купил готовую. Обошлась где-то в 2т.р. с доставкой


Инфраструктура


Кусок моей домашней сети, который ответственен за проект имеет следующую конфигурацию:



Rpi+камера висят около окна. Я провёл много экспериментов для того чтобы найти удобное крепление и хороший вид:



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



Картинки получаются такими:


Качество с вебки не ахти какое. Но, в принципе, понятно происходящее.

Вернёмся к архитектуре. В Rpi воткнут WiFi модуль, который подключен в роутеру. Фотографии сохраняются на сетевой диск (WD MyBook live). Для набора базы это необходимое условие (флешки на RPi на много не хватит). При использовании, конечно, можно отключать. Но мне удобно.

Сам Rpi висит без монитора. Его управление, программирование и настройка сейчас делается с основного компа по SSH. В начале что-то настраивал воткнув в монитор, но это не обязательно.

Сбор базы


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

Сбор базы — это масса ручного, пусть даже неквалифицированного труда. Специально для разметки больших баз есть сервисы Яндекс.Толока и Amazon Mechanical Turk. От их использования я воздержусь: размечу всё вручную сам, тут недолго. Хотя, может, имело бы смысл и туда загнать, потренироваться в использовании.

Естественно, хочется автоматизировать такой процесс. Для этого рассмотрим, что мы хотим.
Что есть база в нашей ситуации:
  • Система работает с видео — значит это должны быть кадры из видео. Мощности для анализа видео последовательностей на стареньком RPi точно не хватит
  • Система должна распознавать птиц в видео, значит в базе должны быть примеры кадров на которых птицы присутствуют, а так же примеры кадров где не присутствуют
  • Система должна распознавать качество изображений. Значит в базе должны быть отметки, определяющие качество кадра
  • Система должна иметь набор кадров на каждый тип птичек который она распознаёт

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

Проще всего сделать тривиальный «детектор движения» и набрать весь его выход. Детектор движения сделаем самым простым способом:

$\sum_{W,H}^{}I_{x,y}^{frame_1}-I_{x,y}^{frame_2} > D$



Код на несколько строчек:

import cv2
import time
video_capture = cv2.VideoCapture(0)
video_capture.set(3,1280)
video_capture.set(4,720)
video_capture.set(10, 0.6)
ret, frame_old = video_capture.read()
i=0
j=0
while True:
    time.sleep(0.5)
    ret, frame = video_capture.read()
    diffimg = cv2.absdiff(frame, frame_old) #Просто вычитаем старый и новый кадр
    d_s = cv2.sumElems(diffimg)
    d = (d_s[0]+d_s[1]+d_s[2])/(1280*720)
    frame_old=frame
    print d
    if i>30: #Первые 5-10 кадров камера выходит на режим, их надо пропустить
        if (d>15): #Порог срабатывания
            cv2.imwrite("base/"+str(j)+".jpg", frame)
            j=j+1
    else:
        i=i+1


Результат работы детектора


Детектор срабатывал на любую шевелёнку. На её начало и на её окончание. В результате работы детектора в течении недели была набрана база примерно в 2000 кадров. Можно считать, что птицы там в каждом втором кадре => приблизительно 1000 изображений птичек + 1000 изображений не птичек.

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

Разметка базы


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

Для каждой картинки размечалось два признака:
  1. Тип птицы. Ко мне, к сожалению прилетало лишь два вида синиц. Итого, три типа:
    1. Птицы нет.
    2. Лазоревка
    3. Синица большая
  2. Качество снимка. Субъективная оценка по шкале [0,8].

Итого, имеем для каждой картинки вектор из двух величин. Ну, например, тут:

image

Явно качество нулевое (0), а сидит – большая синица (2).

Всего по базе получилось примерно половина кадров с птицами, половина пустая. При этом синиц-Лазоревок было всего 3-5% от базы. Да, набрать большую базу от них – сложно. И да, обучиться по этим 3-5% (~40 картинок) – нереально. В итоге пришлось обучать только по обычным синицам. И надеяться что рано или поздно база лазоревок наберётся сильно больше.

Расширение базы


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

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

Задача с кормушкой мне понравилась во многом из-за этого. Она с одной стороны очень простая – делается практически мгновенно. А с другой стороны – очень показательная. 90% задач тут – это не имеющая отношения к конкурсам тягомотина.

База, которую мы набрали выше — крайне мала для задач такого вида и не оптимальна. Она не предполагает «стабильности». Всего 4-5 позиций камеры. Одна погода за окном.

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

if (d>20):
  frame = frame[:, :, [2, 1, 0]] # Подготавливаем кадр
  transformed_image = transformer.preprocess('data', frame) # Подготавливаем кадр
  net.blobs['data'].data[0] = transformed_image # Подготавливаем сеть
  net.forward() # Запускаем сеть
  if (net.blobs['pool10'].data[0].argmax()!=0): # 0 - отсутствие цели
      misc.imsave("base/"+str(j)+"_"+
           str(net.blobs['pool10_Q'].data[0].argmax())+".jpg",frame)
      j=j+1
  else: #Кто-то спросит: ЗАЧЕМ?!
      misc.imsave("base_d/"+str(k)+".jpg",frame)
      k=k+1

Как набор базы!? А что же мы раньше делали?

Раньше мы набирали обычную базу. А теперь – мы набираем базу ошибок. За одно утро сетка выдала более 500 ситуаций распознанных как синицы:

image image
image image

Но позвольте! Может ваша сетка не работает? Может вы перепутали каналы, когда передавали изображение к от камеры к сетке?

К сожалению, нет. Это судьба всех сеток обученных на малом объёме данных (особенно у простых сетей). В тренировочном сете было всего 6-9 позиций камеры различных. Мало засветок. Мало посторонних шумов. А когда сетка видит что-то совершенно новое – она может выкинуть неверный результат.

Но это не страшно. Ведь мы прикрутили сбор базы. Всего 300-400 пустых кадров в нашу базу – и ситуация улучшается. Вместо 500 ложных тревог за утро их уже ноль. Только вот что-то и птичек продетектировалось всего 2/3 от их общего числа. Вот этих не распознало:

image image

Для их сбора и стоит «else» в коде выше. Просмотреть базу срабатываний детектора движения за весь день и выбрать 2-3 пропуска просто. Для этих картинок у меня заняло времени — секунд двадцать.

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



Решение задачи на практике – это построение такой схемы, со всеми процессами дообучения, переобучения, сбора и оптимизации сбора.

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

Это всё? База готова? Система работает? Конечно нет. За окном лежит мягкий, белый и пушистый снег. Но он становиться жестким и обледеневшим. Наступает весна. В последние два дня опять попёрли ложняки:



Солнышко светит не оттуда. Снег подтаял. Капель застучала.

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

Пока такого нет.

Генерация базы


Базу можно дополнять автоматическим образом, генерируя искажения. Это значительно увеличивает стабильность. Я делал не все возможные приращения. Можно сделать больше и поднять качество. Что я делал:
  • Отзеркаливание картинки
  • Повороты картинки на углы в пределах 15 градусов
  • Кропы картинки (по 5-10%)
  • Изменения яркости каналов изображения в разных комбинациях

А это можно было бы добавить:
  • Гомография
  • Разбивание картинки на 2 части и склеивание новой. Приращение очень неплохо заходило в этом конкурсе.
  • Выбивание кусков изображения квадратами разных цветов
  • нелинейные преобразования

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

Настройка и запуск сети


Установка


Один из главных вопросов, которые мне хотелось понять для себя — возможность запуска ML-фреймворков для CV на простых устройствах. Например на Raspberry Pi.
Слава богу, что кто-то подумал об этом за меня. На ГитХабе есть полезный репозиторий почти без инструкций.
На RPi B+ Caffe и всё необходимое для него можно собрать и установить где-то за день (самому нужно подходить раз в час и пихать очередную команду). На RPi3 как я понимаю можно сильно быстрее (за 2-3 часа должен справиться).

Чтобы не захламлять статью кучей Linux-команд — просто скидываю ссылку сюда, где я всех их описал. Caffe собирается! Работает!

image

Изначально я думал использовать какую-то простенькую сеточку, например CaffeNet, или даже VGG16. Но автор порта Caffe под RPi настоятельно советовал использовать SqueezeNet. Я попробовал — и мне понравилось. Быстрая, достаточно мало памяти занимает. Точность, конечно, не уровня ResNet. Первая попытка развернуть сеть не очень удалась. Сеть съела 500 МБ оперативной памяти из моих 400 свободных. Достаточно быстро понял, что основная проблема была в выходном слое. Он был от ImageNet на 1000 выводов. Мне было нужно всего десяток выходных нейронов. Это уменьшило размер сети сразу до 150 метров. Сетка сама по себе очень интересная. По точности она сопоставима с AlexNet. При этом в 50 раз быстрее, по заявлениям авторов. Сама сетка реализует следующие принципы:
  1. Свёртки 3*3 заменены на свёртки 1*1. Каждая такая замена в 9 раз уменьшает число параметров
  2. На вход оставшихся свёрток 3*3 пробуют подавать только маленькое число каналов
  3. Уменьшение размера делается как можно позднее, чтобы свёрточные слои имели большую площадь активации
  4. Полный отказ от полносвязных слоёв на выходе. Вместо них используются прямые выходы на распознающие нейроны с convolution-слоя через avg-pooling
  5. Добавление аналогов Residual-слоёв

Итого. Есть локальный компонент:

image

А есть глобальный, созданный из этих локальных:

image

Идеи хорошие. На RPi3 судя по всему даёт реальное время (чую, что 10-15 fps должно быть).
На моём RPi B+ это дало 1.5-2 кадра в секунду. Что ж, на большее, я, если честно, и не рассчитывал.

Авторы порта под Caffe использовали сетку через C++, чтобы повысить производительность. Но я перетащил в Питон. На нём сильно быстрее разрабатывать.

Обучение сети


Во-первых, как я сказал выше, пришлось поменять последний полносвязный слой:

layer {
  name: "conv10_BIRD"
  type: "Convolution"
  bottom: "fire9/concat"
  top: "conv10"
  convolution_param {
    num_output: 3
    kernel_size: 1
    weight_filler {
      type: "gaussian"
      mean: 0.0
      std: 0.01
    }
  }
}
layer {
  name: "conv10_Q"
  type: "Convolution"
  bottom: "fire9/concat"
  top: "conv10_Q"
  convolution_param {
    num_output: 3
    kernel_size: 1
    weight_filler {
      type: "gaussian"
      mean: 0.0
      std: 0.01
    }
  }
}

Я заменил его на два выхода. На одном выходе — наличие птицы + её тип. На втором — качество.
Итоговая скорость работы на RPi B+ у такой штуки ~ 2-3 секунды на кадр + его предобработку (почистить код от конвертаций лишних, обучить в формате в котором OpenCV напрямую данные принимает – будет 1.5-2 секунды).

В реальности, обучения слоя на «качество» – это та ещё морока. Я использовал три подхода (да, можно подходить корректно и брать специальные слои потерь. Но лень:
  1. Девять выходных нейронов, на каждом из которых L2 регуляризация (Euclidian). Решение стянулось к центру матожидания. Незачёт.
  2. Девять выходных нейронов, но по которым разбрасывается не 1-0, а некоторая величина матожидания. Например, для кадра помеченного как “4”: 0, 0, 0.1, 0.4, 0.9, 0.4, 0.1,0, 0. Ошибка по гауссу при таком подходе сглаживает шум в выборке. Обучение более-менее пошло, но точность не понравилась.
  3. Три нейрона с SoftMax на выходе. «Нет птицы», «птица плохого качества» (величина “0” в метрике качества), «птица нормального качества» (величина «1-8» в метрике качества). Этот метод сработал лучше всего. Статистика средненькая, но хоть как-то работает. Плюс при обучении поставил маленький вес слою (0.1)

Оставил — последний. Он единственный который хоть как-то работал.
С птицами по базе всё хорошо. 88%-90% правильного отнесения в класс. При этом, естественно, 100% потеря всех лазоревок. После того как я добрал базу — качество улучшилось.
Ещё чуть-чуть улучшилось за счёт приращений из базы (описывал выше).

Вывод информации, Telegram


Переходим к последней миле. Нужно доставить картинки пользователю. Было несколько вариантов:
  • Оставлять на сетевом диске. Уныние. Посмотреть можно только дома.
  • Выложить в Твиттер. Минус — я им не пользуюсь. Нет привычки. Плюс, кому нафиг нужен такой спам в ленте (иногда прилетало по 100 птичек в день)
  • Почта. Пробовал, знаю. Ужасно. Нет. Конечно, я когда-то на почтовых клиентах сделал управление сетью телескопов, но больше не хотелось.
  • Telegram. Нечто новое для меня, но стоит на телефоне уже пол года, использовался 5 раз.
  • Сделать свой http-клиент.

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

А потом я был приятно удивлён. Несказанно приятно удивлён. Этого часа мне практически хватило, чтобы написать и подключить всё что я задумал. Нет, я конечно вру. Потратил 2 часа. А потом ещё полтора чтобы прикрутить ненужную свистелку. Настолько оно всё просто/удобно/безбажно работает. По сути сделать бота:
  1. Зайти в Telegram
  2. Подключить бота "@BotFather". Написать /start, дальше следовать инструкциям. Через 15 секунд у вас есть свой бот.
  3. Выбрать удобный язык для программирования, найти соответствующий враппер. Я взял питон.
  4. Примеры, которые там будут — на 90% закроют нужный вам функционал.

Как я понял, очень желательна обработка команд /start и /help.
Если я когда-то буду делать умный дом — то чую, что без этой штуки не обойдётся.
Что умеет бот. Ссылка на бота будет ниже:
  1. Послать по запросу последний кадр с птицей. Я разделю это на 2 команды потом: просто кадр и хороший кадр.
  2. Включать режим “переслать все новые кадры с птицами с кормушки”. Каждый раз когда прилетает птичка – рассылаю всем заинтересованным людям её фоточку. Так как это всё хозяйство крутиться на Raspberry Pi – я внёс ограничение на число людей которые могу подключиться к этому режиму, чтобы не перегружать его (15 человек). При этом последних 10 человек периодически буду сбрасывать, чтобы кто-то ещё мог посмотреть. Вот в этом канале будет этот режим дублироваться – @win_feed .
  3. Сколько сегодня было птиц. Простой вопрос – простой ответ.
  4. Загадочный «inline mode». Это штука в телеграмме, которая позволяет при набивке текста в любом сообщении послать запрос боту. Я не знаю зачем я его добавил. Настолько увлёкся, что не мог остановиться. В запрос я добавил вывод последних 5 фотографий с птичками. Типа «обращение к архиву». Делал скорее ради эксперимента.

Бот совмещён с распознаванием. Его текст — в исходниках. Файл capture.py.

Ссылка на бота и на канал с выводом бота — ниже, в подвале статьи.

image

А вот так выглядит режим спама:

image

Как развивать


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

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

Бюджет времени


Очень много из упомянутого я делал в параллельно с другими задачами. Так что оценка может смещаться. Если захотите сделать себе такое же — часть пути помогут срезать мои исходники, но очень много придётся повторять.
  • Запуск старого RPI. Тестирование, проверка, подключение WiFi, подключение сетевых дисков — 3-4 часа.
  • Сборка макета для наблюдения, подвешивание — 1 час
  • Написание первой программы сборки базы — 0.5 часа
  • Разбор базы, анализ, разметка — 5 часов, из них 2 — жена.
  • Установка на RPi caffe — примерно 10-15 часов. Обновление системы, сборка Pip модулей, и.т.д. Процесс чисто в бэкграунде. Раз в час заходить проверять что собралось что нет и запускать дальше.
  • Чтение мануалов по SqueezeNet, обучение, запуск сети, оптимизация, тестирование, сравнение, написание программы обучения, тесты — примерно 4-5 часа + часа 4 системного времени на обучение.
  • Апдейт программы выцепления движения на распознавание — 1 час
  • Telegramm бот (все время в сумме) — 4 часа
  • Анализ собираемой базы, анализ работы, дополнительные обучения, и.т.д. — 3 часа + 5 часов компьютерного времени

Реально это всё дело растянулось недели на три-четыре. Мне кажется, что при наличии исходников и нового RPi — можно сделать раза в 2-3 быстрее.

Исходники


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

Как затестить


Есть несколько ограничений:
  1. Распознавание и Telegram bot крутятся на raspberry pi. Понятно, что мощи у него не много. И от Хабра эффекта он возможно ляжет. Поэтому часть я специально ограничил. Ограничил я функцию «присылать свежую картинку». Это самая нагруженная функция. Всего я сделал доступ на 15 первых человек к этой функции. На 5-6 людях проверил, работает нормально. Плюс буду периодически сбрасывать, чтобы если кому-то интересно смогли её включить. Кроме того, данная функция дублируется на этот Telegram — канал. В случае, если бот перегрузиться и хаброэффект не потянет — я зарегал ему дублирующий бот-аккаунт. Тут напишу что упал, перекину на него и не буду давать адрес. Тогда картинки можно будет смотреть только в канале. Потом верну, чтобы кто интересно — постестил.
  2. Птицы. В январе они летали на кормушку постоянно. За день бывало по 200 прилётов. Но чем дальше время шло — тем меньше их становилось. Не совсем понимаю почему. То ли стайка мигрировала, то ли нашла более кошерное место для еды, то ли объелась семечками, то ли почуяла весну. На прошлой неделе прилетали по 2-3 птичка в день. А то и ни одной. Так что если подключитесь, а птиц не будет — извиняйте.
  3. Бывают ложные обнаружения. Не часто, но бывают. Обычно они вызваны каким-то эффектом который. до этого не наблюдался и друг стал. Поэтому часто идут сериями. Более того. Сейчас весна. Я думаю, что как снег стает (через 2-3 дня) — либо ложняков попрёт в десятки раз больше, либо пропускать будет.
  4. Птички летают в пределах от 8 часов утра до 18 вечера (время Московское).
  5. Кормушка не будет постоянно работать. Хочу разобрать железяку и усовершенствовать. Плюс- скоро снег растает. Неделю продержу включённым, потом буду отключать. Точно верну следующей зимой, скорее всего в сильно более адекватном виде.

Надеюсь, вас напугал.
Вот ссылка на бота — @WindowFeeder_bot
А вот ещё раз канал — t.me/win_feed

Source code


Репозиторий проекта.
Тут — программы для разметки базы. Под винду и под убунту (почему-то OpenCV по разному воспринимает коды клавиатуры, было лень запариваться).
Тут — пример обучения сети. На мой взгляд очень полезный для Caffe. Когда я что-то обучаю сам, то зачастую получается какая-то похожая программка такого типа.
Это — основной код. Тут реализован: детектор движения, бот Telegram, нейронная сетка для распознавания.
Тут база фотографий. Для большинства фотографий есть текстовый файл. В нём две цифры. Первая — тип птицы. Вторая — качество снимка (актуально только когда птица есть). Так же есть картинки без текстовичков. Там всегда нет птицы. Часть базы я взял из VOC2012, чтобы создать подвыборку с изображениями совсем не относящимися к теме. Так что увидите кошечек или собачек — не удивляйтесь.
Если наберёте свою базу, то добавка моей должна повысить стабильность.

Инструкции, полезные команды, и.т.д.


Достаточно большой объём подробностей по настройке RPi я срезал в этой статье. В своём блоге я чуть более подробно рассказывал про некоторый этапы настройки.
Плюс тут я отрезал часть идей которые не получили продолжения — там они есть. Всего 4 заметки по теме: 1, 2, 3, 4.
Версия Caffe под Raspberry Pi утащена отсюда.
Там почти нет описания по установке. Можно читать в моём блоге, можно пробовать по наиболее близкому гайду действовать (пропуская кусок с hdf5).
Гайд по запуску OpenCV на RPi.
Полезная инструкция по созданию бота в Телеграмме. А вообще, большую часть сэмплов про него я брал отсюда. Хороший репозиторий (API под Python).

З.Ю.


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

З.Ю.Ю.


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

Поделиться с друзьями
-->

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


  1. cry_san
    27.02.2017 04:50
    -1

    Вопрос в тему — что насчет загаженного наружного подоконника (олива)?
    Также можно доделать кормушку для отлова птиц. Понравилась птичка — дал команду и дверка закрылась (это как вариант показать детям птичку в живую, а потом ее вместе выпустить).


    1. ZlodeiBaal
      27.02.2017 04:55
      +4

      Кормушка висит где-то с начала января. Пока не загадили. Но летают на 100% синицы. У них тактика «подлетел-схватил-улетел». Тут время на поднасрать не остаётся:)

      Понравилась птичка — дал команду и дверка закрылась

      Я думаю, что после такого птички больше не прилетят)


      1. cry_san
        27.02.2017 04:56
        -2

        Уже раз пойманные не прилетят. Прилетят другие :)


        1. Idot
          27.02.2017 10:21
          +3

          В местности проживает не бесконечное число птиц.


    1. kotyara12
      27.02.2017 11:39

      У меня кормушка на окне висит лет 7 уже. До февраля отливы чистые — пока синицы кормятся. Они «на месте» семечки не лузгают — хватают и улетают на ближайшую ветку. Больше секунды в кормушке не сидят.
      А вот в феврале (в как раз сейчас) начинают прилетать снегири. Красивые, большие. Но ужасные грязнули — как засядет в кормушке, так тут же «и жрет и ...». И в результате весь отлив сразу же покрывается грязью.


      1. ZlodeiBaal
        27.02.2017 11:39

        Снегирей пока не было. Жду.
        Я несколько не уверен, что они прилетят. Они крупнее синиц, а леток не очень большой.


        1. Alexeyco
          27.02.2017 12:52

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


      1. kotyara12
        27.02.2017 12:25
        +2

        Нашел видео, правда старое


  1. mikkisse
    27.02.2017 06:41

    Классные к вам птички залетают :) Респект!


  1. Stas911
    27.02.2017 07:18
    +1

    Идея классная — есть простор для развития!

    Не понял, насчет роста нагрузки от числа подписчиков канала в Телеграм. Если вы пуляете фото в канал — его разве не Телеграм после этого хранит и раздает и не все равно, сколько подписчиков — 15 или 100500?


    1. vlreshet
      27.02.2017 10:10
      +1

      Автор поправит если ошибаюсь — бот отправляет фото не в общий канал, а обрабатывает запрос отдельно от каждого пользователя. Соответственно если будет 1000 подписчиков — то придётся обработать 1000 запросов и выслать фото 1000 раз.


      1. ZlodeiBaal
        27.02.2017 11:42
        +1

        Да, спасибо. Именно так. Как я понял, бот не может одно и то же фото отправить сразу 10 людям.
        Я нашёл один чит, но прикрутил его только в Inline mode. Можно отправить не фото, а ссылку на фото выложенное в канал. Это тратит меньше мощности.
        Возможно у такого подхода есть подводные камни. Не испытывал.


    1. FantomNotaBene
      27.02.2017 10:55
      +1

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


  1. ivan-vovanych
    27.02.2017 08:52
    -2

    Наша кормушка все равно прикольней)


  1. Idot
    27.02.2017 09:04

    Прикольно. Только, не понятно, почему кормушка не открытая, а закрытая.


    1. RoHaS
      27.02.2017 09:27

      Смею предположить, что «Снег подтаял. Капель застучала.» повлечет за собой лужи и кашу в корме. А так все закрыто и сухо. Да и дверка для птичек есть :)


    1. ZlodeiBaal
      27.02.2017 11:44

      Да, хотелось чтобы она была устойчивая к дождю. Бывают ещё кормушки, которые имеют «крышу», а вместо летка щель. Но жене больше понравилась эта:)


  1. DJBlend
    27.02.2017 09:22
    +2

    Решал похожую проблему таким стеком: ip камера hikvision с датчиком движения и отправкой на почту, а с почты через ifttt в telegram


    1. ZlodeiBaal
      27.02.2017 11:45
      +1

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


  1. mortimoro
    27.02.2017 10:48
    +1

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

    PS: есть вероятность, что это были не синицы двух типов, а всего две разные синицы. Так что для полной статистики надо сделать распознавание «лиц», чтобы определять уникальность птиц и не считать два раза одну и ту же ;)


    1. ZlodeiBaal
      27.02.2017 11:47
      +1

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


  1. Mephistophele
    27.02.2017 10:55

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


    1. ZlodeiBaal
      27.02.2017 11:49

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


  1. snikes
    27.02.2017 11:25
    +1

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


  1. Idot
    27.02.2017 11:35

    Меня очень смущает надёжность использования присосок в качестве крепления :(

    PS упс! не заметил, что этот вопрос уже задали.


    1. ZlodeiBaal
      27.02.2017 11:50

      У производителя кормушек есть группа в вконтакте. Изучал там комментарии. Про «отвалилась» не нашёл ни одного. Учитывая, что страховка есть — не очень парюсь. Максимум придётся корм заменить.


  1. ittakir
    27.02.2017 11:50
    +3

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


    1. ZlodeiBaal
      27.02.2017 11:57
      +2

      Нет, не проще:
      1) Точка подвеса камеры движется. Положение летка тоже. Пришлось бы ручную разметку использовать.
      2) Это не решает проблему движущегося фона.В моём случае — качающихся деревьев.
      3) Задача сегменации от фона — это вообще жесткач, если у объекта есть хоть часть цвета совпадающего с фоном.
      4) Еще до появления нейронных сетей я делал такие алгоритмы. Это очень сложно. И очень много эмпирик. А после того как появиться контровое солнце — всё равно всё перестанет работать, пока вручную ещё пяток эмпирик не воткнуть. Нейронная сеть тем и хороша, что она сама ищет эмпирики. И потенциально, при большой базе может использоваться везде.


      1. ittakir
        27.02.2017 13:00
        +3

        1. Камеру можно и закрепить
        2. Деревья мелкие, амплитуда движения низкая. Птица большая, цельная, двигается быстро. Да, эмпирика, но сильно упростит жизнь. Если вы переложите эту логику отфильтровывания деревьев на нейронную сеть, то неизбежно должны будете сделать ее более сложной.
        3. Зачем цвет? Зачем Full HD? Переводите картинку в низкое разрешение, в hsv. Оперируйте яркостью, а не RGB значениями.
        4. Мне кажется, сеть это не магический черный ящик, который сделал вжух-вжух, и решил задачу. Тут нужно самому понять, как можно словами описать алгоритм распознавания птицы. Если пытаться запихать в сеть и фоновые деревья, и солнце, и снег, то ничего не получится. А если вы не можете словами описать процесс выделения птицы, то сеть тем более не справится.


        1. ZlodeiBaal
          27.02.2017 13:06
          +2

          Не хочу с вами спорить. Задачами CV занимаюсь уже лет 8. Делал крупные проекты ещё до прихода нейросетей. В том числе в сфере безопасности. То что вы тут написали простите — полная чушь.
          Могу лишь предложить сделать стабильное решение предложенным вами способом, а потом написать статью почему это не работает:)
          Да, сделать детекцию без сетей можно (но не так как вы пишите). Огромный труд, где-то 3-5 человекомесяцев. При этом работать будет хреново. А на половине окон вообще не будет.


          1. ittakir
            27.02.2017 15:39
            +2

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


            1. ZlodeiBaal
              27.02.2017 16:20

              Для современных алгоритмов эта предварительная фильтрация не нужна. Они и так работают. От фильтрации всё может стать только хуже.
              Главное — база. Чем больше, тем лучше!


  1. makcpop
    27.02.2017 11:51
    +4

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


    1. ZlodeiBaal
      27.02.2017 11:53
      +2

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


  1. noonv
    27.02.2017 12:56

    Отличная работа!


  1. MIKSby
    27.02.2017 13:34

    «Иди кормушки вешай!»


  1. mike_y_k
    27.02.2017 16:37

    Спасибо! Отличная идея.
    Вот ещё одно занятие для RPi 3 с родной камерой. Только не с кормушкой, а с воробьями на балконе ;). Надо будет посмотреть на результат.


    1. ZlodeiBaal
      27.02.2017 16:37

      Наберёте базу — присылайте!:)


  1. Alexeyco
    27.02.2017 18:48

    Скажите, возможно ли примерно то же самое сделать с текстом? Я имею в виду, научить нейросеть распознавать «нежелательные» комментарии.


    1. ZlodeiBaal
      27.02.2017 18:50
      +1

      Да, таких работ море.
      Но вам скорее нужен тот кто в Data Scince специализируется.
      CV — это несколько другое.


  1. Art-Kormushka-com-ru
    27.02.2017 18:49
    +1

    Здравствуйте! За блогом автора следим с первой его статьи. Спасибо Антон за Ваши труды и любовь к нашим пернатым друзьям! Всё пытались придумать как использовать наработки автора в реальных кормушках, но не смогли. Может у кого-то есть идеи на этот счёт? Будем рады выслушать!
    С уважением, Никита.
    Арт-Кормушка.рф


    1. artoym
      01.03.2017 14:41

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


  1. lazywicked
    27.02.2017 23:57
    +1

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


  1. mrgloom
    28.02.2017 00:39

    По моим замерам SqeezeNet v1.1 не быстрее AlexNet (правда это на gtx 1070, а не на встроенных системах), а в статье там обещают 50x fewer parameters.


    1. Vasyutka
      28.02.2017 16:06

      Почти наверняка из-за накладных расходов. один forward на caffe с предв.загрузкой данных — это уже 10мс даже на 1070.


      1. mrgloom
        28.02.2017 20:50
        +1

        Я мерил forward pass через встроенную в Caffe утилиту как то так, не исключено, что какой то оверхед и от Caffe идёт.

        Memory:

        SqueezeNet has 50x fewer weights than AlexNet, but the activations are not particularly small.

        https://github.com/DeepScale/SqueezeNet/issues/7

        Speed:
        https://github.com/DeepScale/SqueezeNet/issues/19
        https://github.com/DeepScale/SqueezeNet/issues/29
        Гм, а тут пишут что быстрее:
        https://github.com/DeepScale/SqueezeNet/issues/16#issuecomment-250696943

        Сравнение:
        https://github.com/DeepScale/SqueezeNet/issues/19#issuecomment-234714578
        https://github.com/DeepScale/SqueezeNet/issues/16#issuecomment-231955551
        https://github.com/DeepScale/SqueezeNet/issues/3
        https://github.com/mrgloom/kaggle-dogs-vs-cats-solution

        В итоге для Caffe на практике меньше захламляет HDD своими снапшотами при тренировке.


        1. ZlodeiBaal
          01.03.2017 02:39

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


          1. mrgloom
            01.03.2017 20:44
            +1

            Мне кажется надо смотреть в сторону что используется на mobile devices и embedded systems.
            Типа http://libccv.org/post/how-to-run-a-state-of-the-art-image-classifier-on-a-iphone/

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

            В целом я не особо в теме в этой области и на Caffe готовое решение не видел.


    1. ZlodeiBaal
      28.02.2017 20:10

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


  1. adm1007s
    02.03.2017 00:38

    Спасибо, было крайне интересно прочесть о Вашем опыте.
    Хочу один вопрос задать по теме доступа к картинкам.
    WD MyBook Live вроде позволяет удаленный доступ организовать при помощи приложений от WD — почему таким вариантом не воспользовались?


    1. ZlodeiBaal
      02.03.2017 00:40

      Зачем это делать в локальной сети? Или вы про удалённый просмотр?
      Там у WD проблемм и глюков море, если что. Он требует чтобы и устройство с которого и устройство на которое заходят прокидывалось через NAT. А сейчас море провайдеров NAT частично банят.


  1. Hando
    06.03.2017 16:47
    -3

    О, круто, спасибо. Сделаю себе ловушку для птичек, чтобы кошку живой едой порадовать.