В этом примере показано, как обучить сиамскую сеть сравнивать рукописные цифры с помощью уменьшения размерности.
Сиамская сеть - это тип сети глубокого обучения, которая использует две или более идентичных подсетей, которые имеют одинаковую архитектуру и совместно используют одни и те же параметры и веса. Сиамские сети обычно используются в задачах, которые включают в себя поиск взаимосвязи между двумя сопоставимыми вещами. Некоторые распространенные приложения для сиамских сетей включают распознавание лиц, проверку подписи [1] или идентификацию перефразирования [2]. Сиамские сети хорошо справляются с этими задачами, потому что их общие веса означают, что во время обучения нужно изучать меньше параметров, и они могут дать хорошие результаты с относительно небольшим количеством данных обучения.
Сиамские сети особенно полезны в тех случаях, когда существует большое количество классов с небольшим количеством наблюдений каждого из них. В таких случаях не хватает данных, чтобы обучить глубокую сверточную нейронную сеть классифицировать изображения на эти классы. Вместо этого сиамская сеть может определить, находятся ли два изображения в одном классе. Сеть делает это, уменьшая размерность обучающих данных и используя основанную на расстоянии функцию затрат для дифференциации между классами.
В этом примере для уменьшения размерности набора изображений рукописных цифр используется сиамская сеть. Сиамская архитектура уменьшает размерность, отображая изображения одного класса на близлежащие точки в низкоразмерном пространстве. Затем представление с уменьшенной характеристикой используется для извлечения из набора данных изображений, наиболее похожих на тестовое изображение. Данные тренировки в этом примере - изображения размера 28 на 28 на 1, давая начальную размерность особенности 784. Сиамская сеть уменьшает размерность входных изображений до двух характеристик и обучена выводить аналогичные уменьшенные характеристики для изображений с одной и той же меткой.
Можно также использовать сиамские сети для идентификации подобных изображений, напрямую сравнивая их. Пример см. в разделе Подготовка сиамской сети для сравнения изображений.
Загрузите обучающие данные, состоящие из изображений рукописных цифр. Функция digitTrain4DArrayData загружает цифровые изображения и их метки.
[XTrain,YTrain] = digitTrain4DArrayData;
XTrain множество 28 на 28 на 1 на 5000, содержащее 5 000 одноканальных изображений, каждый размер 28 на 28. Значения каждого пикселя находятся между 0 и 1. YTrain - категориальный вектор, содержащий метки для каждого наблюдения, представляющие собой числа от 0 до 9, соответствующие значению записанной цифры.
Отображение случайного выбора изображений.
perm = randperm(numel(YTrain), 9);
imshow(imtile(XTrain(:,:,:,perm),"ThumbnailSize",[100 100]));
Чтобы обучить сеть, данные должны быть сгруппированы в пары изображений, которые похожи или отличаются друг от друга. Здесь подобные изображения определяются как имеющие одну и ту же метку, в то время как разные изображения имеют разные метки. Функция getSiameseBatch (определено в разделе «Вспомогательные функции» этого примера) создает рандомизированные пары похожих или разнородных изображений, 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.
Для первых двух полностью соединенных слоев укажите размер выхода 1024 и используйте инициализатор He weight.
Для конечного полностью подключенного слоя укажите размер вывода два и используйте инициализатор He weights.
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 (определено в разделе «Вспомогательные функции» данного примера). modelGradients функция принимает сиамский dlnetwork объект dlnet and мини-пакет входных данных dlX1 и dlX2 с их этикетками pairLabels. Функция возвращает значения потерь и градиенты потерь относительно обучаемых параметров сети.
Цель сиамской сети состоит в том, чтобы вывести вектор признаков для каждого изображения таким образом, чтобы векторы признаков были одинаковыми для аналогичных изображений и особенно различными для разных изображений. Таким образом, сеть может различать два входа.
Найти контрастные потери между выходами последнего полностью подключенного уровня, векторы признаков features1 и features1 от pairImage1 и pairImage2соответственно. Контрастные потери для пары даны в [3]
margin-d, 0) 2,
где - значение метки пары ( 1 для аналогичных y = 0 для разнородных изображений), а d - евклидово расстояние между двумя векторами признаков f1 и d=‖f1-f2‖2.
Параметр margin используется для ограничения: если два изображения в паре отличаются друг от друга, то их расстояние должно быть как минимум , либо возникнут потери.
Контрастная потеря имеет два члена, но только один всегда ненулевой для данной пары изображений. В случае аналогичных изображений первый член может быть ненулевым и минимизирован за счет уменьшения расстояния между признаками и изображения. В случае различных изображений второй член может быть ненулевым и минимизирован путем увеличения расстояния между элементами изображения, по меньшей мере, до расстояния . Чем меньше величина , тем меньше ограничения на то, насколько близка может быть разнородная пара до возникновения убытка.
Укажите значение для использования во время обучения.
margin = 0.3;
Укажите параметры для использования во время обучения. Обучение для 3000 итераций.
numIterations = 3000; miniBatchSize = 180;
Укажите параметры оптимизации ADAM:
Установка коэффициента обучения на 0.0001.
Инициализируйте среднюю градиентную скорость и среднюю градиентно-квадратную скорость затухания с помощью [].
Задать коэффициент градиентного затухания равным 0.9 и квадрат градиентного коэффициента распада до 0.99.
learningRate = 1e-4; trailingAvg = []; trailingAvgSq = []; gradDecay = 0.9; gradDecaySq = 0.99;
Обучение на GPU, если он доступен. Для использования графического процессора требуется Toolbox™ параллельных вычислений и поддерживаемое устройство графического процессора. Сведения о поддерживаемых устройствах см. в разделе Поддержка графического процессора по выпуску (Parallel Computing Toolbox). Для автоматического определения наличия графического процессора и размещения соответствующих данных на графическом процессоре установите значение 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 функция, определенная в разделе Создание пакетов пар изображений.
Преобразовать данные изображения в dlarray объекты с базовым типом single и укажите метки размеров 'SSCB' (пространственный, пространственный, канальный, пакетный).
Для обучения GPU преобразуйте данные изображения в 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



