В этом примере показано, как обучить сиамскую сеть, чтобы сравнить рукописные цифры с помощью сокращения размерности.
Сиамская сеть является типом нейронной сети для глубокого обучения, которая использует две или больше идентичных подсети, которые имеют ту же архитектуру и совместно используют те же параметры и веса. Сиамские сети обычно используются в задачах, которые включают нахождение отношения между двумя сопоставимыми вещами. Некоторые распространенные приложения для сиамских сетей включают распознавание лиц, верификацию подписи [1], или перефразируют идентификацию [2]. Сиамские сети выполняют хорошо в этих задачах, потому что их разделяемые веса означают, что существует меньше параметров, чтобы учиться во время обучения, и они могут привести к хорошим результатам с относительно небольшим количеством обучающих данных.
Сиамские сети особенно полезны в случаях, где существуют большие количества классов с небольшими числами наблюдений за каждым. В таких случаях существует недостаточно данных, чтобы обучить глубокую сверточную нейронную сеть классифицировать изображения в эти классы. Вместо этого сиамская сеть может определить, находятся ли два изображения в том же классе. Сеть делает это путем сокращения размерности обучающих данных и использования основанной на расстоянии функции стоимости, чтобы дифференцироваться между классами.
Этот пример использует сиамскую сеть для сокращения размерности набора изображений рукописных цифр. Сиамская архитектура уменьшает размерность путем отображения изображений с тем же классом к соседним точкам в низком мерном пространстве. Представление уменьшаемой функции затем используется, чтобы извлечь изображения из набора данных, которые являются самыми похожими на тестовое изображение. Обучающие данные в этом примере являются изображениями размера 28 28 1, давая начальную размерность функции 784. Сиамская сеть уменьшает размерность входных изображений к двум функциям и обучена, чтобы вывести подобные уменьшаемые функции изображений с той же меткой.
Можно также использовать сиамские сети, чтобы идентифицировать подобные изображения путем прямого сравнения их. Для примера смотрите, Обучают сиамскую Сеть, чтобы Сравнить Изображения.
Загрузите обучающие данные, который состоит из изображений рукописных цифр. Функциональный digitTrain4DArrayData
загружает изображения цифры и их метки.
[XTrain,YTrain] = digitTrain4DArrayData;
XTrain
28 28 1 5 000 массивов, содержащих 5 000 одноканальных изображений, каждый размер 28 28. Значения каждого пикселя между 0
и 1
. YTrain
категориальный вектор, содержащий метки для каждого наблюдения, которые являются числами от 0 до 9 соответствий значению записанной цифры.
Отобразите случайный выбор изображений.
perm = randperm(numel(YTrain), 9);
imshow(imtile(XTrain(:,:,:,perm),"ThumbnailSize",[100 100]));
Чтобы обучить сеть, данные должны быть сгруппированы в пары изображений, которые или подобны или отличаются. Здесь, подобные изображения заданы как наличие той же метки, в то время как отличающиеся изображения имеют различные метки. Функциональный getSiameseBatch
(заданный в разделе Supporting Functions этого примера), создает рандомизированные пары подобных или отличающихся изображений, pairImage1
и pairImage2
. Функция также возвращает метку pairLabel
, который идентифицирует, подобна ли пара изображений или отличается друг от друга. Подобные пары изображений имеют pairLabel = 1
, в то время как отличающиеся пары имеют pairLabel = 0
.
Как пример, создайте маленький представительный набор пяти пар изображений
batchSize = 10; [pairImage1,pairImage2,pairLabel] = getSiameseBatch(XTrain,YTrain,batchSize);
Отобразите сгенерированные пары изображений.
for i = 1:batchSize subplot(2,5,i) imshow([pairImage1(:,:,:,i) pairImage2(:,:,:,i)]); if pairLabel(i) == 1 s = "similar"; else s = "dissimilar"; end title(s) end
В этом примере новый пакет 180 парных изображений создается для каждой итерации учебного цикла. Это гарантирует, что сеть обучена на большом количестве случайных пар изображений приблизительно с равными пропорциями подобных и отличающихся пар.
Сиамская сетевая архитектура проиллюстрирована в следующей схеме.
В этом примере две идентичных подсети заданы как серия полносвязных слоев со слоями ReLU. Создайте сеть, которая принимает 28 28 1 изображением и выводит эти два характеристических вектора, используемые для уменьшаемого представления функции. Сеть уменьшает размерность входных изображений к два, значение, которое легче построить и визуализировать, чем начальная размерность 784.
Для первых двух полносвязных слоев задайте выходной размер 1 024 и используйте Его инициализатор веса.
Для итогового полносвязного слоя задайте выходной размер два и используйте инициализатор весов Его.
layers = [ imageInputLayer([28 28],'Name','input1','Normalization','none') fullyConnectedLayer(1024,'Name','fc1','WeightsInitializer','he') reluLayer('Name','relu1') fullyConnectedLayer(1024,'Name','fc2','WeightsInitializer','he') reluLayer('Name','relu2') fullyConnectedLayer(2,'Name','fc3','WeightsInitializer','he')]; lgraph = layerGraph(layers);
Чтобы обучить сеть с пользовательским учебным циклом и включить автоматическое дифференцирование, преобразуйте график слоев в dlnetwork
объект.
dlnet = dlnetwork(lgraph);
Создайте функциональный modelGradients
(заданный в разделе Supporting Functions этого примера). modelGradients
функционируйте берет сиамский dlnetwork
объект dlnet
and
мини-пакет входных данных dlX1
и dlX2
с их маркирует pairLabels
. Функция возвращает значения потерь и градиенты потери относительно настраиваемых параметров сети.
Цель сиамской сети состоит в том, чтобы вывести характеристический вектор для каждого изображения, таким образом, что характеристические векторы подобны для подобных изображений и особенно отличаются для отличающихся изображений. Таким образом сеть может различить между двумя входными параметрами.
Найдите сравнительную потерю между выходными параметрами от последнего полносвязного слоя, характеристические векторы features1
и features1
от pairImage1
и pairImage2
, соответственно. Сравнительная потеря для пары дана [3]
где значение парной метки ( для подобных изображений; для отличающихся изображений), и Евклидово расстояние между двумя векторами функций и : .
параметр используется для ограничения: если два изображения в паре отличаются, то их расстояние должно быть, по крайней мере, , или потеря будет понесена.
Сравнительная потеря имеет два условия, но только один является когда-либо ненулевым для данной пары изображений. В случае подобных изображений первый срок может быть ненулевым и минимизирован путем сокращения расстояния между функциями изображений и . В случае отличающихся изображений второй срок может быть ненулевым, и минимизирован путем увеличения расстояния между функциями изображений по крайней мере, к расстоянию . Меньшее значение , меньше ограничения его по тому, как близко отличающаяся пара может быть, прежде чем потеря понесена.
Задайте значение использовать во время обучения.
margin = 0.3;
Задайте опции, чтобы использовать во время обучения. Обучайтесь для 3 000 итераций.
numIterations = 3000; miniBatchSize = 180;
Задайте опции для оптимизации ADAM:
Установите скорость обучения на 0.0001
.
Инициализируйте запаздывающий средний градиент и запаздывающие средние уровни затухания градиентного квадрата с []
.
Установитесь коэффициент затухания градиента на 0.9
и градиент в квадрате затухает фактор к 0.99
.
learningRate = 1e-4; trailingAvg = []; trailingAvgSq = []; gradDecay = 0.9; gradDecaySq = 0.99;
Обучайтесь на графическом процессоре, если вы доступны. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA®, графический процессор с вычисляет возможность 3.0 или выше. Автоматически обнаружить, если вы имеете графический процессор в наличии и помещаете соответствующие данные по графическому процессору, устанавливаете значение executionEnvironment
к "auto"
. Если вы не имеете графического процессора или не хотите использовать один для обучения, устанавливать значение executionEnvironment
к "cpu"
. Чтобы убедиться вы используете графический процессор для обучения, устанавливаете значение executionEnvironment
к "gpu"
.
executionEnvironment = "auto";
Чтобы контролировать процесс обучения, можно построить учебную потерю после каждой итерации. Создайте переменную plots
это содержит "training-progress"
. Если вы не хотите строить процесс обучения, установите это значение к "none"
.
plots = "training-progress";
Инициализируйте параметры графика для учебного графика прогресса потерь.
plotRatio = 16/9; if plots == "training-progress" trainingPlot = figure; trainingPlot.Position(3) = plotRatio*trainingPlot.Position(4); trainingPlot.Visible = 'on'; trainingPlotAxes = gca; lineLossTrain = animatedline(trainingPlotAxes); xlabel(trainingPlotAxes,"Iteration") ylabel(trainingPlotAxes,"Loss") title(trainingPlotAxes,"Loss During Training") end
Чтобы оценить, как хорошо сеть делает при сокращении размерности, вычислите и постройте уменьшаемые функции набора тестовых данных после каждой итерации. Загрузите тестовые данные, который состоит из изображений рукописных цифр, похожих на обучающие данные. Преобразуйте тестовые данные в dlarray
и укажите, что размерность маркирует 'SSCB'
(пространственный, пространственный, канал, пакет). Если вы используете графический процессор, преобразуете тестовые данные в gpuArray
.
[XTest,YTest] = digitTest4DArrayData; dlXTest = dlarray(single(XTest),'SSCB'); % If training on a GPU, then convert data to gpuArray. if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu" dlXTest = gpuArray(dlXTest); end
Инициализируйте параметры графика для графика уменьшаемой функции тестовых данных.
dimensionPlot = figure;
dimensionPlot.Position(3) = plotRatio*dimensionPlot.Position(4);
dimensionPlot.Visible = 'on';
dimensionPlotAxes = gca;
uniqueGroups = unique(YTest);
colors = hsv(length(uniqueGroups));
Инициализируйте в противоречии с, отслеживают общее количество итераций.
iteration = 1;
Обучите модель с помощью пользовательского учебного цикла. Цикл по обучающим данным и обновлению сетевые параметры в каждой итерации.
Для каждой итерации:
Извлеките пакет пар изображений и меток с помощью getSiameseBatch
функция, определяемая в разделе Create Batches of Image Pairs.
Преобразуйте данные изображения в dlarray
объекты с базовым типом single
и укажите, что размерность маркирует 'SSCB'
(пространственный, пространственный, канал, пакет).
Для обучения графического процессора преобразуйте данные изображения в gpuArray
объекты.
Оцените градиенты модели с помощью dlfeval
и modelGradients
функция.
Обновите сетевые параметры с помощью adamupdate
функция.
% Loop over mini-batches. for iteration = 1:numIterations % Extract mini-batch of image pairs and pair labels [X1,X2,pairLabels] = getSiameseBatch(XTrain,YTrain,miniBatchSize); % Convert mini-batch of data to dlarray. Specify the dimension labels % 'SSCB' (spatial, spatial, channel, batch) for image data dlX1 = dlarray(single(X1),'SSCB'); dlX2 = dlarray(single(X2),'SSCB'); % If training on a GPU, then convert data to gpuArray. if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu" dlX1 = gpuArray(dlX1); dlX2 = gpuArray(dlX2); end % Evaluate the model gradients and the generator state using % dlfeval and the modelGradients function listed at the end of the % example. [gradients,loss] = dlfeval(@modelGradients,dlnet,dlX1,dlX2,pairLabels,margin); lossValue = double(gather(extractdata(loss))); % Update the Siamese network parameters. [dlnet.Learnables,trailingAvg,trailingAvgSq] = ... adamupdate(dlnet.Learnables,gradients, ... trailingAvg,trailingAvgSq,iteration,learningRate,gradDecay,gradDecaySq); % Update the training loss progress plot. if plots == "training-progress" addpoints(lineLossTrain,iteration,lossValue); end % Update the reduced-feature plot of the test data. % Compute reduced features of the test data: dlFTest = predict(dlnet,dlXTest); FTest = extractdata(dlFTest); figure(dimensionPlot); for k = 1:length(uniqueGroups) % Get indices of each image in test data with the same numeric % label (defined by the unique group): ind = YTest==uniqueGroups(k); % Plot this group: plot(dimensionPlotAxes,gather(FTest(1,ind)'),gather(FTest(2,ind)'),'.','color',... colors(k,:)); hold on end legend(uniqueGroups) % Update title of reduced-feature plot with training progress information. title(dimensionPlotAxes,"2-D Feature Representation of Digits Images. Iteration = " +... iteration); legend(dimensionPlotAxes,'Location','eastoutside'); xlabel(dimensionPlotAxes,"Feature 1") ylabel(dimensionPlotAxes,"Feature 2") hold off drawnow end
Сеть теперь училась представлять каждое изображение как 2D вектор. Как вы видите из графика уменьшаемой функции тестовых данных, изображения подобных цифр кластеризируются друг близко к другу в этом 2D представлении.
Можно использовать обучивший сеть, чтобы найти выбор изображений, которые похожи друг на друга из группы. В этом случае используйте тестовые данные в качестве группы изображений. Преобразуйте группу изображений к dlarray
объекты и gpuArray
объекты, если вы используете графический процессор.
groupX = XTest; dlGroupX = dlarray(single(groupX),'SSCB'); if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu" dlGroupX = gpuArray(dlGroupX); end
Извлеките одно тестовое изображение из группы и отобразите ее. Удалите тестовое изображение из группы так, чтобы это не появлялось в наборе подобных изображений.
testIdx = randi(5000);
testImg = dlGroupX(:,:,:,testIdx);
trialImgDisp = extractdata(testImg);
figure
imshow(trialImgDisp, 'InitialMagnification', 500);
dlGroupX(:,:,:,testIdx) = [];
Найдите уменьшаемые функции тестового изображения с помощью predict
.
trialF = predict(dlnet,testImg);
Найдите 2D уменьшаемое представление функции каждого из изображений в группе, использующей обучивший сеть.
FGroupX = predict(dlnet,dlGroupX);
Используйте уменьшаемое представление функции, чтобы найти девять изображений в группе, которые являются самыми близкими к тестовому изображению, с помощью Евклидовой метрики расстояния. Отобразите изображения.
distances = vecnorm(extractdata(trialF - FGroupX));
[~,idx] = sort(distances);
sortedImages = groupX(:,:,:,idx);
figure
imshow(imtile(sortedImages(:,:,:,1:9)), 'InitialMagnification', 500);
Путем сокращения изображений до более низкой размерности сеть может идентифицировать изображения, которые похожи на испытательное изображение. Уменьшаемое представление функции позволяет сети различать между изображениями, которые подобны и отличаются. Сиамские сети часто используются в контексте распознавания подписи или ухода за лицом. Например, можно обучить сиамскую сеть, чтобы принять изображение поверхности как вход и возвратить набор самых подобных поверхностей от базы данных.
Функциональный modelGradients
берет сиамский dlnetwork
объект dlnet
, пара мини-данных пакетного ввода X1
и X2
, и метка pairLabels
. Функция возвращает градиенты потери относительно настраиваемых параметров в сети, а также сравнительной потери между уменьшаемыми функциями размерности парных изображений. В этом примере, функциональном modelGradients
введен в разделе Define Model Gradients Function.
function [gradients, loss] = modelGradients(net,X1,X2,pairLabel,margin) % The modelGradients function calculates the contrastive loss between the % paired images and returns the loss and the gradients of the loss with % respect to the network learnable parameters % Pass first half of image pairs forward through the network F1 = forward(net,X1); % Pass second set of image pairs forward through the network F2 = forward(net,X2); % Calculate contrastive loss loss = contrastiveLoss(F1,F2,pairLabel,margin); % Calculate gradients of the loss with respect to the network learnable % parameters gradients = dlgradient(loss, net.Learnables); end function loss = contrastiveLoss(F1,F2,pairLabel,margin) % The contrastiveLoss function calculates the contrastive loss between % the reduced features of the paired images % Define small value to prevent taking square root of 0 delta = 1e-6; % Find Euclidean distance metric distances = sqrt(sum((F1 - F2).^2,1) + delta); % label(i) = 1 if features1(:,i) and features2(:,i) are features % for similar images, and 0 otherwise lossSimilar = pairLabel.*(distances.^2); lossDissimilar = (1 - pairLabel).*(max(margin - distances, 0).^2); loss = 0.5*sum(lossSimilar + lossDissimilar,'all'); end
Следующие функции создают рандомизированные пары изображений, которые подобны или отличаются, на основе их меток. В этом примере, функциональном getSiameseBatch
введен в разделе Create Pairs of Similar и Dissimilar Images.
function [X1,X2,pairLabels] = getSiameseBatch(X,Y,miniBatchSize) % getSiameseBatch returns a randomly selected batch of paired images. % On average, this function produces a balanced set of similar and % dissimilar pairs. pairLabels = zeros(1, miniBatchSize); imgSize = size(X(:,:,:,1)); X1 = zeros([imgSize 1 miniBatchSize]); X2 = zeros([imgSize 1 miniBatchSize]); for i = 1:miniBatchSize choice = rand(1); if choice < 0.5 [pairIdx1, pairIdx2, pairLabels(i)] = getSimilarPair(Y); else [pairIdx1, pairIdx2, pairLabels(i)] = getDissimilarPair(Y); end X1(:,:,:,i) = X(:,:,:,pairIdx1); X2(:,:,:,i) = X(:,:,:,pairIdx2); end end function [pairIdx1,pairIdx2,pairLabel] = getSimilarPair(classLabel) % getSimilarPair returns a random pair of indices for images % that are in the same class and the similar pair label = 1. % Find all unique classes. classes = unique(classLabel); % Choose a class randomly which will be used to get a similar pair. classChoice = randi(numel(classes)); % Find the indices of all the observations from the chosen class. idxs = find(classLabel==classes(classChoice)); % Randomly choose two different images from the chosen class. pairIdxChoice = randperm(numel(idxs),2); pairIdx1 = idxs(pairIdxChoice(1)); pairIdx2 = idxs(pairIdxChoice(2)); pairLabel = 1; end function [pairIdx1,pairIdx2,pairLabel] = getDissimilarPair(classLabel) % getDissimilarPair returns a random pair of indices for images % that are in different classes and the dissimilar pair label = 0. % Find all unique classes. classes = unique(classLabel); % Choose two different classes randomly which will be used to get a dissimilar pair. classesChoice = randperm(numel(classes), 2); % Find the indices of all the observations from the first and second classes. idxs1 = find(classLabel==classes(classesChoice(1))); idxs2 = find(classLabel==classes(classesChoice(2))); % Randomly choose one image from each class. pairIdx1Choice = randi(numel(idxs1)); pairIdx2Choice = randi(numel(idxs2)); pairIdx1 = idxs1(pairIdx1Choice); pairIdx2 = idxs2(pairIdx2Choice); pairLabel = 0; end
[1] Бромли, J. i. Guyon, И. Леканн, Э. Зекингер и Р. Шах. "Верификация подписи с помощью "сиамской" Нейронной сети С временной задержкой". В Продолжениях 6-й Международной конференции по вопросам Нейронных Систем обработки информации (NIPS 1993), 1994, pp737-744. Доступный при Верификации Подписи с помощью "сиамской" Нейронной сети С временной задержкой на веб-сайте Продолжений NIPS.
[2] Wenpeg, Y. и H Schütze. "Сверточная нейронная сеть для Идентификации Пересказа". В Продолжениях 2 015 Конференций североамериканского Cahapter ACL, 2015, pp901-911. Доступный в Сверточной нейронной сети для Идентификации Пересказа на веб-сайте Антологии ACL.
[3] Hadsell, R., С. Чопра и И. Леканн. "Сокращение размерности путем Обучения Инвариантному Отображению". В Продолжениях 2 006 Конференций Общества эпохи компьютеризации IEEE по Компьютерному зрению и Распознаванию образов (CVPR 2006), 2006, pp1735-1742.
adamupdate
| dlarray
| dlfeval
| dlgradient
| dlnetwork