TL; DR: очень легкое руководство по обнаружению объектов на изображениях. Мы будем загружать простые изображения и применять к ним все более сложные нейронные сети. В конце концов, алгоритм сможет обнаруживать несколько объектов разной формы и цвета (изображение ниже). Чтобы продолжить, вы должны иметь базовое представление о нейронных сетях.

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

В этом сообщении блога мы рассмотрим обнаружение объектов - выяснение, какие объекты находятся на изображении. Например, представьте себе беспилотный автомобиль, которому необходимо обнаруживать другие автомобили на дороге. Существует множество сложных алгоритмов обнаружения объектов. Для них часто требуются огромные наборы данных, очень глубокие сверточные сети и длительное время обучения. Чтобы упростить изучение этого руководства, мы применим два упрощения: 1) Мы используем не настоящие фотографии, а изображения с абстрактными геометрическими формами. Это позволяет нам загружать данные изображения и использовать более простые нейронные сети. 2) Мы прогнозируем фиксированное количество объектов на каждом изображении. Это значительно упрощает весь алгоритм (на самом деле он удивительно прост, если не считать нескольких уловок). В конце поста я расскажу, как можно расширить этот подход, чтобы обнаружить гораздо больше объектов на изображении.

Я постарался сделать это руководство как можно проще: я буду идти по шагам, начиная с обнаружения одного объекта. Для каждого шага есть блокнот Jupyter с полным кодом в этом репозитории на github. Вам не нужно загружать дополнительный набор данных. Код написан на Python плюс keras, поэтому сети должны быть просты для понимания даже новичкам. Кроме того, я использую (в основном) очень простые сети прямого распространения, так что вы можете обучить их за считанные минуты.

Обнаружение одного объекта

Начнем с простого: мы спрогнозируем ограничивающую рамку отдельного прямоугольника. Чтобы создать «изображения», я создал кучу массивов numpy 8x8, установил фон на 0 и случайный прямоугольник в массиве на 1. Вот несколько примеров (белый - 0, черный - 1):

Нейронная сеть - это очень простая сеть прямого распространения с одним скрытым слоем (без сверток, ничего особенного). Он принимает сплющенное изображение (т.е. 8 x 8 = 64 значения) в качестве входных данных и прогнозирует параметры ограничивающей рамки (т.е. координаты x и y нижнего левого угла, ширину w и высоту h). Во время обучения мы просто регрессируем прогнозируемые граничные рамки к ожидаемым с помощью среднеквадратичной ошибки (MSE). В качестве оптимизатора я использовал adadelta - это в основном стандартный стохастический градиентный спуск, но с адаптивной скоростью обучения. Это действительно отличный выбор для экспериментов, потому что вам не нужно тратить много времени на оптимизацию гиперпараметров. Вот как сеть реализована в keras:

model = Sequential([
        Dense(200, input_dim=64), 
        Activation('relu'), 
        Dropout(0.2), 
        Dense(4)
    ])
model.compile('adadelta', 'mse')

Я обучил эту сеть с помощью 40k случайных изображений в течение 50 эпох (~ 1 минута на процессоре моего ноутбука) и получил почти идеальные результаты. Вот предполагаемые ограничивающие рамки на изображениях выше (они были вытянуты во время обучения):

Неплохо, не правда ли? Вы можете видеть, что я также нанес значения долговых обязательств над каждой ограничивающей рамкой: этот индекс называется I ntersection O ver U nion и измеряет перекрытие. между прогнозируемой и реальной ограничивающей рамкой. Он рассчитывается путем деления площади пересечения (красный на изображении ниже) на площадь объединения (синий). Долговая расплата находится в диапазоне от 0 (без перекрытия) до 1 (без перекрытия). В приведенном выше эксперименте я получил почти идеальную долговую расписку в среднем 0,9 (по имеющимся тестовым данным). Код этого раздела находится в этой записной книжке Jupyter.

Обнаружение нескольких объектов

