Поиск по сайту Поиск

Многозначная классификация с помощью Keras

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

В этом руководстве мы расскажем, как создать многозначную нейронную сеть с помощью Keras.

https://www.pyimagesearch.com/wp-content/uploads/2018/05/keras_multi_label_animation.gif

Многозначная или нечёткая классификация (multi-label classification) позволяет определить, с какой вероятностью объект принадлежит к каждому из классов.

Урок разбит на четыре части.

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

Далее мы кратко обсудим SmallerVGGNet — архитектуру нашей глубокой свёрточной нейронной сети.

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

Cодержание

1. Набор данных
2. Структура проекта
3. Архитектура Keras-модели
4. Создание модели
5. Обучение модели
6. Применение модели к новым изображениям
7. Результаты
8. Загрузки

Набор данных

https://www.pyimagesearch.com/wp-content/uploads/2018/04/keras_multi_label_dataset.jpg

Набор данных состоит из 2167 изображений в шести категориях:

— Черные джинсы (344 изображений)

— Синее платье (386 изображений)

— Синие джинсы (356 изображений)

— Синяя рубашка (369 изображений)

— Красное платье (380 изображений)

— Красная рубашка (332 изображения)

Цель нейросети — классифицировать как цвет, так и тип одежды. Вы можете использовать этот датасет, а можете создать свой с помощью урока «Как (быстро) собрать набор данных для глубокого обучения».

Процесс загрузки и ручного удаления лишних изображений занимает примерно 30 минут.

Структура проекта

В разделе «Загрузки» вы можете скачать архив с кодом и набором данных. Структура проекта выглядит следующим образом:

В корне находятся 6 файлов и 3 папки.

Файлы, с которыми мы будем работать в этом уроке:

  1. search_bing_api.py: этот скрипт позволяет быстро создать набор данных для глубокого обучения. Вам не нужно запускать его, так как датасет уже находится в архиве. Можете использовать его в образовательных целях.
  2. train.py: скрипт для обучения классификатора.
  3. fashion.model: файл модели. Скрипт train.py сериализует модель Keras на диск. Мы будем использовать её позже в файле classify.py.
  4. mlb.pickle: бинаризатор меток MultiLabelBinarizer из scikit-learn, созданный с помощью train.py — этот файл содержит имена классов в виде сериализованных структур данных.
  5. plot.png: график, который создаёт обучающий скрипт. Если вы используете собственный набор данных, не забудьте проверить этот файл на точность, потери и переобучение.
  6. classify.py: скрипт для проверки классификатора. Всегда выполняйте проверку в исходном проекте, прежде чем использовать модель для других задач.

И три каталога:

  1. dataset: папка содержит набор изображений. У каждого класса свой соответствующий подкаталог. Когда датасет упорядочен таким образом, из него проще извлечь метки классов по заданному пути. 
  2. pyimagesearch: это модуль с нашей нейросетью.  В него входят файлы __init__.py и smallervggnet.py.
  3. examples: здесь находятся семь примеров изображений. На каждом из них мы протестируем результаты классификации с помощью скрипта classify.py.

Если список показался вам большим, не пугайтесь: мы рассмотрим файлы в том порядке, в котором они представлены.

Архитектура Keras-модели

https://www.pyimagesearch.com/wp-content/uploads/2018/04/cnn_keras_smallervggnet.png

Архитектура CNN (свёрточной нейронной сети) SmallerVGGNet, которую мы используем для этого урока — упрощённая версия своего прародителя VGGNet. Модель VGGNet впервые представили Карен Симонян и Эндрю Циссерман в своей статье “Very Deep Convolutional Networks for Large Scale Image Recognition в 2015 году.

На этом уроке мы не будем вдаваться в подробности архитектуры нейросети. Если у вас возникнут какие-либо вопросы, задавайте их в комментариях — мы с радостью ответим на них или напишем отдельный пост с описанием модели.

Загрузив и распаковав zip-архив, откройте файл smallervggnet.py из каталога pyimagesearch:

В строках 2-10 мы импортируем необходимые модули. Создадим класс SmallerVGGNet:

Наш класс определён в строке 12. Затем мы создаём функцию сборки (build) в строке 14.

