Автор: Александр Лекомцев

Редактура: Александр Гончаренко, Ксения Рябинова

Думаю, вы не раз слышали о том, что нейросети для компьютерного зрения — черные ящики. На самом деле это не совсем так, и есть методы, позволяющие интерпретировать их ответы. Первые известные работы по данной теме начинаются с 2009 года (”Visualizing Higher-Layer Features of a Deep Network”, Dumitru Erhan et al.). Однако революция в интерпретации моделей компьютерного зрения произошла только через семь лет, и произвел её другой метод — Grad-CAM.

Рисунок 1. Пример работы Grad-CAM из статьи

Рисунок 1. Пример работы Grad-CAM из статьи

Class Activation Mapping

Для понимания Grad-CAM изучим его предшественника — Class Activation Mapping (CAM). CAM — это метод получения тепловых карт внимания из уже обученной сети. То есть, каждому пикселю изображения он сопоставляет число от нуля до единицы, которое отвечает на вопрос: “насколько сильно этот пиксель влияет на ответ нейросети?”.

Рисунок 2. Архитектура сети для CAM

Рисунок 2. Архитектура сети для CAM

Метод требует определенной структуры сети. Сначала идут несколько свёрточных слоёв. Это может быть любой стандартный бэкбон. Мы прогоняем картинку через несколько его слоёв, затем ещё одним слоем получаем тензор размера (высота изображения x ширина изображения x n, где n — гиперпараметр для определения количества карт активации, на основе которых мы строим карту внимания). Далее мы делаем global average pooling и получаем из n карт активации n чисел. Потом мы перевзвешиваем их линейным слоем: каждое полученное число умножаем на соответствующую компоненту в векторе весов $<w_1, …, w_n>$. Поскольку вектор $<w_1, …, w_n>$ зависит от класса C, давайте введём для него обозначение $\vec{w^c}$. Последним шагом применяем софтмакс и получаем вероятность каждого класса. Мы обучаем всю сеть вместе, включая вектора $\vec{w^c}$.

Для поиска максимально влияющих на результат пикселей нужно посмотреть на предпоследний слой. Для получения вероятности класса мы перемножаем результаты пуллинга на вектор $<w_1, …, w_n>$ , тогда его компоненты можно интерпретировать как “важность” результата конкретного пуллинга. Тут интуиция такая: в картах активации будут собираться определенные паттерны, которые позволяют разделить между собой классы. Тогда вектор $\vec{w^c}$ будет учиться отражать влияние паттернов на метку класса. При этом можно посмотреть и на саму карту активации — самые большие значения будут соответствовать тем участкам изображения, на которые сеть обращала внимание.

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

Grad-CAM

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

Рисунок 3. Архитектура сети для Grad-CAM

Рисунок 3. Архитектура сети для Grad-CAM

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

Но откуда взять веса $\vec{w^c}$? Авторы Grad-CAM предлагают посмотреть на величину градиента (отсюда и “grad” в названии метода). Пусть $y^c$ — выход модели для класса С (до применения софтмакса), $A^k$ — карта активации для k-го канала в тензоре. Тогда $\frac{\partial y^c}{\partial A_{ij}^k}$ — градиент выхода для класса C по отношению к элементу карты активации. Все эти градиенты мы усредняем по ширине и высоте и получаем вес на замену $\vec{w^c}$ (см. Рисунок 4).

Рисунок 4. Формула расчета весов на замену  $\vec{w^c}$

Рисунок 4. Формула расчета весов на замену $\vec{w^c}$

Для получения весов мы усредняем градиенты для каждой карты активации после сверточного слоя (формула на Рисунке 4). Авторы вводят для нас вектор $<{\alpha_1}^c, …, {\alpha_n}^c>$ только для доказательства того, что он соответствует вектору $\vec{w^c}$, а Grad-CAM является обобщением CAM. Обратите внимание: мы берем ответ для класса без применения софтмакса, чтобы не “примешивать” остальные классы в градиент, и строим для каждого независимую тепловую карту. Кроме того, пуллинг находится в отдельной ветке сети и не является частью основной архитектуры, на которую мы “навешиваем” Grad-CAM.

Рисунок 5. Приближение части, относящейся к Grad-CAM. Цветным пунктиром — поэлементное умножение вектора $\vec{w^c}$ на тензор $A$

Рисунок 5. Приближение части, относящейся к Grad-CAM. Цветным пунктиром — поэлементное умножение вектора $\vec{w^c}$ на тензор $A$