Обучите сеть с помощью функции Model

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

Загрузка обучающих данных

The digitTrain4DArrayData функция загружает изображения, их метки цифр и углы поворота от вертикали. Создание arrayDatastore объекты для изображений, меток и углов, а затем используйте combine функция, чтобы создать один datastore, который содержит все обучающие данные. Извлеките имена классов и количество недискретных ответов.

[XTrain,YTrain,anglesTrain] = digitTrain4DArrayData;

dsXTrain = arrayDatastore(XTrain,'IterationDimension',4);
dsYTrain = arrayDatastore(YTrain);
dsAnglesTrain = arrayDatastore(anglesTrain);

dsTrain = combine(dsXTrain,dsYTrain,dsAnglesTrain);

classNames = categories(YTrain);
numClasses = numel(classNames);
numResponses = size(anglesTrain,2);
numObservations = numel(YTrain);

Просмотрите некоторые изображения из обучающих данных.

idx = randperm(numObservations,64);
I = imtile(XTrain(:,:,:,idx));
figure
imshow(I)

Задайте модель глубокого обучения

Задайте следующую сеть, которая предсказывает и метки, и углы поворота.

  • Блок свертки-batchnorm-ReLU с 16 фильтрами 5 на 5.

  • Ветвь из двух блоков свертки-batchnorm каждый с 32 фильтрами 3 на 3 с операцией ReLU между

  • Пропускное соединение с блоком свертки-batchnorm с 32 свертками 1 на 1.

  • Объедините обе ветви с помощью сложения и последующей операции ReLU

  • Для вывода регрессии выход ветвь с полностью связанной операцией размера 1 (количество откликов).

  • Для вывода классификации выход ветвь с полностью связанной операцией размера 10 (количество классов) и операцией softmax.

Задайте и инициализируйте параметры модели и состояние

Определите параметры для каждой из операций и включите их в struct. Используйте формат parameters.OperationName.ParameterName где parameters - struct, O perationName - имя операции (для примера «conv1») и ParameterName - имя параметра (для примера - «Веса»).

Создайте struct parameters содержащие параметры модели. Инициализируйте обучаемые веса и смещения слоев с помощью initializeGlorot и initializeZeros функции , взятые в качестве примера,, соответственно. Инициализируйте параметры смещения и шкалы нормализации партии . с помощью initializeZeros и initializeOnes функции , взятые в качестве примера,, соответственно.

Чтобы выполнить обучение и вывод с использованием слоев нормализации партии ., необходимо также управлять состоянием сети. Перед предсказанием необходимо задать среднее значение набора данных и отклонения, выведенные из обучающих данных. Создайте struct state содержит параметры состояния. Статистика нормализации партии . не должна быть dlarray объекты. Инициализируйте нормализацию партии ., обученную средним и обученным состояниям отклонения, используя zeros и ones функций, соответственно.

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

Инициализируйте параметры для первого сверточного слоя.

filterSize = [5 5];
numChannels = 1;
numFilters = 16;

sz = [filterSize numChannels numFilters];
numOut = prod(filterSize) * numFilters;
numIn = prod(filterSize) * numFilters;

parameters.conv1.Weights = initializeGlorot(sz,numOut,numIn);
parameters.conv1.Bias = initializeZeros([numFilters 1]);

Инициализируйте параметры и состояние для первого слоя нормализации партии ..

parameters.batchnorm1.Offset = initializeZeros([numFilters 1]);
parameters.batchnorm1.Scale = initializeOnes([numFilters 1]);
state.batchnorm1.TrainedMean = zeros(numFilters,1,'single');
state.batchnorm1.TrainedVariance = ones(numFilters,1,'single');

Инициализируйте параметры для второго сверточного слоя.

filterSize = [3 3];
numChannels = 16;
numFilters = 32;

sz = [filterSize numChannels numFilters];
numOut = prod(filterSize) * numFilters;
numIn = prod(filterSize) * numFilters;

parameters.conv2.Weights = initializeGlorot(sz,numOut,numIn);
parameters.conv2.Bias = initializeZeros([numFilters 1]);

Инициализируйте параметры и состояние для второго слоя нормализации партии ..

