Запустите пользовательский учебный эксперимент для сравнения изображений

В этом примере показано, как создать пользовательский учебный эксперимент, чтобы обучить сиамскую сеть, которая идентифицирует подобные изображения рукописных символов. Для пользовательского учебного эксперимента вы явным образом задаете метод обучения, используемый Experiment Manager. В этом примере вы реализуете пользовательский учебный цикл, чтобы обучить сиамскую сеть, тип нейронной сети для глубокого обучения, которая использует две или больше идентичных подсети, которые имеют ту же архитектуру и совместно используют те же параметры и веса. Некоторые распространенные приложения для сиамских сетей включают распознавание лиц, верификацию подписи, и перефразируют идентификацию.

Эта схема иллюстрирует сиамскую сетевую архитектуру в этом примере.

Чтобы сравнить два изображения, вы передаете каждое изображение через одну из двух идентичных подсетей та доля веса. Подсети преобразуют каждого 105 105 1 изображением к 4096-мерному характеристическому вектору. Изображения того же класса имеют подобные 4096-мерные представления. Выходные характеристические векторы от каждой подсети объединены посредством вычитания, и результат передается через fullyconnect операция с одним выходом. Сигмоидальная операция преобразует это значение в вероятность, указывающую, что изображения подобны (когда вероятность близко к 1), или отличающийся (когда вероятность близко к 0). Бинарная потеря перекрестной энтропии между сетевым предсказанием и истинной меткой обновляет сеть во время обучения. Для получения дополнительной информации смотрите, Обучают сиамскую Сеть, чтобы Сравнить Изображения.

Открытый эксперимент

Во-первых, откройте пример. Experiment Manager загружает проект с предварительно сконфигурированным экспериментом, который можно смотреть и запустить. Чтобы открыть эксперимент, в панели Браузера Эксперимента, дважды кликают имя эксперимента (ImageComparisonExperiment).

Пользовательские учебные эксперименты состоят из описания, таблицы гиперпараметров и учебной функции. Для получения дополнительной информации смотрите, Конфигурируют Пользовательский Учебный Эксперимент.

Поле Description содержит текстовое описание эксперимента. В данном примере описание:

Train a Siamese network to identify similar and dissimilar images of handwritten characters.
Try different weight and bias initializers for the convolution and fully connected layers in the network.

Раздел Hyperparameters задает стратегию (Exhaustive Sweep) и гиперзначения параметров, чтобы использовать для эксперимента. Когда вы запускаете эксперимент, Experiment Manager обучает сеть с помощью каждой комбинации гиперзначений параметров, заданных в гипертаблице параметров. Этот пример использует гиперпараметры WeightsInitializer и BiasInitializer задавать вес и инициализаторы смещения, соответственно, для свертки и полносвязных слоев в каждой подсети. Для получения дополнительной информации об этих инициализаторах, смотрите WeightsInitializer и BiasInitializer.

Учебная Функция задает обучающие данные, сетевую архитектуру, опции обучения и метод обучения, используемый экспериментом. Вход к учебной функции является структурой с полями от гипертаблицы параметров и experiments.Monitor возразите, что можно использовать, чтобы отследить прогресс обучения, значения записи метрик, используемых обучением, и произвести учебные графики. Учебная функция возвращает структуру, которая содержит обучивший сеть, веса для итогового fullyconnect операция для сети и среда выполнения используются для обучения. Experiment Manager сохраняет этот выход, таким образом, можно экспортировать его в рабочее пространство MATLAB, когда обучение завершено. Учебная функция имеет пять разделов.

  • Инициализируйте Выход, устанавливает начальное значение сети и fullyconnect веса к пустым массивам, чтобы указать, что обучение не запустилось. Эксперимент устанавливает среду выполнения на "auto", таким образом, это обучает и проверяет сеть на графическом процессоре, если вы доступны. Используя графический процессор требует Parallel Computing Toolbox™ и поддерживаемого устройства графического процессора. Для получения дополнительной информации смотрите Поддержку графического процессора Релизом (Parallel Computing Toolbox).

