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

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

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

Мы собираемся пройти обучение модели обнаружения объектов, детектора, с помощью TensorFlow Object Detection API и использовать эту модель для извлечения данных для нашей модели классификации. После этого мы обучим классификатор классифицировать породы кошек. Следующие шаги будут сосредоточены на том, как эта архитектура помогает нам в решении проблемы, представленной в первом предложении, - введении в наш классификатор другого класса (породы кошек).

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

Готовый? Пойдем!

1. Детектор - обнаружение объектов TensorFlow

Набор данных

Как уже упоминалось, предпочтительным набором данных является Набор данных о домашних животных Oxford-IIIT, который содержит набор данных о домашних животных 37 категорий с примерно 200 изображениями для каждого класса. Это большой объем данных для обучения наших моделей.

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

Модель обнаружения объектов

Для обнаружения объектов мы будем использовать TensorFlow Object Detection (TFOD). Модель обнаружения кошек основана на модели EfficientDet D2 от TensorFlow Detection Model Zoo.

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

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

Загляните в тетрадь для более подробного объяснения тренировочного процесса.

Наша модель обучена и готова, так что давайте протестируем картинку с множеством кошек!

Ой ... Это не похоже. Почему модель обнаружила только одну кошку, если на картинке их четыре?

Причина довольно проста - в нашем наборе данных была только одна аннотация на изображение, поэтому наша модель научилась делать то же самое - обнаруживать только одну кошку на изображение. Все остальное, даже если это кошка, имеет очень низкую степень достоверности; следовательно, он не попадет в наши выходные данные, поскольку мы устанавливаем наш порог достоверности на 50%.

Давайте посмотрим, как модель работает при обрезке изображения выше:

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

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

2. Классификатор - обучение передачи TensorFlow

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

Это также хорошее место, чтобы оценить, насколько хорошо работает детектор!

Breeds detecting network never seen before:
Breed: Russian Blue number of files:191 
Breed: British Shorthair number of files:185 
Breed: Maine Coon number of files:200 
Breed: Persian number of files:160 
Breed: Egyptian Mau number of files:180
Breed: Ragdoll number of files:183
Breeds used for training:
Breed: Abyssinian number of files:190 
Breed: Bengal number of files:176
Breed: Birman number of files:196 
Breed: Bombay number of files:176 
Breed: Sphynx number of files:197
Breed: Siamese number of files:199

Если предположить, что у каждой породы около 200 экземпляров, мы можем видеть, что наша запоминаемость значительно превышает 85–90% для каждого из классов. Имейте в виду, что детектор был обучен на небольшом подмножестве данных о выбранных породах, так как мы не могли использовать все изображения из-за отсутствия файлов аннотаций .xml. Несмотря на это, нет никакой значительной разницы в запоминаемости между породами, используемыми для дрессировки, и остальными. Это означает, что детектор работает очень хорошо и понимает, что вообще такое «кошка».

Имея эти вырезы - мы наконец можем обучить наш классификатор с помощью трансферного обучения. Таким образом, мы экономим много времени - обучение, проводимое в Google Colab с включенным графическим процессором, занимает менее 5 минут, чтобы достичь точности 85%! Такое короткое время обучения чрезвычайно важно, если мы хотим, чтобы наш классификатор регулярно пополнялся новыми данными и классами.

Трансферное обучение можно выполнить с помощью пары строк кода:

Прежде всего - загружаем модель Xception, которая представляет собой уже обученную модель распознавания изображений. Мы опускаем верхние уровни классификации модели, чтобы мы могли добавить уровни классификации, подходящие для нашего обнаружения. Мы замораживаем загруженную модель, чтобы на нее не повлияло обучение - она ​​уже обучена извлекать важные элементы из изображений, а выполнение этой задачи требует больше всего времени и усилий. С трансферным обучением нам больше не нужно этого делать; мы обучаем - в данном случае - 6 слоев вместо 132 слоев, из которых построена модель Xception.

Окончательная точность на обучающем наборе составила 82,19% и 85,02% на проверочном наборе. Обучение длилось 20 эпох - увеличение этого числа также могло повысить окончательную точность модели. Время на эпоху составляло 6 секунд + несколько секунд для фазы проверки.

3. Добавление нового класса - «неопределенный / неизвестный».

Немного теории

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

Вдобавок - что, если наш детектор выдаст вырезки чего-то, кроме кошки? Опять же - наш классификатор по-прежнему классифицирует его как одну из этих 6 пород.

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

В примере с кошкой детектор не выводит ничего, что мы могли бы отнести к этой группе «неопределенное / неизвестное», но мы можем смоделировать это, запустив детектор на разных изображениях кошек, взятых из Интернета.

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