parameters.batchnorm2.Offset = initializeZeros([numFilters 1]);
parameters.batchnorm2.Scale = initializeOnes([numFilters 1]);
state.batchnorm2.TrainedMean = zeros(numFilters,1,'single');
state.batchnorm2.TrainedVariance = ones(numFilters,1,'single');

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

filterSize = [3 3];
numChannels = 32;
numFilters = 32;

sz = [filterSize numChannels numFilters];
numOut = prod(filterSize) * numFilters;
numIn = prod(filterSize) * numFilters;

parameters.conv3.Weights = initializeGlorot(sz,numOut,numIn);
parameters.conv3.Bias = initializeZeros([numFilters 1]);

Инициализируйте параметры и состояние для третьего слоя нормализации партии ..

parameters.batchnorm3.Offset = initializeZeros([numFilters 1]);
parameters.batchnorm3.Scale = initializeOnes([numFilters 1]);
state.batchnorm3.TrainedMean = zeros(numFilters,1,'single');
state.batchnorm3.TrainedVariance = ones(numFilters,1,'single');

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

filterSize = [1 1];
numChannels = 16;
numFilters = 32;

sz = [filterSize numChannels numFilters];
numOut = prod(filterSize) * numFilters;
numIn = prod(filterSize) * numFilters;

parameters.convSkip.Weights = initializeGlorot(sz,numOut,numIn);
parameters.convSkip.Bias = initializeZeros([numFilters 1]);

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

parameters.batchnormSkip.Offset = initializeZeros([numFilters 1]);
parameters.batchnormSkip.Scale = initializeOnes([numFilters 1]);
state.batchnormSkip.TrainedMean = zeros([numFilters 1],'single');
state.batchnormSkip.TrainedVariance = ones([numFilters 1],'single');

Инициализируйте параметры для полносвязного слоя, соответствующего выходу классификации.

sz = [numClasses 6272];
numOut = numClasses;
numIn = 6272;
parameters.fc1.Weights = initializeGlorot(sz,numOut,numIn);
parameters.fc1.Bias = initializeZeros([numClasses 1]);

Инициализируйте параметры для полносвязного слоя, соответствующего выходу регрессии.

sz = [numResponses 6272];
numOut = numResponses;
numIn = 6272;
parameters.fc2.Weights = initializeGlorot(sz,numOut,numIn);
parameters.fc2.Bias = initializeZeros([numResponses 1]);

Просмотрите struct параметров.

parameters
parameters = struct with fields:
            conv1: [1×1 struct]
       batchnorm1: [1×1 struct]
            conv2: [1×1 struct]
       batchnorm2: [1×1 struct]
            conv3: [1×1 struct]
       batchnorm3: [1×1 struct]
         convSkip: [1×1 struct]
    batchnormSkip: [1×1 struct]
              fc1: [1×1 struct]
              fc2: [1×1 struct]

Просмотрите параметры для операции «conv1».

parameters.conv1
ans = struct with fields:
    Weights: [5×5×1×16 dlarray]
       Bias: [16×1 dlarray]

Просмотрите struct состояния.

state
state = struct with fields:
       batchnorm1: [1×1 struct]
       batchnorm2: [1×1 struct]
       batchnorm3: [1×1 struct]
    batchnormSkip: [1×1 struct]

Просмотрите параметры состояния для операции «batchnorm1».

state.batchnorm1
ans = struct with fields:
        TrainedMean: [16×1 single]
    TrainedVariance: [16×1 single]

Задайте функцию модели

Создайте функцию model, перечисленный в конце примера, который вычисляет выходы модели глубокого обучения, описанной ранее.

Функция model принимает параметры модели parameters, входные данные dlX, флаг doTraining который определяет, должна ли модель возвращать выходы для обучения или предсказания, и состояние сети state. Сеть выводит предсказания для меток, предсказания для углов и обновленное состояние сети.

Задайте функцию градиентов модели

Создайте функцию modelGradients, перечисленный в конце примера, который берёт параметры модели, мини-пакет входных данных dlX с соответствующими целями T1 и T2 содержит метки и углы, соответственно, и возвращает градиенты потерь относительно настраиваемых параметров, обновленного состояния сети и соответствующих потерь.

