В этом примере показано, как передать изображение в сверточную нейронную сеть и отобразить активации различных слоев сети. Исследуйте активации и обнаружите, какие функции учит сеть, сравнивая области активации с оригинальным изображением. Узнайте, что каналы в более ранних слоях учатся простым функциям, таким как цвет и ребра, в то время как каналы в более глубоких слоях учатся сложным функциям, таким как глаза. Идентификация функций таким образом может помочь вам понять, чему научилась сеть.
Для примера требуются 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)
Слой Вход задает размер входа. Вы можете изменить размер изображения перед его передачей через сеть, но сеть также может обрабатывать большие изображения. Если вы передаете сети большие изображения, активации также становятся больше. Однако, поскольку сеть обучается на изображениях размера 227 227, она не обучается распознавать объекты или функции, большие, чем этот размер.
Исследуйте функции, наблюдая, какие области в сверточных слоях активируются на изображении и сравнивая с соответствующими областями в оригинальных изображениях. Каждый слой сверточной нейронной сети состоит из многих 2-D массивов, называемых каналами. Передайте изображение через сеть и исследуйте выходные активации conv1
слой.
act1 = activations(net,im,'conv1');
Активации возвращаются как трехмерный массив с третьей размерностью, индексирующим канал на conv1
слой. Чтобы показать эти активации с помощью imtile
function, измените форму массива на 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