Метод требует четырёх параметров: ширина (width), высота (height), глубина (depth) и классы (classes). Глубина определяет количество цветовых каналов в исходном изображении, а классы — число категорий или меток (не их названия). Мы будем использовать эти параметры в обучающем скрипте для модели с формой входных данных 96 x 96 x 3.

Необязательный аргумент finalAct (значение по умолчанию — “softmax”) будет использоваться в конце построения архитектуры. Изменение этого значения на “sigmoid” позволит нам выполнить многозначную классификацию.

Внутри функции мы инициализируем модель (строка 17) и по умолчанию используем архитектуру “channel_last” в строках 18 и 19. Строки 23-25 нужны для бэкэндов с поддержкой “channel_first”.

Создадим первый слой CONV => RELU => POOL:

Слой CONV имеет 32 фильтра с ядром 3x3 и активацией RELU (Rectified Linear Unit). Мы применяем пакетную нормализацию, max-pooling и 25% исключений.

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

Далее перейдём к двум наборам слоёв (CONV => RELU) * 2 => POOL:

Обратите внимание на изменения размеров фильтров, ядер и pool_size. Так мы постепенно уменьшаем размер сети, но увеличиваем глубину.

За этим блоком следует набор слоёв FC => RELU:

Полностью связанные слои размещаются в конце сети (параметр Dense в строках 57 и 64).

В строке 65 мы определяем, использовать ли активацию “softmax” для классификации по одной метке, или активацию “sigmoid” для нескольких меток. Желаемый параметр надо указать в строке 14 этого сценария и в строке 95 файла train.py.

Создание модели

Теперь, когда мы инициализировали сеть SmallerVGGNet, давайте создадим скрипт для её обучения классификации по нескольким меткам. 

Откройте файл train.py:

В строках 2-19 импортируются необходимые пакеты и модули. Строка 3 подключает бэкэнд matplotlib для сохранения графиков на диск в фоновом режиме.

Мы исходим из того, что на этом этапе у вас уже установлены Keras, scikit-learn, matplotlib, imutils и OpenCV. Если же это ваш первый проект глубокого обучения, то вы можете получить все необходимые библиотеки двумя способами:

  1. используйте предварительно настроенную среду (требует 5 минут вашей работы, а обучение нейросети будет стоить дешевле чашки кофе);
  2. создайте собственное окружение (требует времени, терпения и настойчивости).

Предварительно настроенная среда позволяет быстро загрузить и собрать файлы, завершив работу в считанные минуты. Например, в наших облачных серверах с мощными видеокартами для глубокого обучения NVIDIA Tesla V100 предустановлен образ с Ubuntu 18.04, CUDA Toolkit и средой Deepo c Jupyter Notebok и популярными библиотеками для машинного обучения.

Если вы хотите создать свою среду (и у вас есть время на отладку и устранение неполадок), то советуем ознакомиться со статьями:

Настройка Ubuntu для глубокого обучения с Python  (только для CPU)

Настройка Ubuntu 16.04 + CUDA + GPU для глубокого обучения с Python  (GPU и CPU)

Настройка macOS для глубокого обучения с Python, TensorFlow и Keras

Итак, ваша среда настроена и все пакеты успешно импортированы. Давайте разберём аргументы командной строки:

Аргументы командной строки устанавливают параметры для скрипта подобно аргументам функций.

Мы работаем с четырьмя аргументами (строки 23-30):

--dataset: путь к набору изображений на диске.

--model: путь к сериализованной модели Keras.

--labelbin: путь к выходному бинаризатору с несколькими метками.

--plot: путь к выходному файлу графика обучения.

Перейдём к инициализации важных для процесса обучения переменных:

Переменные в строках 35-38 определяют, что:

— сеть будет обучаться в течение 75 эпох, обрабатывая тренировочные шаблоны и улучшая их распознавание методом обратного распространения ошибки;

— начальная скорость обучения равна 10-3 (значение по умолчанию для оптимизатора Adam);

— размер пакета составляет 32. Вы можете отрегулировать это значение в зависимости от возможностей графического процессора;

— как упоминалось выше, изображения имеют размер 96x96 и содержат 3 канала.