Настройка опций обучения

Задайте опции обучения. Обучайте на 20 эпох с мини-партией размером 128.

numEpochs = 20;
miniBatchSize = 128;

Чтобы контролировать процесс обучения, можно построить график потерь обучения после каждой итерации. Создайте переменные графики, которые содержат «процесс обучения». Если вы не хотите строить график процесса обучения, задайте для этого значения значение «none».

plots = "training-progress";

Обучите модель

Использование minibatchqueue для обработки и управления мини-пакетами изображений. Для каждого мини-пакета:

  • Используйте пользовательскую функцию мини-пакетной предварительной обработки preprocessMiniBatch (определено в конце этого примера), чтобы закодировать метки классов с одним «горячим» кодом.

  • Форматируйте данные изображения с помощью меток размерностей 'SSCB' (пространственный, пространственный, канальный, пакетный). По умолчанию в minibatchqueue объект преобразует данные в dlarray объекты с базовым типом single. Не добавляйте формат к меткам классов или углам.

  • Обучите на графическом процессоре, если он доступен. По умолчанию в minibatchqueue объект преобразует каждый выход в gpuArray при наличии графический процессор. Для использования графический процессор требуется Parallel Computing Toolbox™ и поддерживаемый графический процессор. Для получения информации о поддерживаемых устройствах смотрите Поддержку GPU by Release (Parallel Computing Toolbox).

mbq = minibatchqueue(dsTrain,...
    'MiniBatchSize',miniBatchSize,...
    'MiniBatchFcn', @preprocessMiniBatch,...
    'MiniBatchFormat',{'SSCB','',''});

Для каждой эпохи перетасуйте данные и закольцовывайте по мини-пакетам данных. В конце каждой итерации отобразите процесс обучения. Для каждого мини-пакета:

  • Оцените градиенты модели и потери с помощью dlfeval и modelGradients функция.

  • Обновляйте параметры сети с помощью adamupdate функция.

Инициализируйте параметры для Adam.

trailingAvg = [];
trailingAvgSq = [];

Инициализируйте график процесса обучения.

if plots == "training-progress"
    figure
    lineLossTrain = animatedline('Color',[0.85 0.325 0.098]);
    ylim([0 inf])
    xlabel("Iteration")
    ylabel("Loss")
    grid on
end

Обучите модель.

iteration = 0;
start = tic;

% Loop over epochs.
for epoch = 1:numEpochs
    
    % Shuffle data.
    shuffle(mbq)
    
    % Loop over mini-batches
    while hasdata(mbq)
    
        iteration = iteration + 1;
        
        [dlX,dlY1,dlY2] = next(mbq);
              
        % Evaluate the model gradients, state, and loss using dlfeval and the
        % modelGradients function.
        [gradients,state,loss] = dlfeval(@modelGradients, parameters, dlX, dlY1, dlY2, state);
        
        % Update the network parameters using the Adam optimizer.
        [parameters,trailingAvg,trailingAvgSq] = adamupdate(parameters,gradients, ...
            trailingAvg,trailingAvgSq,iteration);
        
        % Display the training progress.
        if plots == "training-progress"
            D = duration(0,0,toc(start),'Format','hh:mm:ss');
            addpoints(lineLossTrain,iteration,double(gather(extractdata(loss))))
            title("Epoch: " + epoch + ", Elapsed: " + string(D))
            drawnow
        end
    end
end

Экспериментальная модель

Протестируйте классификационную точность модели путем сравнения предсказаний на тестовом наборе с истинными метками и углами. Управление набором тестовых данных с помощью minibatchqueue объект с той же настройкой, что и обучающие данные.

[XTest,YTest,anglesTest] = digitTest4DArrayData;

dsXTest = arrayDatastore(XTest,'IterationDimension',4);
dsYTest = arrayDatastore(YTest);
dsAnglesTest = arrayDatastore(anglesTest);

dsTest = combine(dsXTest,dsYTest,dsAnglesTest);

mbqTest = minibatchqueue(dsTest,...
    'MiniBatchSize',miniBatchSize,...
    'MiniBatchFcn', @preprocessMiniBatch,...
    'MiniBatchFormat',{'SSCB','',''});