output.network = [];
output.weights = [];
output.executionEnvironment = "auto";
  • Загрузите и Предварительно обработайте Обучение, и Тестовые данные задает обучение и тестовые данные для эксперимента как imageDatastore объекты. Эксперимент использует набор данных Omniglot, который состоит из наборов символов для 50 алфавитов, разделенных на 30 наборов для обучения и 20 наборов для тестирования. Для получения дополнительной информации об этом наборе данных смотрите Наборы Данных изображения.

monitor.Status = "Loading Training Data";
url = "https://github.com/brendenlake/omniglot/raw/master/python/images_background.zip";
downloadFolder = tempdir;
filename = fullfile(downloadFolder,"images_background.zip");
dataFolderTrain = fullfile(downloadFolder,"images_background");
if ~exist(dataFolderTrain,"dir")
    websave(filename,url);
    unzip(filename,downloadFolder);
end
imdsTrain = imageDatastore(dataFolderTrain, ...
    IncludeSubfolders=true, ...
    LabelSource="none");
files = imdsTrain.Files;
parts = split(files,filesep);
labels = join(parts(:,(end-2):(end-1)),'_');
imdsTrain.Labels = categorical(labels);
monitor.Status = "Loading Test Data";
url = "https://github.com/brendenlake/omniglot/raw/master/python/images_evaluation.zip";
downloadFolder = tempdir;
filename = fullfile(downloadFolder,"images_evaluation.zip");
dataFolderTest = fullfile(downloadFolder,"images_evaluation");
if ~exist(dataFolderTest,"dir")
    websave(filename,url);
    unzip(filename,downloadFolder);
end
imdsTest = imageDatastore(dataFolderTest, ...
    IncludeSubfolders=true, ...
    LabelSource="none");
files = imdsTest.Files;
parts = split(files,filesep);
labels = join(parts(:,(end-2):(end-1)),'_');
imdsTest.Labels = categorical(labels);
  • Архитектура Сети Define задает архитектуру для двух идентичных подсетей, которые принимают 105 105 1 изображением и выводят характеристический вектор. Свертка и полносвязные слоя используют веса и смещают инициализаторы, заданные в таблице гиперпараметра. Чтобы обучить сеть с пользовательским учебным циклом и включить автоматическое дифференцирование, учебная функция преобразует график слоев в dlnetwork объект. Веса для итогового fullyconnect операция инициализируется путем выборки случайного выбора от узкого нормального распределения со стандартным отклонением 0,01.

