Системный, основанный на данных подход к пониманию того, что мешает работе модели

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

  • Ограничивающим фактором обычно является отсутствие данных. Люди часто тратят много времени на обдумывание дизайнерских решений, таких как выбор архитектуры модели и настройка гиперпараметров. Однако мы снова и снова обнаруживаем, что при решении проблем в реальном мире самый простой способ повысить производительность — это использовать подход, основанный на данных, для выявления областей, в которых модель испытывает трудности, и сбора дополнительных данных для повышения производительности там.
  • Ярлыки наборов данных часто несовместимы. Чрезвычайно сложно создать (или найти) высококачественные наборы данных для обнаружения объектов. Рассмотрим рис. 1 выше: если вы покажете это изображение двум разным людям и попросите их пометить присутствующие объекты (т. е. добавить коробки и метки), результат наверняка будет другим. Вероятно, будут некоторые различия в расположении и размере ограничивающих рамок, и, в зависимости от сложности изображения и варианта использования, аннотаторы могут вводить разные рамки. Кроме того, этот процесс маркировки утомителен, что еще больше упрощает внесение ошибок или несоответствий во время длительных сеансов.
  • Стандартные показатели трудно интерпретировать. Средняя средняя точность (mAP) — основной показатель, используемый для оценки производительности детектора объектов — не интуитивно понятен и может затруднить понимание того, как именно работает модель, в отличие от точности, прецизионности или вспомнить для задач классификации. Как таковой, это бесполезно для обнаружения областей, где модель работает плохо, и уж тем более для помощи в разработке стратегий по улучшению ситуации.

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

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

Хотя в документе предлагается реализация на GitHub, я обнаружил, что у нее есть два основных недостатка:

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

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

ВАЖНО: Весь код, предоставленный в связи с этой статьей, предлагается под лицензией Apache 2.0.

Что такое анализ ошибок?

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

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

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

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

Данные

Первое, что нам нужно, это данные для использования в качестве примера. Для этого мы идем к валидационному набору MS COCO 2017, одному из самых популярных эталонных наборов данных для обнаружения объектов. Мы сначала скачиваем его в нашу рабочую папку, а затем загружаем и форматируем в удобные панды DataFrames.

# Download images and annotations
!curl http://images.cocodataset.org/zips/val2017.zip --output coco_valid.zip
!curl http://images.cocodataset.org/annotations/annotations_trainval2017.zip --output coco_valid_anns.zip
# Unzip images into coco_val2017/images
!mkdir coco_val2017/
!unzip -q coco_valid.zip -d coco_val2017/
!mv -f coco_val2017/val2017 coco_val2017/images
# Unzip and keep only valid annotations as coco_val2017/annotations.json
!unzip -q coco_valid_anns.zip -d coco_val2017
!mv -f coco_val2017/annotations/instances_val2017.json coco_val2017/annotations.json
!rm -rf coco_val2017/annotations
# Remove zip files downloaded
!rm -f coco_valid.zip
!rm -f coco_valid_anns.zip
images_df, targets_df = load_dataset()

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

Модель

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

Хотя существует множество архитектур, мы будем использовать Faster-RCNN с магистралью ResNet50. Основные причины этого выбора заключаются в том, что эта архитектура имеет тенденцию работать достаточно хорошо и что существует легкодоступная реализация PyTorch.

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

Реализация Faster-RCNN в PyTorch имеет несколько особенностей, которые делают невозможным одновременное получение потерь и прогнозов. Хотя код предоставляется, детали выходят за рамки. Способ получения убытков и прогнозов зависит от используемой модели.

ВАЖНО: выполнение следующего кода на ЦП может занять несколько часов (если оно вообще завершится); поэтому я рекомендую вам сделать это на компьютере с графическим процессором, что займет несколько минут.

preds_df = get_predictions(images_path, images_df, targets_df)

Проверка потерь

Прежде чем мы углубимся в анализ TIDE, есть еще один инструмент, который также может оказаться полезным для анализа ошибок: модель потерь. Потери призваны измерить, насколько хорошим или плохим является прогноз. Таким образом, самые высокие потери будут указывать на изображения, с которыми модель борется больше всего. Мы можем визуализировать их, чтобы попытаться понять, что происходит. На самом деле, этот подход не уникален для обнаружения объектов. Для этого можно использовать любую модель, которая выводит потери на выборку.

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

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

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

  • Далеко на картинке много птиц, вероятно, фламинго. Цели для них непоследовательны, поскольку крошечная часть из них помечена индивидуально, в то время как все они находятся внутри большой коробки. Модель не может найти ни одного из них. Фактически, несколько изображений с очень высокими потерями представляют аналогичную ситуацию: маленькие птицы далеко, которых модель не может найти.
  • Существует вид животного, у которого нет ограничивающей рамки. Это, вероятно, означает, что у COCO нет категории для него, и, следовательно, он не помечен. Тем не менее, наша модель идентифицирует его как животное и, не имея лучшей альтернативы, помечает его такими словами, как зебра, лошадь или корова.

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