Чтобы предсказать метки и углы данных валидации, закольцовывайте мини-пакеты и используйте функцию модели с doTraining значение опции установлено в false. Сохраните предсказанные классы и углы. Сравните предсказанные и истинные классы и углы и сохраните результаты.

doTraining = false;

classesPredictions = [];
anglesPredictions = [];
classCorr = [];
angleDiff = [];

% Loop over mini-batches.
while hasdata(mbqTest)
    
    % Read mini-batch of data.
    [dlXTest,dlY1Test,dlY2Test] = next(mbqTest);
    
    % Make predictions using the predict function.
    [dlY1Pred,dlY2Pred] = model(parameters,dlXTest,doTraining,state);
    
    % Determine predicted classes.
    Y1PredBatch = onehotdecode(dlY1Pred,classNames,1);
    classesPredictions = [classesPredictions Y1PredBatch];
    
    % Dermine predicted angles
    Y2PredBatch = extractdata(dlY2Pred);
    anglesPredictions = [anglesPredictions Y2PredBatch];
    
    % Compare predicted and true classes
    Y1Test = onehotdecode(dlY1Test,classNames,1);
    classCorr = [classCorr Y1PredBatch == Y1Test];
    
    % Compare predicted and true angles
    angleDiffBatch = Y2PredBatch - dlY2Test;
    angleDiff = [angleDiff extractdata(gather(angleDiffBatch))];
    
end

Оцените точность классификации.

accuracy = mean(classCorr)
accuracy = 0.9730

Оцените точность регрессии.

angleRMSE = sqrt(mean(angleDiff.^2))
angleRMSE = single
    6.6909

Просмотрите некоторые изображения с их предсказаниями. Отображение прогнозируемых углов красного цвета и правильных меток зеленого цвета.

idx = randperm(size(XTest,4),9);
figure
for i = 1:9
    subplot(3,3,i)
    I = XTest(:,:,:,idx(i));
    imshow(I)
    hold on
    
    sz = size(I,1);
    offset = sz/2;
    
    thetaPred = anglesPredictions(idx(i));
    plot(offset*[1-tand(thetaPred) 1+tand(thetaPred)],[sz 0],'r--')
    
    thetaValidation = anglesTest(idx(i));
    plot(offset*[1-tand(thetaValidation) 1+tand(thetaValidation)],[sz 0],'g--')
    
    hold off
    label = string(classesPredictions(idx(i)));
    title("Label: " + label)
end

Моделируйте функцию

Функция model принимает параметры модели parameters, входные данные dlX, флаг doTraining который определяет, должна ли модель возвращать выходы для обучения или предсказания, и состояние сети state. Сеть выводит предсказания для меток, предсказания для углов и обновленное состояние сети.

function [dlY1,dlY2,state] = model(parameters,dlX,doTraining,state)

% Convolution
weights = parameters.conv1.Weights;
bias = parameters.conv1.Bias;
dlY = dlconv(dlX,weights,bias,'Padding','same');

% Batch normalization, ReLU
offset = parameters.batchnorm1.Offset;
scale = parameters.batchnorm1.Scale;
trainedMean = state.batchnorm1.TrainedMean;
trainedVariance = state.batchnorm1.TrainedVariance;

if doTraining
    [dlY,trainedMean,trainedVariance] = batchnorm(dlY,offset,scale,trainedMean,trainedVariance);
    
    % Update state
    state.batchnorm1.TrainedMean = trainedMean;
    state.batchnorm1.TrainedVariance = trainedVariance;
else
    dlY = batchnorm(dlY,offset,scale,trainedMean,trainedVariance);
end

dlY = relu(dlY);

% Convolution, batch normalization (Skip connection)
weights = parameters.convSkip.Weights;
bias = parameters.convSkip.Bias;
dlYSkip = dlconv(dlY,weights,bias,'Stride',2);

offset = parameters.batchnormSkip.Offset;
scale = parameters.batchnormSkip.Scale;
trainedMean = state.batchnormSkip.TrainedMean;
trainedVariance = state.batchnormSkip.TrainedVariance;

