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