Как создать мощные функции из глубоких сверточных сетей

Во время отпуска в прекрасной Франции я и моя семья много играли в SET, простую и элегантную карточную игру. Цель состоит в том, чтобы найти определенные комбинации карт до того, как их найдут другие. Играя в игру, мы часто смотрели на карты, гадая, есть ли еще один НАБОР, которого мы просто не видим. Так начался забавный личный побочный проект, в котором я применяю машинное обучение для нахождения комбинаций SET.

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

«То, что я не могу создать, я не понимаю»

- Ричард П. Фейнман

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

Вместо YOLO мне будет интереснее и сложнее начать с нуля.

Общий план выглядит следующим образом:

1. Извлечение карточек из изображения
Используйте компьютерное зрение для извлечения отдельных карточек.

2. Классифицируйте каждое отдельное изображение
Используйте глубокую сверточную сеть для создания функций для (линейного) классификатора.

3. Найдите допустимые комбинации SET
Используйте комбинаторику для правильных наборов. Интересно, что есть элегантный способ сделать это всего в нескольких строках кода.

Об игре

Прежде чем мы углубимся в детали, позвольте мне немного рассказать об игре в SET.

SET - популярная карточная игра, которая бросает вызов вашим навыкам распознавания образов. Цель игры - найти «НАБОР», который представляет собой особую комбинацию из трех карт.

Есть 81 уникальная карточка с четырьмя атрибутами: цвет, форма, заливка и количество. Каждый атрибут может принимать три разных значения. Три карты называются набором, если по каждому из четырех атрибутов карты либо одинаковы, либо все разные [1]

На стол кладут в общей сложности 12–21 карту, и в реальном времени игроки пытаются собрать как можно больше наборов.

Существуют разные версии игры. Версия, которую я использовал для этого проекта, - это версия Ravensburger 2001 года, которая имеет следующие особенности:

  • цвет: красный, зеленый, фиолетовый
  • форма: квадратная, волнистая, круглая
  • заливка: сплошная, пунктирная, открытая
  • количество: один, два, три

Игра SET была изобретена Маршей Джин Фалько в 1974 году. Как генетический исследователь она изучала, наследуется ли эпилепсия у немецких овчарок. Чтобы представить генетическую информацию собак, она начала рисовать символы на карточках. Различные свойства (например, цвет) символов отражали разные черты собак. Она поняла, что это может быть непростая головоломка, и при поддержке друзей и семьи она разработала и продала карточную игру. SET стал очень популярным как внутри, так и за пределами математического сообщества. [1]

1. Извлеките карточки из изображения.

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

  • Идентификация карточек. Чтобы найти карточки на изображении, мы используем тот факт, что белые карточки сильно отличаются от фона. Чтобы усилить этот эффект, изображения сначала подвергаются предварительной обработке. Затем контуры находятся путем группировки похожих пикселей. Наконец, контуры, которые не соответствуют типичным карточкам (например, символы на карточках), отфильтровываются.
  • Регистрация изображения - найденные контуры преобразуются в единую систему координат, это называется совмещением изображения. Таким образом, все карточки окажутся в альбомной ориентации и их можно будет вырезать из изображения.

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

2. Классифицируйте каждое изображение по отдельности.

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

Создайте набор данных

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

Всего трех примеров в классе недостаточно для успешного обучения модели. Используя ImageDataGenerator API в Keras, вы можете создавать искусственные образцы из базового набора данных. Таким образом, вы можете создать набор данных произвольного размера, в котором карточки поворачиваются, масштабируются, переворачиваются и т. Д. Реальные образцы лучше, чем искусственные, но это отличная альтернатива, если вы не хотите сами делать тысячи снимков.

Протестируйте базовую модель

В качестве основы я обучил модель логистической регрессии и использовал расширенные изображения в качестве входных данных. В приведенных ниже результатах вы можете увидеть производительность этой модели для разных размеров наборов данных. С обучающим набором из 8100 дополненных изображений точность проверки составляет чуть более 43%.

Для сравнения, модель, которая выбирает классы случайным образом, получит только 1,23%, так что модель линейной логистической регрессии, по крайней мере, научилась чему-то полезному.

Для наших целей действительно важно, чтобы точность была высокой . Если мы хотим найти все комбинации SET на изображении, нам нужно правильно классифицировать 12+ карт. Точность 91% или меньше означает, что в среднем в каждом изображении есть карта, неправильно классифицированная, что нарушит обнаружение SET.

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

Выбор стратегии трансферного обучения

Для нашей задачи я мог бы попытаться обучить глубокую сверточную нейронную сеть (DCNN) с нуля, но модель, вероятно, переборщится из-за моего небольшого (базового) набора данных.

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

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

  • Если ваш новый набор данных большой:
    с большим набором данных меньше шансов переобучить, поэтому вы можете точно настроить всю сеть, или если ваши данные достаточно разные, обучите DCNN с нуля. На практике, даже если набор данных отличается, инициализация сети с весами из предварительно обученной модели все еще может быть полезной.
  • Если ваш новый набор данных невелик:
    Не тренируйте и не настраивайте DCNN, потому что он переоборудуется. Вместо этого обучите линейный классификатор *, используя CNN-функции из более ранних или более поздних слоев в зависимости от того, насколько набор данных похож на исходный набор данных.
    Если ваш набор данных отличается, выберите более общие функции где-нибудь раньше в сети. Если это похоже, наиболее полезны функции из более специфичных для набора данных конечных слоев.

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

Для задачи обнаружения SET у нас есть очень маленький набор данных, который также сильно отличается от изображений ImageNet, поэтому стратегия передачи обучения для этого проекта будет заключаться в обучении линейного классификатор из «где-то раньше» в сети. Следующий шаг - выяснить, какой слой обеспечит наилучшую производительность.

