Мы хотим получить понятные человеку причины для определенного модельного решения. Для этого мы используем библиотеку SHAP для расчета значений Шепли. В одном предложении значения Шепли определяют предельный вклад функции в результат модели. Они учитывают фоновое распределение других признаков. Подробное объяснение вы можете найти здесь. В этой статье мы строим модель, в которой мы можем выборочно удалить часть ввода, т.е. скрыть участки пикселей на изображении. Эти патчи служат суррогатными функциями, для которых мы вычисляем и визуализируем значения Шепли.

Библиотеки XAI, такие как SHAP и LIME, поддерживают ряд стандартных моделей и входных данных. К ним относятся (глубокие) нейронные сети и ввод изображений. Обнаружение объектов отличается от моделей, поддерживаемых из коробки: ближайшим аналогом может быть классификация изображений. При классификации изображений ввод такой же, а используемые модели обычно представляют собой глубокие нейронные сети. Однако результат обнаружения объекта выходит за рамки одного значения для класса или диапазона вероятностей класса. При обнаружении объектов одно изображение может отображать несколько объектов разного размера. Современные модели обнаружения объектов также включают так называемый шаг немаксимального подавления (NMS). Это фильтрует выходные данные последнего слоя нейронной сети до окончательных прогнозов.

Шаг немаксимального подавления (NMS)

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

Вам не нужно тренировать этот шаг, и он недифференцируем. Это означает, что нет прямой связи между входом и конечным выходом через градиент нейронной сети. Это, а также проблема множественных выходов из модели не позволяет использовать такие инструменты, как DeepLift или DeepExplainer в библиотеке SHAP. Однако SHAP предоставляет инструмент, который мы можем использовать для общих моделей черного ящика, KernelExplainer. Проблема нашего объяснимого примера обнаружения объектов заключается в двух аспектах. Во-первых, нам нужно вписать задачу обнаружения объектов в схему KernelExplainer. А во-вторых, нам нужно соединить модель и фреймворк XAI на техническом уровне.

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

Модель и зависимости

В этой статье мы используем алгоритм обнаружения объектов YOLOv5. Он работает на PyTorch, который поддерживается Colab, и конкурирует за максимальную производительность. Кроме того, модели позволяют легко настраивать новые типы объектов.

Из доступных предварительно обученных моделей мы будем использовать YOLOv5s. Это самая маленькая модель, предварительно обученная на наборе данных COCO и его 80 классах.

PyTorch уже доступен в среде Colab, но нам нужно установить библиотеку SHAP, YOLOv5, и загрузить веса предварительно обученной модели. Из кода YOLOv5 нам нужны вспомогательные функции для NMS и для проверки перекрытия ограничивающих прямоугольников (пересечение над Union или IoU).

Цель: одно обнаружение на одном изображении

С помощью библиотеки OpenCV читаем одно изображение. Мы помещаем его в квадрат и меняем размер до 160×160 пикселей. Мы также можем использовать меньшие или большие входные размеры, но ширина/высота квадратов должны быть кратны 32, чтобы соответствовать входным данным предварительно обученной модели. Обнаружение объектов с помощью глубоких нейронных сетей и методов XAI требует значительных ресурсов и времени. Поэтому мы уменьшаем входные изображения, чтобы ускорить время обнаружения объекта. Однако, если вы заинтересованы в получении обнаружений и объяснений с более высоким разрешением в дальнейших вычислениях, не стесняйтесь попробовать разные размеры изображения здесь.

img = cv2.imread("/content/yolov5/inference/images/zidane.jpg", cv2.IMREAD_COLOR) 
img = cv2.resize(img, (new_size_x, new_size_y)) 
img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)

Теперь, чтобы соответствовать ожидаемому входу модели (цветовой формат RGB), мы должны изменить порядок размеров изображения (OpenCV читает изображения в цветовом формате BGR), привести изображение к тензору PyTorch и продолжить работу с моделью. Мы просто загружаем веса модели и готовы делать выводы на изображениях.

model = torch.load("../yolov5s.pt", map_location=device)['model'].float().eval()

Непосредственным выходом этой модели являются координаты — x и y центра идентифицированного объекта, а также ширина и высота. Мы также получаем вероятность объекта в этих координатах плюс вероятности для каждого из 80 классов. В этом векторе перечислены обнаружения для всех возможных точек привязки, большинство из которых будут иметь очень низкие оценки:

prediction = model(torch_image)
[[x, y, w, h, obj. score, class1 prob., class2 prob,…, class80 prob],
[x, y, w, h, obj. score,class1 prob., class2 prob, …, class80 prob],
…
]

Обнаруженные объекты

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

output = non_max_suppression(prediction[0], conf_thres=0.5, iou_thres=0.5)
[[ 17.09375, 58.56250,108.00000, 126.18750, 0.76416, 0.00000], [ 90.81250, 38.93750, 142.00000, 128.25000, 0.68848,0.00000] ]

Для каждого обнаружения мы получаем координаты, теперь уже в формате x1, y1, x2, y2. Мы также получаем произведение оценки объекта и класса с наивысшей оценкой, а также индекс наиболее вероятного класса (индекс класса COCO 0 соответствует категории объекта «человек»). Чтобы увидеть, насколько хорошо мы нашли человека справа, мы смотрим на объединенные оценки второго обнаружения: Модель набрала 68,6%.

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

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

Объяснимое обнаружение объектов — модель «все в одном»

Чтобы использовать эту модель с KernelExplainer SHAP, нам нужно вписать описанные выше шаги в одну модель PyTorch:

1. Приведение изображения к тензору PyTorch

2. Применение базовой модели

3. Применение NMS

4. Вычисление оценки интересующего нас обнаружения

Мы реализуем эти шаги как отдельные слои в PyTorch. Мы делаем шаг 1 с классом Numpy2TorchCaster. Шаг 2 — это модель, которую мы использовали выше. Мы делаем шаги 3 и 4 с классом OD2Score.

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

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

Мы можем связать эти слои последовательно с помощью PyTorch, как показано здесь:

scoring_model = torch.nn.Sequential(
  numpy2torch_converter,
  model,
  od2score_filter
)

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

‍Сетка суперпикселей

Теперь мы можем начать изменять входное изображение и посмотреть, как изменится выходное изображение. К сожалению, изображение имеет значения 160×160 = 25 600 пикселей — 76 800, если считать три цветовых канала отдельно. Расчет влияния каждого отдельного пикселя требует чрезмерных вычислительных ресурсов.

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

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

super_pixel_model = torch.nn.Sequential( 
super_pixler 
numpy2torch_converter, 
model, 
od2score_filter
)

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

Значения формы для суперпикселей

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

explainer = shap.KernelExplainer(super_pixel_model,background_super_pixel) shap_values = explainer.shap_values(image_super_pixel,nsamples=3000)

Мы сопоставляем суперпиксели обратно с составляющими пикселями (легко, поскольку они соответствуют сетке) и масштабируем значения от 0 до 1. В используемой нами цветовой карте красный цвет означает положительный вклад пикселя, синий — отрицательный вклад.

Обнаружение объяснимых объектов — результат

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

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

Дальнейшие комментарии

Здесь можно реализовать все виды усовершенствований.

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

Мы также можем определить более одного значения замены для каждого суперпикселя. Это дает лучшую характеристику того, как будет выглядеть «отсутствие» пикселя.

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

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

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

Обнаружение объяснимых объектов — Заключение

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

Первоначально опубликовано на https://www.steadforce.com.