В этом примере показано, как создать и обучить нейронную сеть для глубокого обучения при помощи функций, а не графика слоев или dlnetwork
. Преимуществом использования функций является гибкость, чтобы описать большое разнообразие сетей. Недостаток - то, что необходимо завершить больше шагов и подготовить данные тщательно. Этот пример использует изображения рукописных цифр с двойными целями классификации цифр и определения угла каждой цифры от вертикали.
digitTrain4DArrayData
функционируйте загружает изображения, их метки цифры и их углы вращения от вертикали.
[XTrain,YTrain,anglesTrain] = digitTrain4DArrayData; classNames = categories(YTrain); numClasses = numel(classNames); numObservations = numel(YTrain);
Просмотрите некоторые изображения от обучающих данных.
idx = randperm(numObservations,64); I = imtile(XTrain(:,:,:,idx)); figure imshow(I)
Задайте следующую сеть, которая предсказывает и метки и углы вращения.
convolution-batchnorm-ReLU блокируется с 16 фильтрами 5 на 5.
Ветвь двух блоков свертки-batchnorm каждый с 32 3х3 фильтрами с операцией ReLU между
Связь пропуска со сверткой-batchnorm блокируется с 32 свертками 1 на 1.
Объедините обе ветви с помощью сложения, сопровождаемого операцией ReLU
Для регрессии выход, ветвь с полностью связанной операцией размера 1 (количество ответов).
Для классификации выход, ветвь с полностью связанной операцией размера 10 (количество классов) и softmax операцией.
Задайте параметры для каждой из операций и включайте их в struct. Используйте формат parameters.OperationName.ParameterName
где parameters
struct, OperationName
имя операции (например, "conv_1") и ParameterName
имя параметра (например, "Веса").
Создайте struct parameters
содержа параметры модели. Инициализируйте learnable веса слоя с помощью функции, взятой в качестве примера, initializeGaussian
, перечисленный в конце примера. Инициализируйте learnable смещения слоя нулями. Инициализируйте смещение нормализации партии. и масштабные коэффициенты с нулями и единицами, соответственно.
Чтобы выполнить обучение и вывод с помощью слоев нормализации партии., необходимо также управлять сетевым состоянием. Перед предсказанием необходимо задать среднее значение набора данных и отклонение, выведенное из обучающих данных. Создайте struct state
содержа параметры состояния. Инициализируйте нормализацию партии. обученное среднее значение и обученные состояния отклонения с нулями и единицами, соответственно.
parameters.conv1.Weights = dlarray(initializeGaussian([5,5,1,16])); parameters.conv1.Bias = dlarray(zeros(16,1,'single')); parameters.batchnorm1.Offset = dlarray(zeros(16,1,'single')); parameters.batchnorm1.Scale = dlarray(ones(16,1,'single')); state.batchnorm1.TrainedMean = zeros(16,1,'single'); state.batchnorm1.TrainedVariance = ones(16,1,'single'); parameters.convSkip.Weights = dlarray(initializeGaussian([1,1,16,32])); parameters.convSkip.Bias = dlarray(zeros(32,1,'single')); parameters.batchnormSkip.Offset = dlarray(zeros(32,1,'single')); parameters.batchnormSkip.Scale = dlarray(ones(32,1,'single')); state.batchnormSkip.TrainedMean = zeros(32,1,'single'); state.batchnormSkip.TrainedVariance = ones(32,1,'single'); parameters.conv2.Weights = dlarray(initializeGaussian([3,3,16,32])); parameters.conv2.Bias = dlarray(zeros(32,1,'single')); parameters.batchnorm2.Offset = dlarray(zeros(32,1,'single')); parameters.batchnorm2.Scale = dlarray(ones(32,1,'single')); state.batchnorm2.TrainedMean = zeros(32,1,'single'); state.batchnorm2.TrainedVariance = ones(32,1,'single'); parameters.conv3.Weights = dlarray(initializeGaussian([3,3,32,32])); parameters.conv3.Bias = dlarray(zeros(32,1,'single')); parameters.batchnorm3.Offset = dlarray(zeros(32,1,'single')); parameters.batchnorm3.Scale = dlarray(ones(32,1,'single')); state.batchnorm3.TrainedMean = zeros(32,1,'single'); state.batchnorm3.TrainedVariance = ones(32,1,'single'); parameters.fc2.Weights = dlarray(initializeGaussian([10,6272])); parameters.fc2.Bias = dlarray(zeros(numClasses,1,'single')); parameters.fc1.Weights = dlarray(initializeGaussian([1,6272])); parameters.fc1.Bias = dlarray(zeros(1,1,'single'));
Просмотрите struct параметров.
parameters
parameters = struct with fields:
conv1: [1×1 struct]
batchnorm1: [1×1 struct]
convSkip: [1×1 struct]
batchnormSkip: [1×1 struct]
conv2: [1×1 struct]
batchnorm2: [1×1 struct]
conv3: [1×1 struct]
batchnorm3: [1×1 struct]
fc2: [1×1 struct]
fc1: [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]
batchnormSkip: [1×1 struct]
batchnorm2: [1×1 struct]
batchnorm3: [1×1 struct]
Просмотрите параметры состояния для "batchnorm1" операции.
state.batchnorm1
ans = struct with fields:
TrainedMean: [16×1 single]
TrainedVariance: [16×1 single]
Создайте функциональный model
, перечисленный в конце примера, который вычисляет выходные параметры модели глубокого обучения, описанной ранее.
Функциональный model
берет входные данные dlX
, параметры модели parameters
, флаг doTraining
который задает, должен ли к модели возвратить выходные параметры для обучения или предсказания и сетевого state
состояния. Сетевые выходные параметры предсказания для меток, предсказания для углов и обновленное сетевое состояние.
Создайте функциональный modelGradients
, перечисленный в конце примера, который берет мини-пакет входных данных dlX
с соответствующими целями T1
и T2
содержание меток и углов, соответственно, и возвращает градиенты потери относительно настраиваемых параметров, обновленного сетевого состояния и соответствующей потери.
Задайте опции обучения.
numEpochs = 20;
miniBatchSize = 128;
plots = "training-progress";
numIterationsPerEpoch = floor(numObservations./miniBatchSize);
Обучайтесь на графическом процессоре, если вы доступны. Это требует Parallel Computing Toolbox™. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA®, графический процессор с вычисляет возможность 3.0 или выше.
executionEnvironment = "auto";
Обучите модель с помощью пользовательского учебного цикла.
В течение каждой эпохи переставьте данные и цикл по мини-пакетам данных. В конце каждой эпохи отобразите прогресс обучения.
Для каждого мини-пакета:
Преобразуйте метки в фиктивные переменные.
Преобразуйте данные в dlarray
объекты с базовым одним типом и указывают, что размерность маркирует 'SSCB'
(пространственный, пространственный, канал, пакет).
Для обучения графического процессора преобразуйте в gpuArray
объекты.
Оцените градиенты модели и потерю с помощью dlfeval
и modelGradients
функция.
Обновите сетевые параметры с помощью adamupdate
функция.
Инициализируйте график процесса обучения.
if plots == "training-progress" figure lineLossTrain = animatedline('Color',[0.85 0.325 0.098]); ylim([0 inf]) xlabel("Iteration") ylabel("Loss") grid on end
Инициализируйте параметры для Адама.
trailingAvg = []; trailingAvgSq = [];
Обучите модель.
iteration = 0; start = tic; % Loop over epochs. for epoch = 1:numEpochs % Shuffle data. idx = randperm(numObservations); XTrain = XTrain(:,:,:,idx); YTrain = YTrain(idx); anglesTrain = anglesTrain(idx); % Loop over mini-batches for i = 1:numIterationsPerEpoch iteration = iteration + 1; idx = (i-1)*miniBatchSize+1:i*miniBatchSize; % Read mini-batch of data and convert the labels to dummy % variables. X = XTrain(:,:,:,idx); Y1 = zeros(numClasses, miniBatchSize, 'single'); for c = 1:numClasses Y1(c,YTrain(idx)==classNames(c)) = 1; end Y2 = anglesTrain(idx)'; Y2 = single(Y2); % Convert mini-batch of data to dlarray. dlX = dlarray(X,'SSCB'); % If training on a GPU, then convert data to gpuArray. if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu" dlX = gpuArray(dlX); end % Evaluate the model gradients, state, and loss using dlfeval and the % modelGradients function. [gradients,state,loss] = dlfeval(@modelGradients, dlX, Y1, Y2, parameters, 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
Протестируйте точность классификации модели путем сравнения предсказаний на наборе тестов с истинными метками и углами
[XTest,YTest,anglesTest] = digitTest4DArrayData;
Преобразуйте данные в dlarray
объект с форматом размерности 'SSCB'
. Для предсказания графического процессора также преобразуйте данные в gpuArray
.
dlXTest = dlarray(XTest,'SSCB'); if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu" dlXTest = gpuArray(dlXTest); end
Чтобы предсказать метки и углы данных о валидации, используйте функцию модели с doTraining
набор опции к false
.
doTraining = false; [dlYPred,anglesPred] = model(dlXTest, parameters,doTraining,state);
Оцените точность классификации.
[~,idx] = max(extractdata(dlYPred),[],1); labelsPred = classNames(idx); accuracy = mean(labelsPred==YTest)
accuracy = 0.9852
Оцените точность регрессии.
angleRMSE = sqrt(mean((extractdata(anglesPred) - anglesTest').^2))
angleRMSE = gpuArray single 10.4900
Просмотрите некоторые изображения с их предсказаниями. Отобразите предсказанные углы красного цвета и правильные метки зеленого цвета.
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 = extractdata(anglesPred(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(labelsPred(idx(i))); title("Label: " + label) end
Функциональный model
берет входные данные dlX
, параметры модели parameters
, флаг doTraining
который задает, должен ли к модели возвратить выходные параметры для обучения или предсказания и сетевого state
состояния. Сетевые выходные параметры предсказания для меток, предсказания для углов и обновленное сетевое состояние.
function [dlY1,dlY2,state] = model(dlX,parameters,doTraining,state) % Convolution weights = parameters.conv1.Weights; bias = parameters.conv1.Bias; dlY = dlconv(dlX,weights,bias,'Padding',2); % 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',1,'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',1); % 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 (angles) weights = parameters.fc1.Weights; bias = parameters.fc1.Bias; dlY2 = fullyconnect(dlY,weights,bias); % Fully connect, softmax (labels) weights = parameters.fc2.Weights; bias = parameters.fc2.Bias; dlY1 = fullyconnect(dlY,weights,bias); dlY1 = softmax(dlY1); end
modelGradients
функция, берет мини-пакет входных данных dlX
с соответствующими целями T1
и T2
содержание меток и углов, соответственно, и возвращает градиенты потери относительно настраиваемых параметров, обновленного сетевого состояния и соответствующей потери.
function [gradients,state,loss] = modelGradients(dlX,T1,T2,parameters,state) doTraining = true; [dlY1,dlY2,state] = model(dlX,parameters,doTraining,state); lossLabels = crossentropy(dlY1,T1); lossAngles = mse(dlY2,T2); loss = lossLabels + 0.1*lossAngles; gradients = dlgradient(loss,parameters); end
initializeGaussian
функциональные демонстрационные веса от Распределения Гаусса со средним значением 0 и стандартным отклонением 0.01.
function parameter = initializeGaussian(sz) parameter = randn(sz,'single').*0.01; end
batchnorm
| crossentropy
| dlarray
| dlconv
| dlfeval
| dlgradient
| fullyconnect
| relu
| sgdmupdate
| softmax