В этом примере показано, как исследовать сетевые предсказания с помощью методов визуализации глубокого обучения.
Нейронные сети для глубокого обучения часто описываются как "черные квадраты", потому что то, почему сеть принимает определенное решение, не всегда очевидно. Можно использовать interpretability метод, чтобы перевести сетевое поведение в выход, который может интерпретировать человек. Этот поддающийся толкованию выход может затем ответить на вопросы о предсказаниях сети. Этот пример фокусируется на методах визуализации, которые являются interpretability методами, которые объясняют сетевые предсказания с помощью визуальных представлений того, на что “смотрит” сеть.
Загрузите предварительно обученную сеть классификации изображений. В данном примере используйте GoogLeNet, предварительно обученная сеть, которая может классифицировать изображения в 1 000 категорий объектов, таких как клавиатура, мышь, карандаш и многие животные.
net = googlenet;
Найдите входной размер сети и меток класса.
inputSize = net.Layers(1).InputSize(1:2); classes = net.Layers(end).Classes;
Загрузите тестовое изображение, содержащее изображение золотистого ретривера.
img = imread("sherlock.jpg");
img = imresize(img,inputSize);
figure
imshow(img)
Классифицируйте изображение с помощью предварительно обученной сети.
[YPred,scores] = classify(net,img); YPred
YPred = categorical
golden retriever
Сеть правильно классифицирует изображение как золотистого ретривера. Найдите эти три класса с самыми высокими баллами.
[~,topIdx] = maxk(scores,3); topScores = scores(topIdx)'; topClasses = classes(topIdx); table(topClasses,topScores)
ans=3×2 table
topClasses topScores
__________________ _________
golden retriever 0.55419
Labrador retriever 0.39633
kuvasz 0.02544
Классы с лучшими тремя баллами являются всеми породами собак. Более высокая музыка сетевых выходных параметров к классам, которые совместно используют подобные функции с истинным классом золотистого ретривера.
Можно использовать методы визуализации, чтобы изучить, почему сеть классифицирует это изображение как золотистого ретривера.
Один из самых простых способов изучить сетевое поведение состоит в том, чтобы визуализировать активации каждого слоя. Большинство сверточных нейронных сетей учится обнаруживать функции, такие как цвет и ребра в их первом сверточном слое. В более глубоких сверточных слоях сеть учится обнаруживать более сложные функции, такие как глаза. Передайте изображение через сеть и исследуйте выходные активации conv2-relu_3x3_reduce
слой.
act = activations(net,img,"conv2-relu_3x3_reduce");
sz = size(act);
act = reshape(act,[sz(1) sz(2) 1 sz(3)]);
Отобразите активации для первых 12 каналов слоя.
I = imtile(mat2gray(act(:,:,:,1:12))); figure imshow(I)
Белые пиксели представляют сильные положительные активации, и черные пиксели представляют сильные отрицательные активации. Вы видите, что сеть изучает низкоуровневые функции, такие как ребра и структура. Первый канал подсвечивает глаза и нос собаки, возможно из-за их отличительного ребра и цвета.
Исследуйте более глубокий слой.
actDeep = activations(net,img,"inception_5b-output");
sz = size(actDeep)
sz = 1×3
7 7 1024
actDeep = reshape(actDeep,[sz(1) sz(2) 1 sz(3)]);
Этот слой имеет 1 024 канала. Каждый канал имеет изображение. Исследование каждого изображения подробно непрактично. Вместо этого можно получить сведения о сетевом поведении путем рассмотрения канала с самой сильной активацией.
[maxValue,maxValueIndex] = max(max(max(actDeep)));
actDeepMax = actDeep(:,:,:,maxValueIndex);
tiledlayout("flow")
nexttile
imshow(img)
nexttile
imshow(imresize(mat2gray(actDeepMax),inputSize))
Самая сильная активация образовывает канал особое внимание на голове собаки, указывая, что этот слой выбирает более комплексные функции.
Чтобы далее исследовать сетевое поведение, можно использовать более комплексные методы визуализации.
Исследуйте сетевые предсказания с помощью взвешенного градиентом отображения активации класса (CAM градиента). Чтобы понять, какие части изображения являются самыми важными для классификации, CAM градиента использует градиент классификационной оценки относительно сверточных функций, определенных сетью. Места, где этот градиент является большим, являются точно местами, где итоговый счет зависит больше всего от данных. Вычислите карту CAM градиента с помощью gradCAM
функционируйте и предсказанный класс.
gradcamMap = gradCAM(net,img,YPred);
По умолчанию, gradCAM
функционируйте извлекает карты функции из последнего слоя ReLU с неодиночным элементом пространственные размерности или последний слой, который собирает выходные параметры слоев ReLU (такие как конкатенация глубины или слои сложения). Можно вычислить карту CAM градиента для более ранних слоев в сети путем определения слоя функции. Вычислите карту CAM градиента для раннего сверточного слоя conv2-relu_3x3
.
gradcamMapShallow = gradCAM(net,img,YPred,'FeatureLayer',"conv2-relu_3x3");
Используйте plotMaps
поддерживание функции, перечисленной в конце этого примера, чтобы сравнить карты CAM градиента.
figure alpha = 0.5; cmap = "jet"; plotMaps(img,gradcamMap,gradcamMapShallow,"Deep Layer","Shallow Layer",alpha,cmap)
Карта CAM градиента для слоя в конце сети подсвечивает голову и ухо собаки, предполагая, что форма уха и глаза важна для классификации этой собаки как золотистый ретривер. Карта CAM градиента, произведенная более ранним слоем, подсвечивает ребра собаки. Это вызвано тем, что более ранние слои в сети изучают простые функции, такие как цвет и ребра, в то время как глубокие слои узнают больше комплексные функции, такие как уши или глаза.
Вычислите чувствительность поглощения газов изображения. Чувствительность поглощения газов является простым методом для измерения сетевой чувствительности к небольшим возмущениям во входных данных. Этот метод тревожит небольшие районы входа, заменяя его на маску закрытия, обычно серый квадрат. Маска преодолевает изображение, и изменение в счете вероятности к данному классу измеряется. Можно использовать этот метод, чтобы подсветить, какие части изображения являются самыми важными для классификации. Можно выполнить чувствительность поглощения газов с помощью occlusionSensitivity
.
Вычислите карту чувствительности поглощения газов для класса золотистого ретривера.
occlusionMap = occlusionSensitivity(net,img,YPred);
Чтобы исследовать результаты поглощения газов с более высоким разрешением, уменьшайте размер маски и шаг с помощью MaskSize
и Stride
опции. Меньший Stride
значение дает к более высокой карте разрешения, но может занять больше времени, чтобы вычислить и использовать больше памяти. Меньший MaskSize
значение дает к большему количеству детали, но может привести к более шумным результатам. Чтобы получить лучшие результаты чувствительности поглощения газов, необходимо тщательно выбрать правильные значения для MaskSize
и Stride
опции.
occlusionMapDetail = occlusionSensitivity(net,img,YPred,'Stride',10,'MaskSize',15);
Используйте plotMaps
функция, чтобы сравнить различные результаты чувствительности поглощения газов.
plotMaps(img,occlusionMap,occlusionMapDetail, ... "Occlusion Sensitivity","Occlusion Sensitivity \newline (High Resolution)",alpha,cmap)
Более низкая карта разрешения показывает подобные результаты CAM градиента, подсвечивая ухо и глаз собаки. Более высокая карта разрешения показывает, что ухо является самым важным для классификации. Более высокая карта разрешения также указывает, что мех на спине у собаки способствует решению классификации.
Затем рассмотрите метод локально поддающихся толкованию объяснений модели агностических (LIME). LIME аппроксимирует поведение классификации глубокой нейронной сети с помощью более простого, большего количества поддающейся толкованию модели, такой как дерево регрессии. Интерпретация решений об этой более простой модели обеспечивает понимание решений о нейронной сети. Простая модель используется, чтобы определить важность функций входных данных как прокси для важности функций к глубокой нейронной сети. Метод LIME использует совсем другой базовый механизм для чувствительности поглощения газов или CAM градиента.
Используйте imageLIME
функционируйте, чтобы просмотреть самые важные функции в решении классификации о глубокой сети. Вычислите карту LIME для лучших двух классов: золотистый ретривер и Лабрадор.
limeMapClass1 = imageLIME(net,img,topClasses(1)); limeMapClass2 = imageLIME(net,img,topClasses(2)); titleClass1 = "LIME (" + string(topClasses(1)) + ")"; titleClass2 = "LIME (" + string(topClasses(2)) + ")"; plotMaps(img,limeMapClass1,limeMapClass2,titleClass1,titleClass2,alpha,cmap)
Карты показывают, какие области изображения важны для классификации. Красные области карты имеют более высокую важность — изображение, испытывающее недостаток в этих областях, имело бы более низкий счет к заданному классу. Для класса золотистого ретривера сеть фокусируется на голове собаки и ухе, чтобы сделать его предсказание. Для класса Лабрадора сеть более фокусируется на носу и глазах собаки, а не ухе. В то время как обе карты подсвечивают, что лоб собаки, для сети, ухо собаки и шея указывают на класс золотистого ретривера, в то время как глаза собаки указывают на класс Лабрадора.
Карты LIME сопоставимы с чувствительностью поглощения газов и картами CAM градиента. Сравнение результатов различных interpretability методов важно для проверки заключений, которые вы делаете.
Методы приписывания градиента производят карты пиксельного разрешения, показывающие, какие пиксели являются самыми важными для сетевого решения классификации. Эти методы вычисляют градиент счета класса относительно входных пикселей. Интуитивно, карта показывает, какие пиксели больше всего влияют на счет класса, когда изменено. Методы приписывания градиента производят карты с более высоким разрешением, чем те от CAM градиента или чувствительности поглощения газов, но которые имеют тенденцию быть намного более шумными, когда хорошо обученная глубокая сеть не строго зависит от точного значения определенных пикселей.
Используйте gradientAttribution
поддерживание функции, перечисленной в конце этого примера, чтобы вычислить карту приписывания градиента для класса золотистого ретривера.
softmaxName = 'prob'; pixelMap = gradientAttribution(net,img,YPred,softmaxName,"autodiff");
Можно получить более резкую карту приписывания градиента путем изменения, назад проходят через слои ReLU так, чтобы элементы градиента, которые меньше нуля и элементов входа к слою ReLU, которые меньше нуля, были оба обнулены. Этот метод известен как ведомую обратную связь. Вычислите карту приписывания градиента для сети с помощью ведомой обратной связи.
pixelGuidedBackpropMap = gradientAttribution(net,img,YPred,softmaxName,"guided-backprop");
Отобразите карты приписывания градиента с помощью пользовательской палитры с 255 цветами, которая сопоставляет значения 0
белому и 1
к черному цвету. Более темные пиксели - самые важные для классификации.
alpha = 1; cmap = [linspace(1,0,255)' linspace(1,0,255)' linspace(1,0,255)']; plotMaps(img,pixelMap,pixelGuidedBackpropMap, ... "Gradient Attribution","Guided Backpropagation",alpha,cmap)
Самые темные части карты - сосредоточенные вокруг собаки. Карта является очень шумной, но она действительно предполагает, что сеть использует ожидаемую информацию в изображении, чтобы выполнить классификацию. Пиксели у собаки оказывают намного больше влияния на классификационную оценку, чем пиксели фона. В ведомой карте обратной связи пиксели фокусируются на поверхности собаки, в частности глаза и нос. Интересно, этот метод подсвечивает различные области, чем более низкие методы визуализации разрешения. Результат предполагает, что на пиксельном уровне нос и глаза собаки важны для классификации изображения как золотистый ретривер.
Глубокая мечта является методом визуализации функции, который создает изображения, которые строго активируют слоя сети. Путем визуализации этих изображений можно подсветить функции изображений, изученные сетью. Эти изображения полезны для понимания и диагностирования сетевого поведения. Можно сгенерировать изображения путем визуализации функций слоев к концу сети. В отличие от предыдущих методов, этот метод является глобальной переменной и показывает вам полное поведение сети, не только для определенного входного изображения.
Чтобы произвести изображения, которые напоминают данный класс наиболее тесно, используйте итоговый полносвязный слой loss3-classifier
. Сгенерируйте глубокие изображения мечты для лучших трех классов, которые сеть предсказывает для тестового изображения. Установите 'Verbose'
к false
подавить подробную информацию о процессе оптимизации.
channels = topIdx; learnableLayer = "loss3-classifier"; dreamImage = deepDreamImage(net,learnableLayer,channels,'Verbose',false);
Увеличение числа уровней пирамиды и итераций на уровень пирамиды может произвести более подробные изображения за счет дополнительного расчета. Сгенерируйте подробный, глубоко мечтают изображения.
dreamImageDetailed = deepDreamImage(net,learnableLayer,channels, ... 'Verbose',false,'NumIterations',100,'PyramidLevels',4);
Сравните глубокие изображения мечты лучших трех классов.
tiledlayout(2,3) for i = 1:3 nexttile imshow(dreamImage(:,:,:,i)); title(string(topClasses(i))); end for i = 1:3 nexttile imshow(dreamImageDetailed(:,:,:,i)); title(string(topClasses(i)) + "\newline (High Resolution)"); end
Глубокие изображения мечты показывают, как сеть предполагает каждый из этих трех классов. Несмотря на то, что эти изображения довольно абстрактны, вы видите ключевые возможности для каждого из высших классов. Это также показывает, как сеть отличает золотые классы и классы Лабрадора.
replaceLayersOfType
функционируйте заменяет все слои заданного класса с экземплярами нового слоя. Новые слои имеют те же имена как исходные слои.
function lgraph = replaceLayersOfType(lgraph,layerType,newLayer) % Replace layers in the layerGraph lgraph of the type specified by % layerType with copies of the layer newLayer. for i=1:length(lgraph.Layers) if isa(lgraph.Layers(i),layerType) % Match names between the old and new layers. layerName = lgraph.Layers(i).Name; newLayer.Name = layerName; lgraph = replaceLayer(lgraph,layerName,newLayer); end end end
Постройте две карты, map1
и map2
, поскольку вход отображает img
. Используйте alpha
установить прозрачность карты. Задайте который палитра использовать использование cmap
.
function plotMaps(img,map1,map2,title1,title2,alpha,cmap) figure subplot(1,3,1) imshow(img) subplot(1,3,2) imshow(img) hold on imagesc(map1,'AlphaData',alpha) colormap(cmap) title(title1) hold off subplot(1,3,3) imshow(img) hold on imagesc(map2,'AlphaData',alpha) colormap(cmap) title(title2) hold off end
Вычислите карту приписывания градиента. Необходимо задать softmax слой. Можно вычислить основную карту или более высокую карту разрешения с помощью ведомой обратной связи.
function map = gradientAttribution(net,img,YPred,softmaxName,method) lgraph = layerGraph(net); lgraph = removeLayers(lgraph,lgraph.Layers(end).Name); dlnet = dlnetwork(lgraph); % To use automatic differentiation, convert the image to a dlarray. dlImg = dlarray(single(img),"SSC"); if method == "autodiff" % Use dlfeval and the gradientMap function to compute the derivative. The gradientMap % function passes the image forward through the network to obtain the class scores % and contains a call to dlgradient to evaluate the gradients of the scores with respect % to the image. dydI = dlfeval(@gradientMap,dlnet,dlImg,softmaxName,YPred); end if method == "guided-backprop" % Use the custom layer CustomBackpropReluLayer (attached as a supporting file) % with a nonstandard backward pass, and use it with automatic differentiation. customRelu = CustomBackpropReluLayer(); % Set the BackpropMode property of each CustomBackpropReluLayer to "guided-backprop". customRelu.BackpropMode = "guided-backprop"; % Use the supporting function replaceLayersofType to replace all instances of reluLayer in the network with % instances of CustomBackpropReluLayer. lgraphGB = replaceLayersOfType(lgraph, ... 'nnet.cnn.layer.ReLULayer',customRelu); % Convert the layer graph containing the CustomBackpropReluLayers into a dlnetwork. dlnetGB = dlnetwork(lgraphGB); dydI = dlfeval(@gradientMap,dlnetGB,dlImg,softmaxName,YPred); end % Sum the absolute values of each pixel along the channel dimension, then rescale % between 0 and 1. map = sum(abs(extractdata(dydI)),3); map = rescale(map); end
Вычислите градиент счета класса относительно одного или нескольких входных изображений.
function dydI = gradientMap(dlnet,dlImgs,softmaxName,classIdx) dydI = dlarray(zeros(size(dlImgs))); for i=1:size(dlImgs,4) I = dlImgs(:,:,:,i); scores = predict(dlnet,I,'Outputs',{softmaxName}); classScore = scores(classIdx); dydI(:,:,:,i) = dlgradient(classScore,I); end end
[1] Чжоу, Bolei, Aditya Khosla, Агата Лапедриса, Од Олива и Антонио Торрэлба. "Изучая Глубокие Функции Отличительной Локализации". В 2 016 Продолжениях Конференции по IEEE по Компьютерному зрению и Распознаванию образов: 2921–29. Лас-Вегас, NV, США: IEEE, 2016. https://doi.org/10.1109/CVPR.2016.319.
[2] Selvaraju, Рэмпрасаэт Р., Майкл Когсвелл, Десять кубометров Abhishek, Рамакришна Ведэнтэм, Devi Parikh и Dhruv Batra. “CAM градиента: Визуальные Объяснения от Глубоких Сетей через Основанную на градиенте Локализацию”. В 2 017 Продолжениях Конференции по IEEE по Компьютерному зрению: 618–626. Венеция, Италия: IEEE, 2017. https://doi.org/10.1109/ICCV.2017.74.
[3] Рибейру, Марко Тулио, Сэмир Сингх и Карлос Гуестрин. “‘Почему я должен Доверять Вам?’: Объяснение Предсказаний Любого Классификатора”. В Продолжениях 22-й Международной конференции ACM SIGKDD по вопросам Открытия Знаний и Анализа данных (2016): 1135–1144. Нью-Йорк, Нью-Йорк: Ассоциация вычислительной техники, 2016. https://doi.org/10.1145/2939672.2939778.
[4] Симонян, Карен, Андреа Ведальди и Эндрю Зиссермен. “Глубоко В Сверточных Сетях: Визуализация Моделей Классификации Изображений и Карт Выступа”. Предварительно распечатайте, представленный 19 апреля 2014. https://arxiv.org/abs/1312.6034.
[5] TensorFlow. "DeepDreaming с TensorFlow". https://github.com/tensorflow/docs/blob/master/site/en/tutorials/generative/deepdream.ipynb.
gradCAM
| imageLIME
| occlusionSensitivity
| deepDreamImage
| tsne
(Statistics and Machine Learning Toolbox)