Для изображения со средней потерей мы видим, что есть правильные прогнозы для большинства или всех целей. Проблема возникает с дополнительными ящиками, которых там быть не должно. Это относится не только к выбранному примеру, но и к большинству изображений с потерями в диапазоне от 0,5 до 1. С этим изображением одним из возможных подходов к повышению производительности может быть удаление лишних блоков путем исключения прогнозов с низкой оценкой, выполнения слияния блоков или применения немаксимального подавления.

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

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

Классификация ошибок

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

Как упоминалось выше, TIDE либо присваивает каждому выводимому прогнозу категорию ошибки, либо считает его правильным. Для этого ему нужен механизм, чтобы попытаться сопоставить каждый прогноз с целью (ограничивающей рамкой), которую он может пытаться предсказать. Способ, которым он пытается выполнить это сопоставление, — это Intersection over Union (IoU). На рисунке ниже показано, как получается IoU для любых двух ограничивающих прямоугольников.

Используя два порога IoU, порог переднего плана (Tf) и порог фона (Tb), мы можем определить следующие типы ошибок (с более подробным объяснением в разделе 2.2 документа TIDE):

  1. Ошибка классификации (CLS):IoU ›= Tf для цели неверного класса (т. е. правильно локализованной, но неправильно классифицированной).
  2. Ошибка локализации (LOC):Tb ‹= IoU ‹ Tf для цели правильного класса (т. е. правильно классифицирована, но неправильно локализована).
  3. Ошибка Cls и Loc (CLS и LOC):Tb ‹= IoU ‹ Tf для цели неверного класса (т. е. неправильно классифицирована и локализована).
  4. Ошибка обнаружения дубликатов (DUP):IoU ›= Tf для цели правильного класса, но другое обнаружение с более высокой оценкой уже соответствует цели (т. е. было бы правильным, если бы не обнаружение с более высокой оценкой).
  5. Ошибка фона (BKG):IoU ‹ Tb для всех целей (т. е. обнаруженный фон в качестве переднего плана).
  6. Ошибка пропущенной цели (MISS): все необнаруженные цели (ложноотрицательные результаты), еще не охваченные ошибкой классификации или локализации.

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

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

Давайте определим некоторые функции, которые помогут нам классифицировать эти типы ошибок на основе прогнозов и аннотаций в нашем DataFrame.

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

errors_df = classify_predictions_errors(targets_df, preds_df)

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

Влияние ошибки

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

Интуиция та же, что представлена ​​в статье TIDE: мы можем рассчитать метрику с предсказаниями нашей модели. Затем мы можем исправлять (т. е. исправлять) один тип ошибки за раз и пересчитывать метрику, чтобы увидеть, какой она была бы, если бы модель не совершала такого рода ошибки. Наконец, мы определяем влияние каждого вида ошибки как разницу между значением метрики после ее исправления и исходным значением. Это дает нам количественный результат того, насколько сильно наша интересующая метрика наказывается каждым типом ошибки.

Для этого нам нужно определить, что означает «исправление ошибки» для каждого типа. Еще раз, мы просто используем методологию, представленную в документе TIDE. Объяснения более подробные, чем в статье (которые они называют «оракулами», а не «исправлениями») с оговорками, которые можно найти только глубоко в их реализации.

  1. Исправление CLS: исправьте метку обнаружения на правильную. Коррекция применяется только к прогнозам, которые представляют ошибку CLS и являются прогнозами с наивысшей оценкой, соответствующими цели (IoU ›= Tb), и эта цель не имеет совпадающего прогноза OK. Все прогнозы CLS, не соответствующие указанным условиям, отбрасываются.
  2. Исправление LOC: исправьте ограничивающую рамку обнаружения, чтобы она совпадала с соответствующей целью. Коррекция применяется только к прогнозам, которые представляют ошибку LOC и являются прогнозами с наивысшей оценкой, соответствующими целевому значению (IoU ›= Tb), и целевое значение не соответствует прогнозу OK. Все прогнозы LOC, не соответствующие указанным условиям, отбрасываются.
  3. Исправление CLS и LOC: поскольку мы не можем быть полностью уверены в том, какую цель пытался найти детектор, мы просто отбрасываем прогноз.
  4. Исправление DUP: удаление обнаружения дубликатов.
  5. Исправление BKG: удаление обнаружения галлюцинаций.
  6. Исправление MISS: удалить пропущенную цель.

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

Теперь мы увидим пример того, как это выглядит на практике. В этом примере мы собираемся использовать метрику средней точности (mAP), так как это стандартная метрика для решения задач обнаружения объектов. Если вы не знакомы с mAP, рекомендую посмотреть это видео начиная с 37 минуты. Это одно из лучших объяснений метрики, что я видел.

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

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

Теперь давайте воспользуемся функцией calculate_error_impact, чтобы понять, как наши ошибки влияют на наш mAP.

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

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

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

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

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

Заключение

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

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

Примечания

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

Бернат Пуч Кэмпс зарегистрирован в LinkedIn.