Хабрахабр

[Перевод] Подсчёт пчёл нейросетью на Raspberry Pi

Опубликовано 17 мая 2018 года

Сразу после установки улея я подумал: «Интересно, как подсчитать количество прилетающих и улетающих пчёл?»

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

Raspberry Pi, стандартная камера Pi и солнечная панель: этого простого оборудования достаточно, чтобы записывать один кадр каждые 10 секунд и сохранять 5000+ изображений в день (с 6 утра до 9 вечера). Во-первых, нужно собрать образцы данных.


Ниже пример изображения… Сколько пчёл вы можете сосчитать?

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

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

v1: полностью свёрточная сеть «пчела есть/нет» на фрагменте

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

v2: изображение RGB → чёрно-белое растровое изображение

Я быстро понял, что задачу можно свести к проблеме трансформации изображения. На входе сигнал камеры RGB, а на выходе — изображение одиночного канала где «белый» пиксель обозначает центр пчёлы.


RGB-вход (фрагмент) и одноканальный выход (фрагмент)

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

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

Архитектура сети — вполне стандартная u-net.

  • полностью свёрточная сеть обучена на фрагментах с половинным разрешением, но работает на изображениях с полным разрешением;
  • кодирование представляет собой последовательность из четырёх свёртываний 3×3 с шагом 2
  • декодирование — последовательность изменений размера по ближайшим соседям + свёртывание 3×3 с шагом 1 + пропуск соединения от кодеров;
  • окончательный слой свёртывания 1×1 с шагом 1 с активацией сигмоидной функции (то есть двоичный выбор «пчела есть/нет» для каждого пикселя).

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

Я сделал декодирование через изменение размера по ближайшим соседям вместо деконволюции скорее по привычке.

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

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

С вероятностной выдачей мы получаем размытое облако там, где могут быть пчёлы. Тут есть некоторый нюанс в постобработке предсказаний на выходе. Всё это пришлось устанавливать вручную и настраивать чисто на глаз, хотя теоретически его можно добавить в конец стека как элемент обучения. Чтобы преобразовать его в чёткую картинку по одному пикселю на пчелу, я добавил пороговое значение, учёт связанных компонентов и обнаружение центроидов с помощью модуля skimage measure. Может, есть смысл сделать это в будущем… 🙂


Вход, необработанная выдача и центроиды кластеров

За один день

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


Три образца, полученные в первый день

За много дней

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

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


Образцы, полученные за три дня

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

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


Слева направо: высокая плотность вокруг входа; пчёлы разного размера; пчёлы на высокой скорости!

Полуконтролируемое обучение

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

Очень простой подход:

  1. Съёмка 10 000 изображений.
  2. Маркировка 100 изображений и обучение model_1.
  3. Использование model_1 для маркировки остальных 9900 изображений.
  4. Обучение model_2 на «размеченных» 10 000 изображений.

В результате model_2 показывает лучший результат, чем model_1.

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


Слева model_1, справа model_1

Маркировка путём исправления плохой модели

Подобные данные также являются отличным примером, как исправление плохой модели происходит быстрее, чем маркировка с нуля…

  1. Помечаем 10 изображений и обучаем модель.
  2. Используем модель для разметки следующих 100 изображений.
  3. Применяем инструмент маркировки для исправления меток на этих 100 изображениях.
  4. Переобучаем модель на 110 картинках.
  5. Повторяем...

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

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

Непосредственно на железе Pi

Изначально планировалось заморозить граф TensorFlow и просто напрямую запустить его на Pi. Это работает без проблем, но вот только Pi снимает лишь 1 изображение в секунду. :/

Запуск на вычислительном модуле Movidius

Меня очень заинтересовала возможность запустить модель на Pi с помощью Movidus Neural Compute Stick. Это удивительный гаджет.

API для преобразования графа TensorFlow в их внутренний формат модели не поддерживает мой способ декодирования. К сожалению, ничего не получилось :/. Здесь нет проблем кроме той, что ничего не получилось. Поэтому пришлось увеличивать размер (upsizing), используя деконволюцию вместо изменений размера по ближайшим соседям. Когда их исправят, можно вернуться к этой теме… Возникает куча маленьких сложностей, из-за которых множились баги.

Так мы избежим любых проблем с неподдерживаемыми операциями на Movidus Neural Compute Stick, хотя маловероятно, что результат получится таким же хорошим, как в модели центроидов v2. Модель v3: изображение RGB → подсчёт пчёл
Это привело меня к третьей версии модели: можем ли мы перейти непосредственно со входа RGB на подсчёт пчёл?

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

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

Реальное и прогнозное количество пчёл в некоторых тестовых образцах

Реальное

40

19

16

15

13

12

11

10

8

7

6

4

v2 (центроиды) прогнозное

39

19

16

13

13

14

11

8

8

7

6

4

v3 (простой подсчёт) прогнозное

33,1

15,3

12,3

12,5

13,3

10,4

9,3

8,7

6,3

7,1

5,9

4,2

… к сожалению, модель по-прежнему не работает на Neural Compute Stick (то есть работает, но выдаёт только случайные результаты). Я составил ещё несколько баг-репортов и опять отложил гаджет, чтобы вернуться потом… когда-нибудь…
Как всегда, осталась куча мелочей…

  • Запуск на Neural Compute Stick (NCS); сейчас ждём некоторой работы с их стороны...
  • Портировать всё на встроенную камеру JeVois. Я немного повозился с ней, но в первую очередь хотел запустить модель на NCS. Я хочу отслеживать пчёл на 120 FPS!!!
  • Отслеживать пчёл между несколькими кадрами/камерами для визуализации оптического потока.
  • Более детально изучить преимущества полуконтролируемого подхода и обучить более крупную модель маркировать данные для меньшей модели.
  • Исследовать возможности NCS; что делать с настройкой гиперпарамеров?
  • Перейти к разработке маленькой версии FarmBot для выполнения некоторых генетических экспериментов с рассадой под управлением ЧПУ (то есть нечто совершенно другое).

Весь код опубликован на Github.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»