monitor.Status = "Creating Network";
layers = [
    imageInputLayer([105 105 1],Name="input1",Normalization="none")
    convolution2dLayer(10,64,Name="conv1", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu1")
    maxPooling2dLayer(2,Stride=2,Name="maxpool1")
    convolution2dLayer(7,128,Name="conv2", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu2")
    maxPooling2dLayer(2,'Stride',2,Name="maxpool2")
    convolution2dLayer(4,128,'Name','conv3', ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu3")
    maxPooling2dLayer(2,'Stride',2,Name="maxpool3")
    convolution2dLayer(5,256,Name="conv4", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu4")
    fullyConnectedLayer(4096,Name="fc1", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)];
lgraph = layerGraph(layers);
dlnet = dlnetwork(lgraph);
fcWeights = dlarray(0.01*randn(1,4096));
fcBias = dlarray(0.01*randn(1,1));
fcParams = struct(...
    "FcWeights",fcWeights,...
    "FcBias",fcBias);
output.network = dlnet;
output.weights = fcParams;
  • Укажите, что Опции обучения задают опции обучения, используемые экспериментом. В этом примере Experiment Manager обучает сеть с мини-пакетным размером 180 для 1 000 итераций, вычисляя точность сети каждые 100 итераций. Обучение может занять время, чтобы запуститься. Для лучших результатов рассмотрите увеличение обучения к 10 000 итераций.

numIterations = 1000;
miniBatchSize = 180;
validationFrequency = 100;
initialLearnRate = 6e-5;
gradientDecayFactor = 0.9;
squaredGradientDecayFactor = 0.99;
trailingAvgSubnet = [];
trailingAvgSqSubnet = [];
trailingAvgParams = [];
trailingAvgSqParams = [];
  • Обучайтесь Модель задает пользовательский учебный цикл, используемый экспериментом. Для каждой итерации пользовательский учебный цикл извлекает пакет пар изображений и меток, преобразует данные в dlarray объекты с базовым одним типом, и указывают, что размерность маркирует 'SSCB' (пространственный, пространственный, канал, пакет) для данных изображения и 'CB' (образуйте канал, пакет) для меток. Если вы обучаетесь на графическом процессоре, данные преобразованы в gpuArray (Parallel Computing Toolbox) объекты. Затем учебная функция оценивает градиенты модели и обновляет сетевые параметры. Чтобы подтвердить, учебная функция создает набор пяти случайных мини-пакетов тестовых пар, оценивает сетевые предсказания и вычисляет среднюю точность по мини-пакетам. После каждой итерации пользовательского учебного цикла учебная функция сохраняет обучивший сеть и веса для fullyconnect операция, записывает учебную потерю и обновляет процесс обучения.

monitor.Metrics = ["TrainingLoss" "ValidationAccuracy"];
monitor.XLabel = "Iteration";
monitor.Status = "Training";
for iteration = 1:numIterations
    [X1,X2,pairLabels] = getSiameseBatch(imdsTrain,miniBatchSize);
    dlX1 = dlarray(single(X1),"SSCB");
    dlX2 = dlarray(single(X2),"SSCB");
    if (output.executionEnvironment == "auto" && canUseGPU) || ...
            output.executionEnvironment == "gpu"
        dlX1 = gpuArray(dlX1);
        dlX2 = gpuArray(dlX2);
    end
    [gradientsSubnet, gradientsParams,loss] = dlfeval(@modelGradients, ...
        dlnet,fcParams,dlX1,dlX2,pairLabels);
    lossValue = double(gather(extractdata(loss)));
    [dlnet,trailingAvgSubnet,trailingAvgSqSubnet] = ...
        adamupdate(dlnet,gradientsSubnet, ...
        trailingAvgSubnet,trailingAvgSqSubnet, ...
        iteration,initialLearnRate,gradientDecayFactor,squaredGradientDecayFactor);
    [fcParams,trailingAvgParams,trailingAvgSqParams] = ...
        adamupdate(fcParams,gradientsParams, ...
        trailingAvgParams,trailingAvgSqParams, ...
        iteration,initialLearnRate,gradientDecayFactor,squaredGradientDecayFactor);
    if ~rem(iteration,validationFrequency) || iteration == 1 || iteration == numIterations
        monitor.Status = "Validating";
        accuracy = zeros(1,5);
        accuracyBatchSize = 150;
        for i = 1:5
            [XAcc1,XAcc2,pairLabelsAcc] = getSiameseBatch(imdsTest,accuracyBatchSize);
            dlXAcc1 = dlarray(single(XAcc1),"SSCB");
            dlXAcc2 = dlarray(single(XAcc2),"SSCB");
            if (output.executionEnvironment == "auto" && canUseGPU) || ...
                    output.executionEnvironment == "gpu"
                dlXAcc1 = gpuArray(dlXAcc1);
                dlXAcc2 = gpuArray(dlXAcc2);
            end
            dlY = predictSiamese(dlnet,fcParams,dlXAcc1,dlXAcc2);
            Y = gather(extractdata(dlY));
            Y = round(Y);
            accuracy(i) = sum(Y == pairLabelsAcc)/accuracyBatchSize;
        end
        recordMetrics(monitor,iteration, ...
            ValidationAccuracy=mean(accuracy)*100);
        monitor.Status = "Training";
    end
    output.network = dlnet;
    output.weights = fcParams;
    recordMetrics(monitor,iteration, ...
        TrainingLoss=lossValue);
    monitor.Progress = (iteration/numIterations)*100;
    if monitor.Stop
        return;
    end
end

Чтобы смотреть учебную функцию, под Учебной Функцией, нажимают Edit. Учебная функция открывается в Редакторе MATLAB®. Кроме того, код для учебной функции появляется в Приложении 1 в конце этого примера.

Запустите эксперимент

Когда вы запускаете эксперимент, Experiment Manager обучает сеть, заданную учебной функцией многократно. Каждое испытание использует различную комбинацию гиперзначений параметров. По умолчанию Experiment Manager запускает одно испытание за один раз. Если у вас есть Parallel Computing Toolbox, можно запустить несколько испытаний одновременно. Для лучших результатов, прежде чем вы запустите свой эксперимент, начинают параллельный пул со стольких же рабочих сколько графические процессоры. Для получения дополнительной информации смотрите Использование Experiment Manager, чтобы Обучить нейронные сети параллельно.

  • Чтобы запустить один суд над экспериментом за один раз, на панели инструментов Experiment Manager, нажимают Run.

  • Чтобы запустить несколько испытаний одновременно, нажмите Use Parallel и затем Запуск. Если нет никакого текущего параллельного пула, Experiment Manager запускает тот с помощью кластерного профиля по умолчанию. Experiment Manager затем выполняет несколько одновременных испытаний, в зависимости от количества параллельных доступных рабочих.

Таблица результатов показывает учебную потерю и точность валидации для каждого испытания.

В то время как эксперимент запускается, нажмите Training Plot, чтобы отобразить учебный график и отследить прогресс каждого испытания.

Оцените результаты

Чтобы найти лучший результат для вашего эксперимента, отсортируйте таблицу результатов точностью валидации.

  1. Укажите на столбец ValidationAccuracy.

  2. Кликните по треугольному значку.

  3. Выберите Sort в порядке убывания.

Испытание с самой высокой точностью валидации появляется наверху таблицы результатов.

Чтобы визуально проверять, идентифицирует ли сеть правильно подобные и отличающиеся пары:

  1. Выберите испытание с самой высокой точностью.

  2. На панели инструментов Experiment Manager нажмите Export.

  3. В диалоговом окне введите имя переменной рабочей области для экспортируемого учебного выхода. Именем по умолчанию является trainingOutput.

  4. Протестируйте сеть на маленьком пакете пар изображений путем вызова displayTestSet функция, которая перечислена в Приложении 3 в конце этого примера. Используйте экспортируемый учебный выход в качестве входа к функции. Например, в командном окне MATLAB, введите:

displayTestSet(trainingOutput)

Функция отображает 10 случайным образом выбранных пар тестовых изображений с предсказанием от обучившего сеть, счета вероятности и метки, указывающей, является ли предсказание правильным или неправильным.

Чтобы записать наблюдения о результатах вашего эксперимента, добавьте аннотацию.

  1. В таблице результатов щелкните правой кнопкой по ячейке ValidationAccuracy лучшего испытания.

  2. Выберите Add Annotation.

  3. В панели Аннотаций введите свои наблюдения в текстовое поле.

Для получения дополнительной информации смотрите сортировку, Фильтр, и Аннотируйте Результаты Эксперимента.

Закройте эксперимент

В панели Браузера Эксперимента щелкните правой кнопкой по имени проекта и выберите Close Project. Experiment Manager закрывает все эксперименты и результаты, содержавшиеся в проекте.

Приложение 1: учебная функция

Эта функция задает обучающие данные, сетевую архитектуру, опции обучения и метод обучения, используемый экспериментом.

Входной параметр

  • params структура с полями от гипертаблицы параметров Experiment Manager.

  • monitor experiments.Monitor возразите, что можно использовать, чтобы отследить прогресс обучения, полей информации об обновлении в таблице результатов, значениях записи метрик, используемых обучением, и произвести учебные графики.

Вывод

  • output структура, которая содержит обучивший сеть, веса для итогового fullyconnect операция для сети и среда выполнения используются для обучения. Experiment Manager сохраняет этот выход, таким образом, можно экспортировать его в рабочее пространство MATLAB, когда обучение завершено.

function output = ImageComparisonExperiment_training1(params,monitor)

output.network = [];
output.weights = [];
output.executionEnvironment = "auto";

monitor.Status = "Loading Training Data";

url = "https://github.com/brendenlake/omniglot/raw/master/python/images_background.zip";
downloadFolder = tempdir;
filename = fullfile(downloadFolder,"images_background.zip");

dataFolderTrain = fullfile(downloadFolder,"images_background");
if ~exist(dataFolderTrain,"dir")
    websave(filename,url);
    unzip(filename,downloadFolder);
end

imdsTrain = imageDatastore(dataFolderTrain, ...
    IncludeSubfolders=true, ...
    LabelSource="none");

files = imdsTrain.Files;
parts = split(files,filesep);
labels = join(parts(:,(end-2):(end-1)),'_');
imdsTrain.Labels = categorical(labels);

monitor.Status = "Loading Test Data";

url = "https://github.com/brendenlake/omniglot/raw/master/python/images_evaluation.zip";
downloadFolder = tempdir;
filename = fullfile(downloadFolder,"images_evaluation.zip");

dataFolderTest = fullfile(downloadFolder,"images_evaluation");
if ~exist(dataFolderTest,"dir")
    websave(filename,url);
    unzip(filename,downloadFolder);
end

imdsTest = imageDatastore(dataFolderTest, ...
    IncludeSubfolders=true, ...
    LabelSource="none");

files = imdsTest.Files;
parts = split(files,filesep);
labels = join(parts(:,(end-2):(end-1)),'_');
imdsTest.Labels = categorical(labels);

monitor.Status = "Creating Network";

layers = [
    imageInputLayer([105 105 1],Name="input1",Normalization="none")
    convolution2dLayer(10,64,Name="conv1", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu1")
    maxPooling2dLayer(2,Stride=2,Name="maxpool1")
    convolution2dLayer(7,128,Name="conv2", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu2")
    maxPooling2dLayer(2,'Stride',2,Name="maxpool2")
    convolution2dLayer(4,128,'Name','conv3', ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu3")
    maxPooling2dLayer(2,'Stride',2,Name="maxpool3")
    convolution2dLayer(5,256,Name="conv4", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)
    reluLayer(Name="relu4")
    fullyConnectedLayer(4096,Name="fc1", ...
        WeightsInitializer=params.WeightsInitializer, ...
        BiasInitializer=params.BiasInitializer)];

lgraph = layerGraph(layers);
dlnet = dlnetwork(lgraph);

fcWeights = dlarray(0.01*randn(1,4096));
fcBias = dlarray(0.01*randn(1,1));
fcParams = struct(...
    "FcWeights",fcWeights,...
    "FcBias",fcBias);

output.network = dlnet;
output.weights = fcParams;

numIterations = 1000;
miniBatchSize = 180;
validationFrequency = 100;
initialLearnRate = 6e-5;
gradientDecayFactor = 0.9;
squaredGradientDecayFactor = 0.99;
trailingAvgSubnet = [];
trailingAvgSqSubnet = [];
trailingAvgParams = [];
trailingAvgSqParams = [];

monitor.Metrics = ["TrainingLoss" "ValidationAccuracy"];
monitor.XLabel = "Iteration";
monitor.Status = "Training";

for iteration = 1:numIterations
    [X1,X2,pairLabels] = getSiameseBatch(imdsTrain,miniBatchSize);

    dlX1 = dlarray(single(X1),"SSCB");
    dlX2 = dlarray(single(X2),"SSCB");
    
    if (output.executionEnvironment == "auto" && canUseGPU) || ...
            output.executionEnvironment == "gpu"
        dlX1 = gpuArray(dlX1);
        dlX2 = gpuArray(dlX2);
    end
    
    [gradientsSubnet, gradientsParams,loss] = dlfeval(@modelGradients, ...
        dlnet,fcParams,dlX1,dlX2,pairLabels);
    lossValue = double(gather(extractdata(loss)));
    
    [dlnet,trailingAvgSubnet,trailingAvgSqSubnet] = ...
        adamupdate(dlnet,gradientsSubnet, ...
        trailingAvgSubnet,trailingAvgSqSubnet, ...
        iteration,initialLearnRate,gradientDecayFactor,squaredGradientDecayFactor);
    
    [fcParams,trailingAvgParams,trailingAvgSqParams] = ...
        adamupdate(fcParams,gradientsParams, ...
        trailingAvgParams,trailingAvgSqParams, ...
        iteration,initialLearnRate,gradientDecayFactor,squaredGradientDecayFactor);
    
    if ~rem(iteration,validationFrequency) || iteration == 1 || iteration == numIterations
        monitor.Status = "Validating";
        accuracy = zeros(1,5);
        accuracyBatchSize = 150;

        for i = 1:5
            [XAcc1,XAcc2,pairLabelsAcc] = getSiameseBatch(imdsTest,accuracyBatchSize);
            
            dlXAcc1 = dlarray(single(XAcc1),"SSCB");
            dlXAcc2 = dlarray(single(XAcc2),"SSCB");
            
            if (output.executionEnvironment == "auto" && canUseGPU) || ...
                    output.executionEnvironment == "gpu"
                dlXAcc1 = gpuArray(dlXAcc1);
                dlXAcc2 = gpuArray(dlXAcc2);
            end

            dlY = predictSiamese(dlnet,fcParams,dlXAcc1,dlXAcc2);
            
            Y = gather(extractdata(dlY));
            Y = round(Y);
            
            accuracy(i) = sum(Y == pairLabelsAcc)/accuracyBatchSize;
        end
        
        recordMetrics(monitor,iteration, ...
            ValidationAccuracy=mean(accuracy)*100);
        monitor.Status = "Training";
    end
    
    output.network = dlnet;
    output.weights = fcParams;
    recordMetrics(monitor,iteration, ...
        TrainingLoss=lossValue);
    monitor.Progress = (iteration/numIterations)*100;
    
    if monitor.Stop
        return;
    end
end
end

Приложение 2: пользовательские учебные функции помощника

modelGradients функционируйте берет в качестве входа сиамский dlnetwork объект net, пара мини-данных пакетного ввода dlX1 и dlX2, и метка, указывающая, подобны ли они или отличаются. Функция возвращает градиенты потери относительно настраиваемых параметров в сети и бинарной потере перекрестной энтропии между предсказанием и основной истиной.

function [gradientsSubnet,gradientsParams,loss] = modelGradients(dlnet,fcParams,dlX1,dlX2,pairLabels)
    Y = forwardSiamese(dlnet,fcParams,dlX1,dlX2);
    loss = binarycrossentropy(Y,pairLabels);
    [gradientsSubnet,gradientsParams] = dlgradient(loss,dlnet.Learnables,fcParams);
end

Эта функция возвращает бинарное значение потери перекрестной энтропии для предсказания от сети.

function loss = binarycrossentropy(Y,pairLabels)
    precision = underlyingType(Y);
    Y(Y < eps(precision)) = eps(precision);
    Y(Y > 1 - eps(precision)) = 1 - eps(precision);
     loss = -pairLabels.*log(Y) - (1 - pairLabels).*log(1 - Y);
     loss = sum(loss)/numel(pairLabels);
 end

Эта функция задает как подсети и fullyconnect и sigmoid операции объединяются, чтобы сформировать полную сиамскую сеть. Функция принимает структуру сети, и два обучения отображает и возвращает предсказание вероятности пары, являющейся подобным (ближе к 1) или отличающийся (ближе к 0).

function Y = forwardSiamese(dlnet,fcParams,dlX1,dlX2)
    F1 = forward(dlnet,dlX1);
    F1 = sigmoid(F1);
     F2 = forward(dlnet,dlX2);
     F2 = sigmoid(F2);
     Y = abs(F1 - F2);
     Y = fullyconnect(Y,fcParams.FcWeights,fcParams.FcBias);
     Y = sigmoid(Y);
 end

Эта функция возвращает случайным образом выбранный пакет парных изображений. В среднем эта функция производит сбалансированный набор подобных и отличающихся пар.

function [X1,X2,pairLabels] = getSiameseBatch(imds,miniBatchSize)
    pairLabels = zeros(1,miniBatchSize);
    imgSize = size(readimage(imds,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(imds.Labels);
        else
            [pairIdx1,pairIdx2,pairLabels(i)] = getDissimilarPair(imds.Labels);
        end
        X1(:,:,:,i) = imds.readimage(pairIdx1);
        X2(:,:,:,i) = imds.readimage(pairIdx2);
    end
end

Эта функция возвращает случайную пару индексов для изображений, которые находятся в том же классе и подобной парной метке 1.

function [pairIdx1,pairIdx2,label] = getSimilarPair(classLabel)
    classes = unique(classLabel);
    classChoice = randi(numel(classes));
    idxs = find(classLabel==classes(classChoice));
    pairIdxChoice = randperm(numel(idxs),2);
    pairIdx1 = idxs(pairIdxChoice(1));
    pairIdx2 = idxs(pairIdxChoice(2));
    label = 1;
end

Эта функция возвращает случайную пару индексов для изображений, которые находятся в различных классах и отличающейся парной метке 0.

function  [pairIdx1,pairIdx2,label] = getDissimilarPair(classLabel)
    classes = unique(classLabel);
    classesChoice = randperm(numel(classes),2);
    idxs1 = find(classLabel==classes(classesChoice(1)));
    idxs2 = find(classLabel==classes(classesChoice(2)));
    pairIdx1Choice = randi(numel(idxs1));
    pairIdx2Choice = randi(numel(idxs2));
    pairIdx1 = idxs1(pairIdx1Choice);
    pairIdx2 = idxs2(pairIdx2Choice);
    label = 0;
end

Эта функция использует обучивший сеть, чтобы сделать предсказания о подобии двух изображений.

function Y = predictSiamese(dlnet,fcParams,dlX1,dlX2)
    F1 = predict(dlnet,dlX1);
    F1 = sigmoid(F1);
     F2 = predict(dlnet,dlX2);
     F2 = sigmoid(F2);
     Y = abs(F1 - F2);
     Y = fullyconnect(Y,fcParams.FcWeights,fcParams.FcBias);
     Y = sigmoid(Y);
 end

Приложение 3: отобразите пары тестовых изображений

Эта функция создает маленький пакет пар изображений, чтобы помочь вам визуально проверять, идентифицирует ли сеть правильно подобные и отличающиеся пары. Эта функция использует функции помощника predictSiamese и predictSiamese, которые перечислены в Приложении 2.

function displayTestSet(trainingOutput)

dlnet = trainingOutput.network;
fcParams = trainingOutput.weights;
executionEnvironment = trainingOutput.executionEnvironment;

downloadFolder = tempdir;
dataFolderTest = fullfile(downloadFolder,"images_evaluation");
imdsTest = imageDatastore(dataFolderTest, ...
    IncludeSubfolders=true, ...
    LabelSource="none");    

files = imdsTest.Files;
parts = split(files,filesep);
labels = join(parts(:,(end-2):(end-1)),'_');
imdsTest.Labels = categorical(labels);

testBatchSize = 10;

[XTest1,XTest2,pairLabelsTest] = getSiameseBatch(imdsTest,testBatchSize);
    
dlXTest1 = dlarray(single(XTest1),"SSCB");
dlXTest2 = dlarray(single(XTest2),"SSCB");

if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu"
   dlXTest1 = gpuArray(dlXTest1);
   dlXTest2 = gpuArray(dlXTest2);
end

dlYScore = predictSiamese(dlnet,fcParams,dlXTest1,dlXTest2);
YScore = gather(extractdata(dlYScore));

YPred = round(YScore);    

XTest1 = extractdata(dlXTest1);
XTest2 = extractdata(dlXTest2);

plotRatio = 16/9;
testingPlot = figure;
testingPlot.Position(3) = plotRatio*testingPlot.Position(4);
testingPlot.Visible = "on";
    
for i = 1:numel(pairLabelsTest)
     
    if YPred(i) == 1
        predLabel = "similar";
    else
        predLabel = "dissimilar" ;
    end
    
    if pairLabelsTest(i) == YPred(i)
        testStr = "\bf\color{darkgreen}Correct\rm\newline";
    else
        testStr = "\bf\color{red}Incorrect\rm\newline";
    end
    
    subplot(2,5,i)        
    imshow([XTest1(:,:,:,i) XTest2(:,:,:,i)]);        
    
    title(testStr + "\color{black}Predicted: " + predLabel + "\newlineScore: " + YScore(i)); 
end

Смотрите также

Приложения

Функции

Объекты

Похожие темы