В этом примере показано, как накормить изображением сверточную нейронную сеть и отобразить активации различных слоев сети. Исследуйте активации и узнайте, какие функции сеть изучает путем сравнения областей активации с оригинальным изображением. Узнайте, что каналы в более ранних слоях изучают простые функции как цвет и ребра, в то время как каналы в более глубоких слоях изучают комплексные функции как глаза. Идентификация функций таким образом может помочь вам изучить то, что изучила сеть.
Пример требует Deep Learning Toolbox™ и Image Processing Toolbox™.
Загрузите предварительно обученную сеть SqueezeNet.
net = squeezenet;
Считайте и покажите изображение. Сохраните его размер для будущего использования.
im = imread('face.jpg');
imshow(im)
imgSize = size(im); imgSize = imgSize(1:2);
Анализируйте сеть, чтобы видеть, на какие слои можно посмотреть. Сверточные слои выполняют свертки с настраиваемыми параметрами. Сеть учится идентифицировать полезные функции, часто с одной функцией на канал. Заметьте, что первый сверточный слой имеет 64 канала.
analyzeNetwork(net)
Слой Image Input задает входной размер. Можно изменить размер изображения прежде, чем передать его через сеть, но сеть также может обработать увеличенные изображения. Если вы питаете сетевые увеличенные изображения, активации также становятся больше. Однако, поскольку сеть обучена на изображениях размера 227 227, это не обучено распознать объекты или функции, больше, чем тот размер.
Исследуйте функции путем наблюдения, какие области в сверточных слоях активируются на изображении и сравнении с соответствующими областями в оригинальных изображениях. Каждый слой сверточной нейронной сети состоит из названных каналов многих 2D массивов. Передайте изображение через сеть и исследуйте выходные активации conv1
слой.
act1 = activations(net,im,'conv1');
Активации возвращены как трехмерный массив с третьей размерностью, индексирующей канал на conv1
слой. Показать эти активации с помощью imtile
функционируйте, измените размерность массива к 4-D. Третья размерность во входе к imtile
представляет цвет изображения. Установите третью размерность иметь размер 1, потому что активации не имеют цвета. Четвертая размерность индексирует канал.
sz = size(act1); act1 = reshape(act1,[sz(1) sz(2) 1 sz(3)]);
Теперь можно показать активации. Каждая активация может принять любое значение, поэтому нормировать выход с помощью mat2gray
. Все активации масштабируются так, чтобы минимальная активация была 0, и максимум равняется 1. Отобразите 64 изображения на 8 8 сетка, один для каждого канала в слое.
I = imtile(mat2gray(act1),'GridSize',[8 8]);
imshow(I)
Каждой мозаикой в сетке активаций является выход канала в conv1
слой. Белые пиксели представляют сильные положительные активации, и черные пиксели представляют сильные отрицательные активации. Канал, который является в основном серым, не активируется как строго на входном изображении. Положение пикселя в активации канала соответствует тому же положению в оригинальном изображении. Белый пиксель в некотором местоположении в канале указывает, что канал строго активируется в том положении.
Измените размер активаций в канале 22, чтобы иметь тот же размер как оригинальное изображение и отобразить активации.
act1ch22 = act1(:,:,:,22); act1ch22 = mat2gray(act1ch22); act1ch22 = imresize(act1ch22,imgSize); I = imtile({im,act1ch22}); imshow(I)
Вы видите, что этот канал активируется на красных пикселях, потому что более белые пиксели в канале соответствуют красным областям в оригинальном изображении.
Также можно попытаться найти интересные каналы, программно исследовав каналы с большими активациями. Найдите канал с самой большой активацией с помощью max
функционируйте, измените размер и покажите активации.
[maxValue,maxValueIndex] = max(max(max(act1))); act1chMax = act1(:,:,:,maxValueIndex); act1chMax = mat2gray(act1chMax); act1chMax = imresize(act1chMax,imgSize); I = imtile({im,act1chMax}); imshow(I)
Сравните с оригинальным изображением и заметьте, что этот канал активируется на ребрах. Это активируется положительно на легких левых/темных правых краях, и негативно на темных левых/легких правых краях.
Большинство сверточных нейронных сетей учится обнаруживать функции как цвет и ребра в их первом сверточном слое. В более глубоких сверточных слоях сеть учится обнаруживать более сложные функции. Более поздние слои создают свои функции путем сочетания функций более ранних слоев. Исследуйте fire6-squeeze1x1
слой таким же образом как conv1
слой. Вычислите, измените и покажите активации в сетке.
act6 = activations(net,im,'fire6-squeeze1x1'); sz = size(act6); act6 = reshape(act6,[sz(1) sz(2) 1 sz(3)]); I = imtile(imresize(mat2gray(act6),[64 64]),'GridSize',[6 8]); imshow(I)
Существует слишком много изображений, чтобы заняться расследованиями подробно, таким образом фокусируйтесь на некоторых из более интересных единиц. Отобразите самую сильную активацию в fire6-squeeze1x1
слой.
[maxValue6,maxValueIndex6] = max(max(max(act6))); act6chMax = act6(:,:,:,maxValueIndex6); imshow(imresize(mat2gray(act6chMax),imgSize))
В этом случае максимальный канал активации не так интересен для подробных функций как некоторые другие и показывает сильную отрицательную (темную), а также положительную (легкую) активацию. Этот канал возможно фокусируется на поверхностях.
В сетке всех каналов существуют каналы, которые могут активироваться на глазах. Исследуйте каналы 14 и 47 далее.
I = imtile(imresize(mat2gray(act6(:,:,:,[14 47])),imgSize)); imshow(I)
Многие каналы содержат области активации, которые являются и легкими и темными. Это положительные и отрицательные активации, соответственно. Однако только положительные активации используются из-за исправленного линейного модуля (ReLU), который следует за fire6-squeeze1x1
слой. Чтобы исследовать только положительные активации, повторите анализ, чтобы визуализировать активации fire6-relu_squeeze1x1
слой.
act6relu = activations(net,im,'fire6-relu_squeeze1x1');
sz = size(act6relu);
act6relu = reshape(act6relu,[sz(1) sz(2) 1 sz(3)]);
I = imtile(imresize(mat2gray(act6relu(:,:,:,[14 47])),imgSize));
imshow(I)
По сравнению с активациями fire6-squeeze1x1
слой, активации fire6-relu_squeeze1x1
слой ясно точно определяет области изображения, которые имеют сильные черты лица.
Проверяйте ли каналы 14 и 47 из fire6-relu_squeeze1x1
слой активируется на глазах. Введите новое изображение одним закрытым глазом на сеть и сравните получившиеся активации с активациями оригинального изображения.
Считайте и покажите изображение одним закрытым глазом и вычислите активации fire6-relu_squeeze1x1
слой.
imClosed = imread('face-eye-closed.jpg');
imshow(imClosed)
act6Closed = activations(net,imClosed,'fire6-relu_squeeze1x1');
sz = size(act6Closed);
act6Closed = reshape(act6Closed,[sz(1),sz(2),1,sz(3)]);
Постройте изображения и активации на одном рисунке.
channelsClosed = repmat(imresize(mat2gray(act6Closed(:,:,:,[14 47])),imgSize),[1 1 3]);
channelsOpen = repmat(imresize(mat2gray(act6relu(:,:,:,[14 47])),imgSize),[1 1 3]);
I = imtile(cat(4,im,channelsOpen*255,imClosed,channelsClosed*255));
imshow(I)
title('Input Image, Channel 14, Channel 47');
Вы видите от активаций, что оба канала 14 и 47 активируются на отдельных глазах, и до некоторой степени также на области вокруг рта.
Сети никогда не говорили узнать о глазах, но она узнала, что глаза являются полезной функцией, чтобы различать классы изображений. Предыдущее машинное обучение приближается часто вручную к спроектированным функциям, характерным для проблемы, но эти глубокие сверточные сети могут изучить полезные функции себя. Например, обучение идентифицировать глаза могло помочь сети различать леопарда и коврик печати леопарда.
activations
| deepDreamImage
| squeezenet