Прогнозирование одного объекта не так уж и весело, поэтому давайте добавим еще один прямоугольник. По сути, мы используем тот же подход, что и выше: загрузите изображения с помощью массивов 8x8 numpy и обучите нейронную сеть прямого распространения предсказывать два ограничивающих прямоугольника (то есть вектор x1, y1, w1, h1, x2, y2, w2, h2 ). Однако, если мы просто продолжим и сделаем это, мы получим следующий (весьма неутешительный) результат:

Обе ограничивающие рамки кажутся посередине прямоугольников. Что случилось? Представьте себе следующую ситуацию: мы обучаем нашу сеть на крайнем левом изображении на графике выше. Предположим, что ожидаемая ограничивающая рамка левого прямоугольника находится в позиции 1 в целевом векторе (x1, y1, w1, h1), а ожидаемая ограничивающая рамка правого прямоугольника находится в позиции 2 в вектор (x2, y2, w2, h2). Судя по всему, наш оптимизатор изменит параметры сети так, чтобы первый предсказатель сдвинулся влево, а второй предсказатель сдвинулся вправо. Представьте себе, что чуть позже мы встречаем похожее изображение, но на этот раз позиции в целевом векторе поменялись местами (т.е. левый прямоугольник в позиции 2, правый прямоугольник в позиции 1). Теперь наш оптимизатор потянет предсказатель 1 вправо, а предсказатель 2 - влево - в точности противоположно предыдущему шагу обновления! Фактически, предсказанные ограничивающие рамки остаются в центре. А поскольку у нас огромный набор данных (40 тысяч изображений), таких «дубликатов» будет довольно много.

Решение состоит в том, чтобы назначить каждый предсказанный ограничивающий прямоугольник прямоугольнику во время обучения. Затем предсказатели могут научиться специализироваться на определенных местах и ​​/ или формах прямоугольников. Для этого мы обрабатываем целевые векторы после каждой эпохи: для каждого обучающего изображения мы вычисляем среднеквадратичную ошибку между прогнозом и целевым A) для текущего порядка ограничивающих прямоугольников в целевом векторе (т. Е. x1, y1, w1, h1, x2, y2, w2, h2) и B), если ограничивающие прямоугольники в целевом векторе перевернуты (т. е. x2, y2, w2, h2, x1, y1, w1, h1). Если MSE A ниже, чем B, мы оставляем целевой вектор как есть; если MSE B ниже, чем A, мы переворачиваем вектор. Я реализовал этот алгоритм здесь. Ниже представлена ​​визуализация процесса переворачивания:

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

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

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

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

Классификация объектов

Обнаружение объектов сейчас работает довольно хорошо, но, конечно, мы также хотим сказать, что такое объект. Поэтому мы добавим треугольники и определим, является ли объект прямоугольником или треугольником. Замечательно то, что для этого нам не нужен дополнительный алгоритм или рабочий процесс. Мы будем использовать ту же сеть, что и выше, и просто добавим одно значение для каждого ограничивающего прямоугольника к целевому вектору: 0, если объект представляет собой прямоугольник, и 1, если это треугольник (т. Е. Двоичная классификация; код здесь).

Вот результаты (я увеличил размер изображения до 16x16, чтобы было легче распознать маленькие треугольники):

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

Собираем все вместе: фигуры, цвета и сверточные нейронные сети

Хорошо, все работает, так что давайте немного повеселимся: мы применим этот метод к еще нескольким реалистичным сценам, то есть к разным цветам, большему количеству форм и нескольким объектам одновременно. Для начальной загрузки изображений я использовал библиотеку pycairo, которая может записывать изображения RGB и простые формы в многочисленные массивы. Я также внес некоторые изменения в саму сеть, но давайте сначала посмотрим на результаты:

Как видите, ограничивающие рамки не идеальны, но в большинстве случаев они находятся в нужном месте. Средняя долговая расписка на тестовом наборе данных составляет около 0,4, что неплохо для распознавания трех объектов одновременно. Предсказанные формы и цвета (написанные над ограничивающими рамками) в значительной степени идеальны (точность теста 95%). Судя по всему, сеть действительно научилась назначать предикторы различным объектам (как мы и стремились с помощью описанного выше трюка с переворачиванием).

По сравнению с простыми экспериментами, описанными выше, я сделал три модификации:

1) Я использовал сверточную нейронную сеть (CNN) вместо сети прямого распространения. CNN сканируют изображение с помощью обучаемых фильтров и извлекают все больше и больше абстрактных характеристик на каждом уровне. Фильтры на ранних слоях могут, например, обнаруживать края или цветовые градиенты, в то время как более поздние слои могут регистрировать сложные формы. Я не буду здесь вдаваться в технические подробности, но вы можете найти отличные вступления в лекциях из класса CS231n Стэнфорда или в этой главе из книги Майкла Нильсена. Для результатов, показанных выше, я обучил сеть с четырьмя сверточными и двумя объединяющими слоями в течение примерно 30–40 минут. Более глубокая / более оптимизированная / более длинная обученная сеть, вероятно, может дать лучшие результаты.

2) Я не использовал одно (двоичное) значение для классификации, а только горячие векторы (0 везде, 1 в индексе класса). В частности, я использовал один вектор для каждого объекта для классификации формы (прямоугольник, треугольник или круг) и один вектор для классификации цвета (красный, зеленый или синий). Обратите внимание, что я добавил случайные вариации цветов во входных изображениях, чтобы увидеть, сможет ли сеть справиться с этим. В целом целевой вектор для изображения состоит из 10 значений для каждого объекта (4 для ограничивающей рамки, 3 для классификации формы и 3 для классификации цвета).

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

Вы можете найти окончательный код в этой записной книжке.

Объекты реального мира

Распознавание форм - отличный и простой пример, но, очевидно, это не то, чем вы хотите заниматься в реальном мире (к сожалению, в природе не так много абстрактных 2D-форм). Кроме того, наш алгоритм может предсказать только фиксированное количество ограничивающих рамок на изображение. Однако в реальном мире у вас есть разные сценарии: на небольшой боковой дороге может не быть машин, но как только вы едете по шоссе, вы должны одновременно распознавать сотни автомобилей.

Несмотря на то, что это кажется незначительной проблемой, на самом деле ее довольно сложно решить - как алгоритм должен решать, что является объектом, а что фоном, если он не знает, сколько там объектов? Представьте, что вы смотрите на дерево с близкого расстояния: даже если вы видите только кучу листьев и палочек, вы все равно можете четко сказать, что это один объект, потому что вы понимаете, что такое дерево. Если бы вместо этого листья валялись на полу, вы бы легко обнаружили их как отдельные объекты. К сожалению, нейронные сети не совсем понимают, что такое деревья, поэтому это довольно сложная задача для них.

Из множества алгоритмов, которые обнаруживают объекты на переменном количестве объектов (например, Overfeat или R-CNN; посмотрите эту лекцию для обзора), я хочу выделить только один, потому что он симпатичный аналогично методу, который мы использовали выше: он называется YOLO (Y или O nly L ook O nce ). В отличие от старых подходов, он обнаруживает объекты на изображении за один проход через нейронную сеть. Короче говоря, он делит изображение на сетку, прогнозирует два ограничивающих прямоугольника для каждой ячейки сетки (то есть точно так же, как мы делали выше), а затем пытается найти лучшие ограничивающие прямоугольники по всему изображению. Поскольку YOLO требуется только один проход по сети, он очень быстрый и работает даже с видео. Ниже представлена ​​демонстрация, а другие примеры вы можете увидеть здесь.

Если вы хотите быть в курсе моих работ, подпишитесь на меня в Twitter (@jrieke)! Вы также можете ознакомиться с некоторыми другими проектами на моем сайте.