Поиск лучшего слоя

Из приведенных выше рекомендаций мы знаем, что нам нужно выбрать слой «где-то раньше» в сети, но как мы узнаем, какой слой дает наилучшие результаты? Чтобы Чтобы найти лучший уровень для нашей задачи классификации SET, я решил протестировать каждый уровень и сравнить производительность на проверочном наборе. Экспериментальная установка выглядит следующим образом.

Для каждого слоя i в глубокой сверточной сети:

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

Слой с наивысшей точностью проверки будет использоваться для окончательной модели.

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

Результаты для ResNet50

Точность проверки для каждого из 50 сверточных слоев модели ResNet50 [2] показана на диаграмме ниже.

Что мне показалось интересным:

  • После первого сверточного слоя (слой 1) сети точность проверки сопоставима с базовыми оценками. Например, для 8100 изображений точность проверки составляет 48,1%. Это небольшое улучшение по сравнению с исходным уровнем (43,2%).
  • По мере углубления в сеть точность проверки улучшается, но оценка вовсе не увеличивается монотонно. Есть высокие пики и глубокие впадины, где каким-то образом представления признаков менее оптимальны для обнаружения карт SET.
  • Количество слоев обеспечивает 100% точность проверки. Лучшие слои находятся где-то на среднем и верхнем уровнях сети. Хотя высший балл кажется впечатляющим, мы должны учитывать, что набор для проверки очень мал (всего один образец для каждого класса). Тем не менее, я полагаю, что хорошая точность проверки дает некоторое представление о том, какой уровень работает лучше всего.
  • Как и ожидалось, объем данных, используемых для обучения, очень важен для производительности. Увеличение количества сэмплов увеличивает производительность, за некоторыми исключениями, на нескольких уровнях.

Сравнение различных глубоких сверточных моделей

Я также сравнил производительность для ряда различных архитектур: ResNet50 [2], MobileNet [3] и MobileNet V2 [4].

Остаточные нейронные сети (ResNets)
В 2015 году команда Microsoft представила Deep Residual Learning как новый способ борьбы с исчезающими градиентами - проблемой, которая мешала очень глубоким сетям работать эффективно. Используя пропустить соединения, можно повторно использовать активации из предыдущих уровней и обеспечить базовую производительность до тех пор, пока не улучшатся дополнительные уровни. Это позволило увеличить количество слоев без ущерба для производительности [2].
В этом эксперименте использовалась модель ResNet50, которая имеет 50 сверточных слоев.

Архитектуры MobileNet
Архитектуры MobileNet, разработанные Google, оптимизированы для очень эффективной работы на мобильных телефонах. Основная идея состоит в том, чтобы использовать другой тип свертки, называемый Глубоко разделимая свертка. Он дает примерно те же результаты, что и обычная сверточная операция, но работает намного быстрее [3].
В MobileNetV2 исходная архитектура MobileNet была улучшена за счет применения (варианта) остаточного обучения и ряда других нововведений. [4].

Результаты проверки для разных сетей
На приведенной ниже диаграмме результаты для каждой модели показаны для набора данных из 8100 изображений.

Что мне показалось интересным:

  • Для архитектуры ResNet50 падение точности на уровне 23 является интересной аномалией. Я не могу объяснить, чем это вызвано, но, что интересно, это происходит в начале этапа 4. На каждом этапе количество фильтров увеличивается вдвое.
  • Обе модели MobileNet кажутся более стабильными, поскольку они демонстрируют меньшую вариативность для последующих уровней. Модель MobileNet неуклонно растет, показывая пиковую производительность (92,6%) на уровне 10. Производительность постепенно снижается при переходе на более высокие уровни.
  • Наилучшим уровнем производительности для MobileNet V2 является уровень 32, который имеет 100% оценку проверки. Производительность ниже для уровней выше в сети.

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

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

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

3. Поиск комбинаций SET

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

Помните, что для того, чтобы иметь SET, три карты должны иметь либо одинаковые, либо разные значения для каждого атрибута. Простое решение - рассмотреть все возможные триплеты и проверить, применяется ли к триплету правило SET. С 12 картами существует 12 из 3 = 220 возможных троек, и для их проверки не потребуется столько вычислений.

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

«Уловка SET»

Я обнаружил, что есть интересный способ определить, является ли триплет SET или нет. Рассмотрим следующие две тройки:

Когда вы посмотрите на эти примеры действительных и недействительных SET, вы обнаружите, что:

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

Это правило справедливо для всех возможных комбинаций и делает наш алгоритм поиска SET довольно элегантным.

Конечные поля

Интересно, что этот трюк не работает для произвольных числовых представлений, но пока мы выбираем числовые значения, которые отличаются по модулю 3, он работает.

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

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

Вы можете думать о карте SET как о точке в 4-мерном пространстве, где каждая функция представляет собой другое измерение (цвет, форма, заливка и количество). Например, карточка со значениями признаков зеленый, квадрат, пунктир, два может быть представлена ​​как 4D-точка [1, 0, 2, 1]. Поскольку каждая функция может принимать только одно три значения, пространство, в котором мы можем определить карточки SET, является конечным полем размера 3. [1]

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

Таким образом, поиск SET - это поиск коллинеарных точек в 4-мерном конечном пространстве! [1]

Собираем все вместе

Это удовлетворительное (а иногда и предательское) чувство, когда все складывается вместе и вы действительно видите, как ваша модель делает то, на что вы надеялись.

Наконец, объединив извлечение карт, классификацию типов карт и алгоритм обнаружения SET мы можем найти комбинации SET из изображения!

использованная литература