Размер
Нейрокурятник: часть 4 — итоговая модель и код на прод
Play

Нейрокурятник: часть 4 — итоговая модель и код на прод

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

  • Точность предсказаний не менее 70-90%;
  • Raspberry pi в самом курятнике в идеале мог бы определять принадлежности фотографий к классам;
  • Нужно как минимум научиться отличать всех кур друг от друга. Программа максимум — также научиться считать яйца;

Статьи про нейрокурятник

  1. Вступление про обучение себя нейросетям
  2. Железо, софт и конфиг для наблюдения за курами , который постит события из жизни кур — без нейросети датасетов
  3. Работающая модельдля распознавания кур в курятнике
  4. Итог — работающий бот, распознающий кур в курятнике

0. TL;DR

Для самых нетерпеливых:

  • Точность получилась в итоге порядка 80%;
  • Датасет можно скачать тут;
  • ipynb jupyter notebook'а со всеми выкладками и boiler-plate код с пояснениями можно скачать тут, html версию тут;
  • Скрипты для демонизации и деплоя на прод — тут (ipynb);

1. Прелюдии

Из современных инструментов, которые адекватно подходят этой цели в голову приходят только сверточные нейросети. Поковырявшись (по ссылке рекурсивная статья про нейросети, если вы хотите научиться) весьма основательное время в нейросетях, поучаствовав в нескольких соревнованиях (к сожалению уже закрытых) на Kaggle (из открытых заинтересовали морские котики, но там сложновато) и тем самым по большей части пройдя курс от fast.ai, я обрисовал для себя примерно такой план:

  1. Разметить небольшой датасет (а сегодня реально не нужно много данных, чтобы построить классификатор);
  2. Использовать keras для тестирования максимально большого числа архитектур в течение максимум 1 дня;
  3. Если получится использовать неразмеченные фотографии, чтобы увеличить точность (semi-supervised подход);
  4. Попытаться сделать визуализацию активаций внутренних слоев нейросети;

2. Посмотрим, что получилось!

Итоговая архитектура модели in a nutshell, которая дала порядка 80% точности

Для начала давайте разберемся, что же творится в курятнике. Чтобы успешно сделать прикладной проект, всегда нужно пытаться контролировать максимальную часть технологической цепочки. Вряд ли получится сделать проект, если данные поступают в виде «вот вам 10 терабайт видео в ужасном качестве, сделайте нам модель распознавания видео в режиме реального времени за 10,000 рублей » или «вот вам 50 фото этикеток от пива» (юмор, но это примеры, основанные на реальных… проектах, слава богу не моих).

  • Куры постоянно залазят в гнездо, чтобы просто посидеть или из любопытства, особенно молодые;
  • Молодые куры (белые на фото выше) — до определенного момента не откладывали яйца в гнездо, а просто ковыряли чужие яйца;
  • У кур бывают стычки, но в 95% случаев соблюдаются правила: i) в гнезде 1 курица ii) за время пребывания курицы в гнезде делается 10-20 уникальных фоток iii) курица как правило польностью закрывает яйца собой iv) текущий вид на куриц является продуктом нескольких итераций поиска оптимального расположения камеры;
  • В день делается порядка 300-400 фото, откладывается 5-8 яиц (молодые куры по глупости и боязни неслись в прямом смысле слова под пол, потом после того как было найдено скопище из 22 яиц под полом, они стали нестись в гнездо);
  • На ночь курам выключают свет — они ложатся спать;
  • Было размечено порядка 900 фото;

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

  • Правильно выбрать алгоритмы предобработки данных (логично, что куры крутятся в гнезде, поэтому можно вращать фотографии хоть на 180 градусов!);
  • Выбрать адекватную по размеру и сложности модель;

Вы можете посмотреть почти полный лог экспериментов тут:

  • ipynb jupyter notebook'а со всеми выкладками и boiler-plate код с пояснениями можно скачать тут, html версию тут;

Вот ее графическое представление:

Поясню состав слоев и почему в принципе почти любая современная CNN выглядит очень похоже:

  1. BatchNormalization — усредняет входящие данные (вычитает среднее и делит на стандартное отклонение), что ускоряет тренировку нейросети в десятки раз. Если интересно почему — то уходите в рекурсию тут или тут. Обязателен к применению;
  2. Convolution2D — сверточные слои. По сути представляют собой фильтры, чтобы нейросеть смогла научиться распознавать абстрактные образы. По идее визуализация должна была быть включена в эту статью, но у я не осилил в итоге (если вы не знаете как выглядят изнутри нейросети, то вот ссылки для вас 1 2 3;
  3. MaxPooling2D — усреднение значений фильтров. Обязателен после сверточных слоев;
  4. Dropout — по сути нужен для регуляризации. В эту спецификацию модели не включил его, потому что брал код из другого своего проекта и просто забыл из-за высокой точности модели;
  5. Flatten — чтобы потом вставить dense слой, иначе не получится;

Обратите внимание, что используется categorical_crossentropy вместе с softmax. В качестве оптимизатора используется adam. Не буду останавливаться почему я выбрал именно их (такое сочетание по сути стандарт), но вы можете почитать тут и посмотреть тут 1, 2 и 3.

Сам процесс поиска оптимальной модели выглядит так:

  1. Пробуем разные способы предобработки данных с простейшей моделью (внезапно веса простейшей dense модели из 3 слоев весят несколько гигабайт для больших фото, что не очень хорошо) и выбираем оптимальный;
  2. Пробуем разные архитектуры сверточных (или каких-либо других) нейросетей, выбираем оптимальную;
  3. При достижении какого-либо значимого бенчмарка (50%+ точности, 75% точности — выбирайте от задачи, чем больше классов, тем более мягким должен бенчмарк) — нужно проанализовать, с предсказанием каких фото и каких классов у модели возникают проблемы;
  4. Ансамбли и fine-tuning внешних слоев у больших архитектур нейросетей — опционально — если хотите выиграть конкурс;
  5. Можно попробовать подмешать в свою выборку 20-30% фото из тестовой, валидационной или просто неразмеченной части датасета (semi-supervised, код по идее работает, но у меня именно в этой задаче постоянно умирали kernel-ы, я забил);
  6. Повторять до бесконечности;

А так выглядит процесс гипнотизации прогресс индикатора.

Кстати этот сниппет кода поможет вам, если вы захотите сделать semi-supervised модель в keras

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

Вот соотношение правильных предсказаний к числу фото

А вот основной источник неверных классификаций

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

Поместив все яйца в один класс в итоге я и получил модель примерно с 80% точности на небольшом датасете.

3. Что пойдет на прод?

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

Весь код такого боевого деплоя выглядит примерно так (тут используется tensor flow в качестве бекенда).

Вот в принципе и все.

Модель предсказывает верную курицу ) Ждите финального бота, который постит верных кур.

📎📎📎📎📎📎📎📎📎📎