Допустим, у вас есть фотография с 10 автомобилями; на переднем бампере каждого автомобиля есть логотип марки автомобиля. Ваша модель распознает 12 логотипов марок автомобилей, но только 8 из них являются логотипами автомобилей; оставшиеся 4 обнаружения - это странное отражение в лобовом стекле, размытая наклейка на заборе на заднем плане, круглое масляное пятно на тротуаре и буква на одной из табличек автомобиля.

Вспомните - если ваша модель обнаруживает 8 логотипов брендов из 10 логотипов на изображении, это означает, что ее запоминаемость составляет 80%.

Точность - сколько из обнаруженных нами логотипов автомобилей, в данном случае 8/12 или 75%. В этом примере точность - это также точность, поскольку мы классифицируем только одну метку.

Теперь мы могли бы снизить порог достоверности, чтобы также поймать эти два необнаруженных логотипа, но с этим точность упадет. Это связано с тем, что наряду с этими двумя новыми обнаружениями в вывод также будет включено некоторое количество неправильных, так что в итоге мы получим 20 вырезок - 10 логотипов марок автомобилей и 10 любых других. 100% отзыв, 50% точность.

Порог в 50% - это хорошая золотая середина, но вы можете увеличить или уменьшить его в зависимости от вашего сценария использования и производительности вашего детектора, а также производительности классификатора.

Добавление нового класса

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

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

Вернемся к кошкам!

После запуска детектора по изображениям кошек мы получаем 150 новых фигурок. 7 классов - 6 пород кошек, которые мы извлекли ранее, и один класс «неизвестный», содержащий изображения кошек, не принадлежащих ни к одному из этих 6 классов.

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

После 20 эпох точность на обучающем наборе составила 87,50% и 76,19% на проверочном наборе. Это немного ниже, чем в предыдущем обучении только с 6 классами. Тем не менее, неизвестный класс может содержать породы, уже определенные и используемые для обучения, что означает, что они сбивают модель с толку и снижают ее точность.

3. Итоговая тренировка по всем классам.

Итоговая подготовка - 12 классов + неизвестно

После 40 эпох - то есть на 20 эпох дольше, чем при предыдущем обучении - модель достигла точности 78,59% на обучающем наборе и 74,45% при проверке. набор.

Из любопытства - посмотрим, как выглядит тренировочный процесс без «неизвестного» класса:

Окончательная точность набора поездов составляет 86,25% и 79,74% для набора данных проверки. Выше, чем раньше! Неизвестный класс снижает точность модели, поскольку, как упоминалось ранее, он может содержать кошек, принадлежащих к породам, уже определенным в наборе данных. Кроме того, еще один класс означает больший набор данных, который требует больше времени на обучение и, возможно, даже изменения в архитектуре модели.

4. Основные выводы

Хорошо, теперь, когда мы прошли весь процесс и убедились, что он работает очень хорошо - давайте подведем итоги!

  1. Архитектура состоит из двух нейронных сетей - Детектора и Классификатора. Детектор - это нейронная сеть для обнаружения объектов. Этого мы тренируем, надеюсь, только один раз. Мы обучаем его распознавать только один класс, который включает в себя общие характеристики того, что мы хотим классифицировать - кошку, мобильное приложение, логотип марки автомобиля.
  2. Затем детектор используется для извлечения вырезок обнаруженных объектов. В зависимости от порога достоверности и качества модели количество ложных срабатываний может быть больше или меньше. Идея состоит в том, чтобы поймать все правильные классы и как можно меньше неправильных - высокая степень полноты, довольно хорошая точность.
  3. Имея все вырезы, пришло время немного поработать вручную - теперь каждый извлеченный вырез должен быть помещен в соответствующую папку. Это папки для каждого класса, которые должны быть распознаны классификатором, и одна папка для хранения всего, что не принадлежащий к любому из этих классов.
  4. Затем на основе этих данных обучается классификатор. Стоит строить архитектуру с использованием трансферного обучения. Это сокращает необходимое время обучения, делая непрерывное обучение или добавление нового класса относительно плавным и быстрым процессом.
  5. Чтобы ввести новый класс, процесс необходимо повторить для новых данных - извлечение вырезок, ручная категоризация в соответствующие классы, а затем повторное обучение классификатора для распознавания n + m классов, где n - предыдущее количество классов, а m - количество вновь введенных классов.
  6. Наконец, наш процесс обнаружения выглядит так: изображение поступает на детектор, который выводит вырезы. Затем вырезы подаются в классификатор для получения окончательной классификации каждого выреза и, таким образом, всех обнаруженных объектов на анализируемом изображении.

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

Tschüss!