Загрузим и предварительно обработаем данные для обучения:

Здесь мы берём пути к изображениям imagePaths и случайным образом перемешиваем их. Затем инициализируем данные и метки (строки 47 и 48).

Далее пройдёмся по всем изображением, обработаем их и извлечём метки классов:

Сначала мы загружаем каждое изображение в память (строка 53). Затем выполняем его предварительную обработку (строки 54 и 55) и добавляем к списку данных (строка 56).

Строки 60 и 61 разделяют путь к изображению на несколько меток. Строка 60 создаёт список из двух элементов, который добавляется в массив меток в строке 61. Вот пример того, как это выглядит в терминале:

Как видите, список меток — это «массив массивов», в котором каждая составляющая является двухэлементным списком.

Но мы ещё не закончили с предварительной обработкой:

Всего двумя строками кода мы преобразовываем списки данных и меток в массивы NumPy и масштабируем интенсивности пикселей в диапазон [0, 1].

Давайте бинаризуем метки с помощью следующего блока кода:

Для этого мы используем класс MultiLabelBinarizer из scikit-learn. Вы не можете использовать стандартный LabelBinarizer для многозначной классификации. Строки 72 и 73 преобразуют метки в вектор, в котором закодирован представленный на изображении класс.

Вот пример, как кортеж ("red","dress") преобразуется в вектор с шестью категориями:

Операция One-hot encoding преобразует категориальные метки в вектор целых чисел. Тот же принцип применяется в последних двух строках, только у нас будет two-hot encoding.

В последней строке две метки являются “hot” (представлены цифрой «1»), что указывает на их наличие. Если какая-либо из меток отсутствует, то в массиве она будет равна нулю.

Создадим обучающую и тестовую выборки, а также инициализируем генератор данных:

В строках 81 и 82 мы выделяем 80% данных для обучения и 20% для тестирования.

Генератор для добавления изображений инициализируется в строках 85-87. Дополнение данных следует выполнять, если в каждом классе содержится не менее 1000 снимков.

Соберём модель и инициализируем оптимизатор Adam:

В строках 92-95 мы собираем модель с параметром finalAct="sigmoid" для многозначной классификации.

Скомпилируем модель и начнём обучение (это может занять некоторое время в зависимости от характеристик вашего процессора):

В строках 105 и 106 мы компилируем модель, используя бинарную кросс-энтропию ("binary_crossentropy"), а не категориальную ("categorical_crossentropy"). Это может показаться нелогичным для многозначной классификации, но цель — обработать каждую выходную метку как независимое распределение Бернулли. Так мы сможем штрафовать каждый выходной узел по отдельности.

В строках 110-114 запускается процесс обучения с ранее созданным генератором.

После этого сохраним нашу модель и бинаризатор меток на диске:

Построим график потерь и точности:

Процесс построения происходит в строках 127-137, а строка 138 выполняет сохранение файла на диск в виде изображения.

Обучение модели

Откройте терминал, перейдите в каталог проекта и выполните команду:

Как видите, мы обучили сеть и достигли:

98.57% точности классификации на обучающей выборке

98.42% точности классификации на тестовой выборке.

График обучения показан на рисунке:

https://www.pyimagesearch.com/wp-content/uploads/2018/04/plot.png

Применение модели к новым изображениям

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

Откройте файл classify.py в каталоге проекта:

В строках 2-9 мы импортируем пакеты Keras и OpenCV.

Затем обрабатываем аргументы командной строки (12-19).

Загрузим и предварительно обработаем входное изображение:

Обработка происходит таким же образом, как и с обучающими данными.

Загрузим модель с бинаризатором меток и классифицируем изображение:

В строках 34 и 35 происходит загрузка модели и бинаризованных меток. Затем мы классифицируем обработанное изображение (строка 40) и извлекаем индексы двух меток классов (строка 41) следующим образом:

— сортируем индексы массива по их вероятности в порядке убывания;

— получаем два индекса класса.

При желании вы можете изменить этот код для работы с большим числом меток классов. Мы советуем также использовать пороговое значение вероятности и возвращать метки с достоверностью > N%.

Выведем метки класса и из значения на выходное изображение:

Цикл в строках 44-48 рисует две метки и соответствующие им значения вероятности на выходном изображении. Также мы отображаем прогнозы в терминале в строках 51 и 52. И, наконец, показываем изображение на экране (строки 55 и 56).

Результаты

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

Запустите команду:

https://www.pyimagesearch.com/wp-content/uploads/2018/04/keras_multi_label_output_01.png

Успех! Оба класса обнаружены с высокой вероятностью.

Теперь попробуем с синим платьем:

https://www.pyimagesearch.com/wp-content/uploads/2018/04/keras_multi_label_output_02.png

Тоже всё хорошо. Вы можете самостоятельно протестировать остальные примеры из папки examples и поделиться результатами.

Разберём пример с чёрным платьем (example_07.jpg). Раз наша нейросеть может определять чёрные и синие джинсы вместе с синими и красными платьями, сможет ли она классифицировать чёрное платье?

https://www.pyimagesearch.com/wp-content/uploads/2018/04/keras_multi_label_output_07.png

О нет, ошибка! Классификатор сообщает, что модель носит чёрные джинсы.

Что же произошло? Почему прогноз неверен?

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

Загрузки

Zip-архив с исходным кодом и набором данных можно скачать по ссылке (размер архива 562 МБ).

⌘⌘⌘

Надеемся, что вам понравился этот пост. Делитесь своими результатами в комментариях, предлагайте темы для новых статей — мы обязательно опубликуем самые интересные. Если что-то осталось для вас непонятным — задавайте вопросы, и мы поможем разобраться.

С оригинальной статьёй можно ознакомиться на портале pyimagesearch.com.

Улучшаем графику в старых играх и видео с помощью нейросетей

Улучшаем графику в старых играх и видео с помощью нейросетей

Бывало ли с вами такое: вы решили скачать любимую компьютерную игру детства и ненадолго погрузиться в счастливые воспоминания. Установили её,...
Read More
Как создать сайт-портфолио для творческого проекта

Как создать сайт-портфолио для творческого проекта

Резьба по книгам, money art, тканевые скульптуры — искусство может принимать самые разные формы. А благодаря Интернету современные художники могут...
Read More
Нейросеть описывает мир незрячим людям

Нейросеть описывает мир незрячим людям

Голосовые ассистенты могут не только играть в «города» и рассказывать о погоде — они способны на гораздо большее! Например, помогать...
Read More
Экскурсии в дата-центр: как мы провели 300 человек на закрытый объект и почему нас уже не остановить

Экскурсии в дата-центр: как мы провели 300 человек на закрытый объект и почему нас уже не остановить

Отвлекитесь немного от экрана и посмотрите на вещи, которые вас окружают. Стол, кружка, лампа, смартфон, клавиатура — всё это материальные...
Read More
Стэнфордский курс: лекция 3. Функция потерь и оптимизация

Стэнфордский курс: лекция 3. Функция потерь и оптимизация

На прошлой лекции мы разобрались, как работает классификация изображений. Что же может «потеряться» в процессе и можно ли этого избежать?...
Read More
Как ИИ отслеживает небезопасное поведение водителей

Как ИИ отслеживает небезопасное поведение водителей

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

Многозначная классификация с помощью Keras

Можно ли обучить нейросеть делать не один, а сразу несколько прогнозов? Этот вопрос возникает, когда нам необходимо классифицировать изображения по...
Read More
Большая игра, или Загадочная история домена SEX.COM

Большая игра, или Загадочная история домена SEX.COM

“The Internet is for porn” — так пелось в бродвейском мюзикле Avenue Q (пародия на «Улицу Сезам»). И, несмотря на то,...
Read More
Топ-5 голосовых приложений, созданных с помощью GPU

Топ-5 голосовых приложений, созданных с помощью GPU

Речевой ИИ активно развивается и набирает популярность. Появляется всё больше приложений, распознающих речь и обрабатывающих естественный язык. Мы решили выделить...
Read More
Какие тайны скрывает главный домен для e‑commerce

Какие тайны скрывает главный домен для e‑commerce

Домен .SHOP появился в 2016 году и стал прямым ответом индустрии на важный запрос рынка — необходимость в короткой и...
Read More