Распознавание товаров на полках с помощью нейронных сетей на технологиях Keras и Tensorflow Object Detection API |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2018-07-04 11:16 искусственный интеллект примеры, системы технического зрения В статье мы расскажем о применении свёрточных нейронных сетей для решения практической бизнес-задачи восстановления реалограммы по фотографии полок с товарами. С помощью Tensorflow Object Detection API мы натренируем модель поиска/локализации. Улучшим качество поиска мелких товаров на фотографиях с большим разрешением с помощью плавающего окна и алгоритма подавления немаксимумов. На Keras реализуем классификатор товаров по брендам. Параллельно будем сравнивать подходы и результаты с решениями 4 летней давности. Все данные, использованные в статье, доступны для скачивания, а полностью рабочий код есть на GitHub и оформлен в виде tutorial.
Введение Что такое планограмма? План-схема выкладки товара на конкретном торговом оборудовании магазина. Также многие производители заключают соглашения с розничными торговцами о выкладке их товаров. А поскольку производителей много, между ними начинается борьба за лучшее место на полке. Каждый хочет, чтобы его товар лежал в центре напротив глаз покупателя и занял как можно большую площадь. Возникает необходимость постоянного аудита. Тысячи мерчандайзеров перемещаются от магазина к магазину, чтобы убедиться, что товар их компании есть на полке и представлен в соответствии с договором. Иногда они ленятся: гораздо приятнее составить отчёт, не выходя из дома, чем ехать в торговую точку. Появляется необходимость постоянного аудита аудиторов. Естественно, задача автоматизации и упрощения этого процесса решается давно. Одной из самых сложных частей была обработка изображений: найти и распознать товары. И только сравнительно недавно эта задача упростилась настолько, что для частного случая в упрощённом виде её полное решение можно описать в одной статье. Это мы и сделаем. Статья содержит минимум кода (только для случаев, когда код понятнее текста). Полное решение доступно в виде иллюстрированного tutorial'а в jupyter notebooks. Статья не содержит описания архитектур нейронных сетей, принципов работы нейронов, математических формул. В статье мы используем их как инженерный инструмент, не сильно вдаваясь в детали его устройства. Данные и подход Как и для любого data driven подхода, для решений на основе нейронных сетей нужны данные. Собрать их можно и вручную: отснять несколько сотен прилавков и разметить с помощью, например, LabelImg. Можно заказать разметку, например, на Яндекс.Толоке. Мы не можем раскрывать детали реального проекта, поэтому объясним технологию на открытых данных. Ходить по магазинам и делать фотографии было лень (да и нас бы там не поняли), а желание самостоятельно делать разметку найденных в интернете фотографий закончилось после сотого классифицированного объекта. К счастью, совершенно случайно наткнулись на архив Grocery Dataset. В 2014 сотрудники Idea Teknoloji, Istanbul, Turkey выложили в свободный доступ 354 снимка из 40 магазинов, сделанных на 4 камеры. На каждой из этих фотографий они выделили прямоугольниками суммарно несколько тысяч объектов, часть из которых классифицировали в 10 категорий.Это фотографии сигаретных пачек. Мы не пропагандируем и не рекламируем курение. Ничего более нейтрального просто не нашлось. Обещаем, что везде в статье, где это позволяет ситуация, будем использовать фотографии котиков. Кроме размеченных фотографий прилавков, они написали статью Toward Retail Product Recognition on Grocery Shelves с решением задачи локализации и классификации. Это задало своего рода опорную отметку: наше решение с использованием новых подходов должно получиться проще и точнее, иначе это неинтересно. Их подход состоит из комбинации алгоритмов: Недавно свёрточные нейронные сети (CNN) совершили революцию в области компьютерного зрения и совершенно изменили подход к решению такого рода задач. За последние несколько лет эти технологии стали доступными широкому кругу разработчиков, а такие высокоуровневые API как Keras значительно снизили порог вхождения. Сейчас практически любой разработчик уже через несколько дней знакомства может использовать всю мощь свёрточных нейронных сетей. Статья описывает использование этих технологий на примере, показывая, как целый каскад алгоритмов может быть с лёгкостью заменён всего лишь двумя нейронными сетями без потери точности. Решать задачу будем по шагам:
Технологии Основные технологии, которые мы будем использовать: Tensorflow, Keras, Tensorflow Object Detection API, OpenCV. Несмотря на то, что и Windows и Mac OS походят для работы с Tensorflow, мы всё-таки рекомендуем использовать Ubuntu. Даже если вы никогда до этого не работали с этой операционной системой, её использование сохранит вам кучу времени. Установка Tensorflow для работы с GPU — тема, заслуживающая отдельной статьи. К счастью, такие статьи уже есть. Например, Installing TensorFlow on Ubuntu 16.04 with an Nvidia GPU. Некоторые инструкции из неё могут быть устаревшими. Шаг 1. Подготовка данных (ссылка на github)
Получаем следующую структуру папок: Будем использовать информацию из директорий ShelfImages и ProductImagesFromShelves. ShelfImages содержит снимки самих стеллажей. В названии закодирован идентификатор стеллажа с идентификатором снимка. Снимков одного стеллажа может быть несколько. Например, одна фотография целиком и 5 фотографий по частям с пересечениями. Файл C1_P01_N1_S2_2.JPG (стеллаж C1_P01, снимок N1_S2_2): Пробегаем по всем файлам и собираем информацию в pandas data frame photos_df: ProductImagesFromShelves содержит вырезанные фотографии товаров с полок в 11 поддиректориях: 0 — не классифицированные, 1 — Marlboro, 2 — Kent и т.д. Чтобы не рекламировать их, будем пользоваться только номерами категорий без указания названий. Файлы в названиях содержат информацию о стеллаже, положении и размеру пачки на нём. Файл C1_P01_N1_S3_1.JPG_1276_1828_276_448.png из директории 1 (категория 1, стеллаж C1_P01, снимок N1_S3_1, координаты верхнего левого угла (1276, 1828), ширина 276, высота 448): Нам не нужны сами фотографии отдельных пачек (будем вырезать их из снимков стеллажей), а информацию о их категории и положении собираем в pandas data frame products_df: На этом же шаге мы разбиваем всю нашу информацию на два раздела: train для тренировки и validation для мониторинга тренировки. В реальных проектах так делать, конечно же, не стоит. А также не стоит доверять тем, кто так делает. Необходимо как минимум выделить ещё test для финальной проверки. Но даже при таком не очень честном подходе нам важно не сильно обмануть себя. Как мы уже отметили, фотографий одного стеллажа может быть несколько. Соответственно, одна и та же пачка может попасть на несколько снимков. Поэтому советуем разбивать не по снимкам и уж тем более не по пачкам, а по стеллажам. Это нужно, чтобы не получилось так, что один и тот же объект, снятый с разных ракурсов, оказался и в train и в validation. Делаем разбиение 70/30 (30% стеллажей идёт на валидацию, остальное на тренировку):
Убедимся, что при нашем разбиении имеется достаточно представителей каждого класса как для тренировки, так и для валидации: Голубым цветом показано количество товаров категории для валидации, а оранжевым для тренировки. Не очень хорошо обстоят дела с категорией 3 для валидации, но её представителей в принципе мало. На этапе подготовки данных важно не ошибиться, так как вся дальнейшая работа основывается на его результатах. Одну ошибку мы всё-таки допустили и провели много счастливых часов, пытаясь понять, почему качество моделей очень посредственное. Уже чувствовали себя проигравшими «олдскульным» технологиям, пока случайно не заметили, что часть исходных фотографий повёрнута на 90 градусов, а часть сделана вверх ногами. При этом разметка сделана так, как будто фотографии ориентированы правильно. После быстрого исправления дело пошло гораздо веселее. Сохраним наши данные в pkl-файлы для использования на следующих шагах. Итого, у нас есть:
Для проверки отобразим один стеллаж по нашим данным:
Шаг 2. Классификация по брендам (ссылка на github) Классификация изображений является основной задачей в области компьютерного зрения. Проблема заключается в «семантическом разрыве»: фотография – это всего лишь большая матрица чисел [0, 255]. Например, 800x600x3 (3 канала RGB). Почему эта задача является сложной: Как мы уже говорили, авторы используемых нами данных выделили 10 брендов. Это крайне упрощённая задача, поскольку марок сигарет на стеллажах гораздо больше. Но всё, что не попало в эти 10 категорий, было отправлено в 0 — не классифицированное: " Их статья предлагает такой алгоритм классификации с итоговой точностью 92%: Что будем делать мы:
Звучит «объёмно», но мы всего лишь воспользовались примером Keras «Trains a ResNet on the CIFAR10 dataset» взяв из него функцию создания ResNet v1. Для запуска процесса тренировки надо подготовить два массива: x – фотографии пачек с размерностью (количество_пачек, высота, ширина, 3) и y – их категории с размерностью (количество_пачек, 10). Массив y содержит так называемые 1-hot вектора. Если категория пачки для тренировки имеет номер 2 (от 0 до 9), то этому соответствует вектор [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]. Важный вопрос, как быть с шириной и высотой, ведь все фотографии сделаны с разным разрешением с разного расстояния. Надо выбрать какой-нибудь фиксированный размер, к которому можно привести все наши снимки пачек. Этот фиксированный размер является мета-параметром, от которого зависит, как будет тренироваться и работать наша нейросеть. С одной стороны, хочется сделать этот размер как можно больше, чтобы ни одна деталь снимка не осталась незамеченной. С другой стороны, при нашем скудном объёме данных для тренировки это может привести к быстрому переобучению: модель будет работать идеально на тренировочных данных, но плохо — на данных для валидации. Мы выбрали размер 120x80, возможно, на другом размере мы получили бы лучший результат. Функция масштабирования:
Отмасштабируем и отобразим одну пачку для проверки. Название марки человеком читается с трудом, посмотрим, как справится с задачей классификации нейронная сеть: После подготовки по флагу, полученному на предыдущем шаге, разбиваем массивы x и y на x_train/x_validation и y_train/y_validation, получаем:
Данные подготовлены, функцию конструктор нейронной сети архитектуры ResNet v1 мы копируем из примера Keras:
Конструируем модель:
У нас довольно ограниченный набор данных. Поэтому для того, чтобы модель во время тренировки не видела одну и ту же фотографию каждую эпоху, используем аугментацию: случайным образом смещаем снимок и немного вращаем. Keras предоставляет для этого такой набор настроек:
Запускаем процесс тренировки.
После тренировки и оценки получаем точность в районе 92%. У вас может получиться другая точность: данных крайне мало, поэтому точность очень сильно зависит от удачности разбиения. На этом разбиении мы не получили точность значительно выше той, что была указана в статье, но мы практически ничего не сделали сами и написали мало кода. Более того, мы можем с лёгкостью добавить новую категорию, а точность должна (по идее) значительно вырасти, если мы подготовим больше данных. Для интереса сравниваем confusion-матрицы: Практически все категории наша нейронная сеть определяет лучше, кроме категорий 4 и 7. Также бывает полезно посмотреть на самых ярких представителей каждой ячейки confusion matrix: Ещё можно понять, почему Parliament был принят за Camel, но вот почему Winston был принят за Lucky Strike – совершенно непонятно, у них же ничего общего. Это и есть основная проблема нейронных сетей – совершенная непрозрачность того, что там внутри происходит. Можно, конечно, визуализировать некоторые слои, но для нас эта визуализация выглядит так: Очевидная возможность улучшить качество распознавания в наших условиях – добавлять больше фотографий. Итак, классификатор готов. Переходим к детектору. Шаг 3. Поиск товаров на фотографии (ссылка на github) Следующие важные задачи в области компьютерного зрения: семантическая сегментация, локализация, поиск объектов и сегментация экземпляров. Для нашей задачи нужен object detection. Статья 2014 года предлагает подход на основе метода Виолы-Джонса и HOG с визуальной точностью: Благодаря использованию дополнительных статистических ограничений точность у них получается весьма хорошей: Сейчас задача распознавания объектов успешно решается с помощью нейронных сетей. Мы воспользуемся системой Tensorflow Object Detection API и натренируем нейронную сеть с архитектурой SSD Mobilenet V1. Тренировка такой модели с нуля требует много данных и может занять дни, поэтому мы используем предтренированную на данных COCO модель по принципу transfer learning. Ключевая концепция этого подхода такая. Почему ребёнку не надо показывать миллионы предметов, чтобы он научился находить и отличать шарик от кубика? Потому что у ребёнка есть 500 миллионов лет развития зрительной коры мозга. Эволюция сделала зрение крупнейшей сенсорной системой. Почти 50% (но это неточно) нейронов человеческого мозга отвечают за обработку изображений. Родителям остаётся только показать шарик и кубик, а затем несколько раз поправить ребёнка, чтобы он отлично находил и отличал одно от другого. С философской точки зрения (с технической отличий больше, чем общего), transfer learning в нейронных сетях работает схожим образом. Свёрточные нейронные сети состоят из уровней, каждый из которых определяет всё более сложные формы: выделяет ключевые точки, объединяет их в линии, которые в свою очередь объединяет в фигуры. И только на последнем уровне из совокупности найденных признаков определяет объект. У предметов реального мира очень много общего. При transfer learning мы используем уже натренированные уровни определения базовых признаков и обучаем лишь слои, ответственные за определение объектов. Для этого нам достаточно пары сотен фотографий и пары часов работы рядового GPU. Сеть изначально была тренирована на наборе данных COCO (Microsoft Common Objects in Context), а это 91 категория и 2 500 000 изображений! Много, хотя и не 500 миллионов лет эволюции. Забегая немного вперёд, эта gif-анимация (немного медленная, не прокручивайте сразу) из tensorboard визуализирует процесс обучения. Как видим, вполне качественный результат модель начинает выдавать практически сразу, дальше идёт уже шлифовка: «Тренер» системы Tensorflow Object Detection API самостоятельно умеет делать аугментацию, вырезать для тренировки случайные части изображений, подбирать «негативные» примеры (участки фотографии, не содержащие никаких объектов). По идее, никакая предобработка фотографий не нужна. Однако на домашнем компьютере с HDD и маленьким объёмом оперативной памяти работать с изображениями высокого разрешения он отказался: сначала долго висел, шуршал диском, потом вылетел. В итоге, мы сжали фотографии до размера 1000x1000 пикселей с сохранением соотношения сторон. Но так как при сжатии большой фотографии теряется много признаков, сначала из каждой фотографии стеллажа вырезали несколько квадратов случайного размера и сжали их в 1000x1000. В результате в тренировочные данные попали и пачки в высоком разрешении (но мало), и в маленьком (но много). Повторимся: этот шаг вынужденный и, скорее всего, совершенно не нужный, а возможно, и вредный. Подготовленные и сжатые фотографии сохраняем в отдельные директории (eval и train), а их описание (с содержащимися на них пачками) формируем в виде двух pandas data frame (train_df и eval_df): Система Tensorflow Object Detection API требует, чтобы входные данные были представлены в виде tfrecord-файлов. Сформировать их можно с помощью утилиты, но мы сделаем это кодом:
Нам остаётся подготовить специальную директорию и запустить процессы: Структура может быть и другой, но мы находим её очень удобной. Директория data cодержит сформированные нами файлы с tfrecords (train.record и eval.record), а также pack.pbtxt с типами объектов, на поиск которых мы будем тренировать нейронную сеть. У нас только один тип определяемых объектов, поэтому файл очень короткий: Директория models (моделей для решения одной задачи может быть много) в дочерней директории ssd_mobilenet_v1 содержит настройки для тренировки в .config файле, а также две пустые директории: train и eval. В train «тренер» будет сохранять контрольные точки модели, «оценщик» будет подхватывать их, запускать на данных для оценки и складывать в директорию eval. Tensorboard будет следить за этими двумя директориями и отображать информацию по процессу. Детальное описание структуры конфигурационных файлов и т.д. можно найти здесь и здесь. Инструкции по установке Tensorflow Object Detection API можно найти здесь. Заходим в директорию models/research/object_detection и выкачиваем предтренированную модель:
Копируем туда же подготовленную нами директорию pack_detector. Сначала запускаем процесс тренировки:
Запускаем процесс оценки. У нас нет второй видеокарты, поэтому запускаем его на процессоре (с помощью инструкции CUDA_VISIBLE_DEVICES=""). Из-за этого он будет сильно запаздывать относительно процесса тренировки, но это не так страшно:
Запускаем процесс tensorboard:
После этого мы можем видеть красивые графики, а также реальную работу модели на оценочных данных (gif в начале): Процесс тренировки можно в любой момент остановить и возобновить. Когда считаем, что модель достаточно хороша, сохраняем чекпоинт в виде inference graph:
Итак, на этом шаге мы получили inference graph, который можем использовать для поиска объектов пачек. Переходим к его использованию. Шаг 4. Реализация поиска (ссылка на github) Код загрузки inference graph и инициализации есть по ссылке выше. Ключевые функции поиска:
Функция находит ограничивающие прямоугольники (bounded boxes) для пачек не на всей фотографии, а на её части. Также функция отфильтровывает найденные прямоугольники с низким показателем обнаружения (detection score), указанным в параметре cutoff. Получается дилемма. С одной стороны, при высоком cutoff мы теряем много объектов, с другой — при низком cutoff начинаем находить много объектов, которые не являются пачками. При этом находим всё равно не всё и не идеально: Однако заметим, что если мы запустим функцию для небольшого куска фотографии, то распознавание получается практически идеальным при cutoff = 0.9: Это происходит из-за того, что модель SSD MobileNet V1 принимает на вход фотографии 300x300. Естественно, при таком сжатии теряется очень много признаков. Но эти признаки сохраняются, если мы вырезаем небольшой квадрат, содержащий несколько пачек. Это наталкивает на идею применения плавающего окна: небольшим прямоугольником пробегаем по фотографии и запоминаем всё найденное. Возникает проблема: мы находим по несколько раз одни и те же пачки, иногда в очень урезанном варианте. Эту проблему можно решить с помощью алгоритма подавления немаксимумов. Идея крайне простая: за один шаг находим прямоугольник с максимальным показателем распознавания (detection score), запоминаем его, удаляем все остальные прямоугольники, которые имеют площадь пересечения с ним больше overlapTresh (реализация найдена на просторах интернета с небольшими изменениями):
Результат получается визуально почти идеальным: Результат работы на фотографии плохого качества с большим количеством пачек: Как мы видим, количество объектов и качество фотографий не помешало распознать все упаковки правильно, чего мы и добивались. Заключение Этот пример в нашей статье довольно «игрушечный»: авторы данных уже собирали их в расчёте на то, что им придётся использовать их для распознавания. Соответственно, выбрали только хорошие снимки, сделанные при нормальном освещении не под углом и т.д. Реальная жизнь намного богаче.
Всё это кардинально меняет и усложняет процесс подготовки данных, тренировки и архитектуру применяемых нейронных сетей, но нас не остановит. Источник: habr.com Комментарии: |
|