if doTraining
    [dlYSkip,trainedMean,trainedVariance] = batchnorm(dlYSkip,offset,scale,trainedMean,trainedVariance);
    
    % Update state
    state.batchnormSkip.TrainedMean = trainedMean;
    state.batchnormSkip.TrainedVariance = trainedVariance;
else
    dlYSkip = batchnorm(dlYSkip,offset,scale,trainedMean,trainedVariance);
end

% Convolution
weights = parameters.conv2.Weights;
bias = parameters.conv2.Bias;
dlY = dlconv(dlY,weights,bias,'Padding','same','Stride',2);

% Batch normalization, ReLU
offset = parameters.batchnorm2.Offset;
scale = parameters.batchnorm2.Scale;
trainedMean = state.batchnorm2.TrainedMean;
trainedVariance = state.batchnorm2.TrainedVariance;

if doTraining
    [dlY,trainedMean,trainedVariance] = batchnorm(dlY,offset,scale,trainedMean,trainedVariance);
    
    % Update state
    state.batchnorm2.TrainedMean = trainedMean;
    state.batchnorm2.TrainedVariance = trainedVariance;
else
    dlY = batchnorm(dlY,offset,scale,trainedMean,trainedVariance);
end

dlY = relu(dlY);

% Convolution
weights = parameters.conv3.Weights;
bias = parameters.conv3.Bias;
dlY = dlconv(dlY,weights,bias,'Padding','same');

% Batch normalization
offset = parameters.batchnorm3.Offset;
scale = parameters.batchnorm3.Scale;
trainedMean = state.batchnorm3.TrainedMean;
trainedVariance = state.batchnorm3.TrainedVariance;

if doTraining
    [dlY,trainedMean,trainedVariance] = batchnorm(dlY,offset,scale,trainedMean,trainedVariance);
    
    % Update state
    state.batchnorm3.TrainedMean = trainedMean;
    state.batchnorm3.TrainedVariance = trainedVariance;
else
    dlY = batchnorm(dlY,offset,scale,trainedMean,trainedVariance);
end

% Addition, ReLU
dlY = dlYSkip + dlY;
dlY = relu(dlY);

% Fully connect, softmax (labels)
weights = parameters.fc1.Weights;
bias = parameters.fc1.Bias;
dlY1 = fullyconnect(dlY,weights,bias);
dlY1 = softmax(dlY1);

% Fully connect (angles)
weights = parameters.fc2.Weights;
bias = parameters.fc2.Bias;
dlY2 = fullyconnect(dlY,weights,bias);

end

Функция градиентов модели

The modelGradients function, принимает параметры модели, мини-пакет входных данных dlX с соответствующими целями T1 и T2 содержит метки и углы, соответственно, и возвращает градиенты потерь относительно настраиваемых параметров, обновленного состояния сети и соответствующих потерь.

function [gradients,state,loss] = modelGradients(parameters,dlX,T1,T2,state)

doTraining = true;
[dlY1,dlY2,state] = model(parameters,dlX,doTraining,state);

lossLabels = crossentropy(dlY1,T1);
lossAngles = mse(dlY2,T2);

loss = lossLabels + 0.1*lossAngles;
gradients = dlgradient(loss,parameters);

end

Функция мини-пакетной предварительной обработки

The preprocessMiniBatch функция предварительно обрабатывает данные с помощью следующих шагов:

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

  2. Извлеките данные о метках и углах из входящих массивов ячеек и соедините вдоль второго измерения в категориальный массив и числовой массив, соответственно.

  3. Однократное кодирование категориальных меток в числовые массивы. Кодирование в первую размерность создает закодированный массив, который совпадает с формой выходного сигнала сети.

function [X,Y,angle] = preprocessMiniBatch(XCell,YCell,angleCell)
    
    % Extract image data from cell and concatenate
    X = cat(4,XCell{:});
    % Extract label data from cell and concatenate
    Y = cat(2,YCell{:});
    % Extract angle data from cell and concatenate
    angle = cat(2,angleCell{:});
        
    % One-hot encode labels
    Y = onehotencode(Y,1);
        
end

См. также

| | | | | | | | | | | |

Похожие темы