Теперь сеть научилась представлять каждое изображение в виде вектора 2-D. Как видно из графика с уменьшенной характеристикой тестовых данных, изображения аналогичных цифр сгруппированы близко друг к другу в этом 2-D представлении.
Можно использовать обучаемую сеть, чтобы найти подборку изображений, похожих друг на друга из группы. В этом случае используйте тестовые данные в качестве группы изображений. Преобразование группы изображений в 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);
Найдите 2-D уменьшенное представление каждого из изображений в группе с помощью обученной сети.
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 вводится в разделе Определение функции градиентов модели.
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 представлен в разделе Создание пар похожих и разнородных изображений.
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] Бромли, Дж., И. Гайон, Я. ЛеКанн, Э. Зекингер и Р. Шах. «Проверка подписи с использованием» сиамской «нейронной сети задержки времени». В трудах 6-й Международной конференции по нейронным системам обработки информации (NIPS 1993), 1994, pp737-744. Доступна при проверке подписи с использованием нейронной сети задержки времени «Siamese» на веб-сайте NIPS Proceedings.
[2] Венпег, Ю. и Х. Шютце. «Сверточная нейронная сеть для идентификации парафраза». В трудах 2015 года Конференция Североамериканского кахаптера ACL, 2015, pp901-911. Доступен в сверточной нейронной сети для идентификации парафраза на сайте ACL Anthology.
[3] Hadsell, R., С. Чопра и И. Леканн. «Уменьшение размерности путем изучения инвариантного сопоставления». В трудах Конференции IEEE Computer Society 2006 по компьютерному зрению и распознаванию образов (CVPR 2006), 2006, pp1735-1742.
adamupdate | dlarray | dlfeval | dlgradient | dlnetwork