Если Deep Learning Toolbox™ не обеспечивает слой, вы требуете для своей классификации или проблемы регрессии, то можно задать собственный слой с помощью этого примера в качестве руководства. Для списка встроенных слоев смотрите Список слоев глубокого обучения.
Чтобы задать пользовательский слой глубокого обучения, можно использовать шаблон, обеспеченный в этом примере, который берет вас через следующие шаги:
Назовите слой – дают слою имя так, чтобы это могло использоваться в MATLAB®.
Объявите, что свойства слоя – задают свойства слоя и какие параметры изучены во время обучения.
Создайте (дополнительную) функцию конструктора – задают, как создать слой и инициализировать его свойства. Если вы не задаете функцию конструктора, то при создании, программное обеспечение инициализирует Name
, Description
и свойства Type
с []
и определяет номер вводов и выводов слоя к 1.
Создайте прямые функции – задают, как данные передают вперед через слой (прямое распространение) во время прогноза и в учебное время.
Создайте обратную функцию – задают производные потери относительно входных данных и learnable параметров (обратное распространение).
Этот пример показывает, как создать слой PReLU, который является слоем с learnable параметром, и используйте его в сверточной нейронной сети. Слой PReLU выполняет пороговую операцию, где для каждого канала, любое входное значение меньше, чем нуль умножаются на скаляр, изученный в учебное время. [1] Для значений меньше, чем нуль, слой PReLU применяет масштабные коэффициенты к каждому каналу входа. Эти коэффициенты формируют learnable параметр, который слой изучает во время обучения.
Эта фигура от [1] сравнивает функции уровня ReLU и PReLU.
Скопируйте слой с learnable шаблоном параметров в новый файл в MATLAB. Этот шаблон обрисовывает в общих чертах структуру слоя с learnable параметрами и включает функции, которые задают поведение слоя.
classdef myLayer < nnet.layer.Layer properties % (Optional) Layer properties. % Layer properties go here. end properties (Learnable) % (Optional) Layer learnable parameters. % Layer learnable parameters go here. end methods function layer = myLayer() % (Optional) Create a myLayer. % This function must have the same name as the class. % Layer constructor function goes here. end function [Z1, …, Zm] = predict(layer, X1, …, Xn) % Forward input data through the layer at prediction time and % output the result. % % Inputs: % layer - Layer to forward propagate through % X1, ..., Xn - Input data % Outputs: % Z1, ..., Zm - Outputs of layer forward function % Layer forward function for prediction goes here. end function [Z1, …, Zm, memory] = forward(layer, X1, …, Xn) % (Optional) Forward input data through the layer at training % time and output the result and a memory value. % % Inputs: % layer - Layer to forward propagate through % X1, ..., Xn - Input data % Outputs: % Z1, ..., Zm - Outputs of layer forward function % memory - Memory value for backward propagation % Layer forward function for training goes here. end function [dLdX1, …, dLdXn, dLdW1, …, dLdWk] = ... backward(layer, X1, …, Xn, Z1, …, Zm, dLdZ1, …, dLdZm, memory) % Backward propagate the derivative of the loss function through % the layer. % % Inputs: % layer - Layer to backward propagate through % X1, ..., Xn - Input data % Z1, ..., Zm - Outputs of layer forward function % dLdZ1, ..., dLdZm - Gradients propagated from the next layers % memory - Memory value from forward function % Outputs: % dLdX1, ..., dLdXn - Derivatives of the loss with respect to the % inputs % dLdW1, ..., dLdWk - Derivatives of the loss with respect to each % learnable parameter % Layer backward function goes here. end end end
Во-первых, дайте слою имя. В первой строке файла класса замените существующее имя myLayer
на preluLayer
.
classdef preluLayer < nnet.layer.Layer ... end
Затем, переименуйте функцию конструктора myLayer
(первая функция в разделе methods
) так, чтобы это имело то же имя как слой.
methods function layer = preluLayer() ... end ... end
Сохраните файл класса слоя в новом файле с именем preluLayer.m
. Имя файла должно совпадать с именем слоя. Чтобы использовать слой, необходимо сохранить файл в текущей папке или в папке на пути MATLAB.
Объявите свойства слоя в разделе properties
и объявите learnable параметры путем листинга их в разделе properties (Learnable)
.
По умолчанию пользовательские промежуточные слои имеют эти свойства:
Свойство | Описание |
---|---|
Name |
Имя слоя, заданное как вектор символов или скаляр строки. Чтобы включать слой в график слоя, необходимо задать непустое уникальное имя слоя. Если вы обучаете серийную сеть со слоем, и Name установлен в '' , то программное обеспечение автоматически присваивает имя к слою в учебное время.
|
Description | Короткое описание слоя, заданного как вектор символов или скаляр строки. Это описание появляется, когда слой отображен в массиве |
Type | Тип слоя, заданного как вектор символов или скаляр строки. Значение Type появляется, когда слой отображен в массиве Layer . Если вы не задаете тип слоя, то программное обеспечение отображает имя класса слоя. |
NumInputs | Количество входных параметров слоя, заданного как положительное целое число. Если вы не задаете это значение, то программное обеспечение автоматически устанавливает NumInputs на количество имен в InputNames . Значение по умолчанию равняется 1. |
InputNames | Входные имена слоя, заданного как массив ячеек из символьных векторов. Если вы не задаете это значение, и NumInputs больше, чем 1, то программное обеспечение автоматически устанавливает InputNames на {'in1',...,'inN'} , где N равен NumInputs . Значением по умолчанию является {'in'} . |
NumOutputs | Количество выходных параметров слоя, заданного как положительное целое число. Если вы не задаете это значение, то программное обеспечение автоматически устанавливает NumOutputs на количество имен в OutputNames . Значение по умолчанию равняется 1. |
OutputNames | Выходные имена слоя, заданного как массив ячеек из символьных векторов. Если вы не задаете это значение, и NumOutputs больше, чем 1, то программное обеспечение автоматически устанавливает OutputNames на {'out1',...,'outM'} , где M равен NumOutputs . Значением по умолчанию является {'out'} . |
Если слой не имеет никаких других свойств, то можно не использовать раздел properties
.
Если вы создаете слой с несколькими входными параметрами, то необходимо установить или NumInputs
или InputNames
в конструкторе слоя. Если вы создаете слой с несколькими выходными параметрами, то необходимо установить или NumOutputs
или OutputNames
в конструкторе слоя. Для примера смотрите, Задают Пользовательский Слой Глубокого обучения с Несколькими Входными параметрами.
Слой PReLU не требует никаких дополнительных свойств, таким образом, можно удалить раздел properties
.
Слой PReLU имеет только один learnable параметр, масштабирующийся коэффициент a. Объявите этот learnable параметр в разделе properties (Learnable)
и вызовите параметр Alpha
.
properties (Learnable)
% Layer learnable parameters
% Scaling coefficient
Alpha
end
Создайте функцию, которая создает слой и инициализирует свойства слоя. Задайте любые переменные, требуемые создать слой как входные параметры к функции конструктора.
Функция конструктора слоя PReLU требует двух входных аргументов: количество каналов ожидаемых входных данных и имени слоя. Количество каналов задает размер learnable параметра Alpha
. Задайте два входных параметра под названием numChannels
и name
в функции preluLayer
. Добавьте комментарий в верхнюю часть функции, которая объясняет синтаксис функции.
function layer = preluLayer(numChannels, name) % layer = preluLayer(numChannels) creates a PReLU layer with % numChannels channels and specifies the layer name. ... end
Инициализируйте свойства слоя, включая learnable параметры в функции конструктора. Замените комментарий % Layer constructor function goes here
на код, который инициализирует свойства слоя.
Установите свойство Name
на входной параметр name
.
% Set layer name.
layer.Name = name;
Дайте слою короткое описание путем установки свойства Description
слоя. Установите описание описывать тип слоя и его размера.
% Set layer description. layer.Description = "PReLU with " + numChannels + " channels";
Для слоя PReLU, когда входные значения отрицательны, слой умножает каждый канал входа соответствующим каналом Alpha
. Инициализируйте learnable параметр Alpha
, чтобы быть случайным вектором размера 1 1 numChannels
. С третьей размерностью, заданной как размер numChannels
, слой может использовать поэлементное умножение входа в прямой функции. Alpha
является свойством расположенного на слое объекта, таким образом, необходимо присвоить вектор layer.Alpha
.
% Initialize scaling coefficient.
layer.Alpha = rand([1 1 numChannels]);
Просмотрите завершенную функцию конструктора.
function layer = preluLayer(numChannels, name)
% layer = preluLayer(numChannels, name) creates a PReLU layer
% with numChannels channels and specifies the layer name.
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "PReLU with " + numChannels + " channels";
% Initialize scaling coefficient.
layer.Alpha = rand([1 1 numChannels]);
end
С этой функцией конструктора команда preluLayer(3,'prelu')
создает слой PReLU с тремя каналами и именем 'prelu'
.
Создайте слой вперед функции, чтобы использовать во время прогноза и учебное время.
Создайте функцию с именем predict
, который распространяет данные вперед через слой во время прогноза и выводит результат.
Синтаксис для predict
[Z1,…,Zm] = predict(layer,X1,…,Xn)
X1,…,Xn
является входными параметрами слоя n
, и Z1,…,Zm
слой m
выходные параметры. Значения n
и m
должны соответствовать свойствам NumInputs
и NumOutputs
слоя.Если количество входных параметров к predict
может отличаться, то используйте varargin
вместо X1,…,Xn
. В этом случае varargin
является массивом ячеек входных параметров, где varargin{i}
соответствует Xi
. Если количество выходных параметров может отличаться, то используйте varargout
вместо Z1,…,Zm
. В этом случае varargout
является массивом ячеек выходных параметров, где varargout{j}
соответствует Zj
.
Поскольку слой PReLU имеет только один вход и один вывод, синтаксисом для predict
для слоя PReLU является Z = predict(layer,X)
.
По умолчанию слой использует predict
в качестве прямой функции в учебное время. Использовать различную прямую функцию в учебное время или сохранить значение потребовали для обратной функции, необходимо также создать функцию с именем forward
.
Размерности входных параметров зависят от типа данных и вывода связанных слоев:
Вход слоя | Введите размер | Размерность наблюдения |
---|---|---|
2D изображения | h-by-w-by-c-by-N, где h, w и c соответствуют высоте, ширине, и количеству каналов изображений соответственно и N, является количеством наблюдений. | 4 |
3-D изображения | h-by-w-by-D-by-c-by-N, где h, w, D и c соответствуют высоте, ширине, глубине, и количеству каналов 3-D изображений соответственно и N, является количеством наблюдений. | 5 |
Векторные последовательности | c-by-N-by-S, где c является количеством функций последовательностей, N, является количеством наблюдений, и S является длиной последовательности. | 2 |
2D последовательности изображений | h-by-w-by-c-by-N-by-S, где h, w и c соответствуют высоте, ширине и количеству каналов изображений соответственно, N, является количеством наблюдений, и S является длиной последовательности. | 4 |
3-D последовательности изображений | h-by-w-by-d-by-c-by-N-by-S, где h, w, d и c соответствуют высоте, ширине, глубине и количеству каналов 3-D изображений соответственно, N, является количеством наблюдений, и S является длиной последовательности. | 5 |
Функция forward
распространяет данные вперед через слой в учебное время и также выводит значение памяти.
Синтаксис для forward
[Z1,…,Zm,memory] = forward(layer,X1,…,Xn)
X1,…,Xn
является входными параметрами слоя n
, Z1,…,Zm
слой m
выходные параметры, и memory
является памятью о слое.Если количество входных параметров к forward
может отличаться, то используйте varargin
вместо X1,…,Xn
. В этом случае varargin
является массивом ячеек входных параметров, где varargin{i}
соответствует Xi
. Если количество выходных параметров может отличаться, то используйте varargout
вместо Z1,…,Zm
. В этом случае varargout
является массивом ячеек выходных параметров, где varargout{j}
соответствует Zj
для j
=1, …, NumOutputs
и varargout{NumOutputs+1}
соответствуют memory
.
Операцией PReLU дают
где вход нелинейной активации f на канале i, и коэффициент, управляющий наклоном отрицательной части. Нижний i в указывает, что нелинейная активация может отличаться на различных каналах.
Реализуйте эту операцию в predict
. В predict
вход X
соответствует x в уравнении. Вывод Z
соответствует . Слой PReLU не требует памяти или различной прямой функции для обучения, таким образом, можно удалить функцию forward
из файла класса. Добавьте комментарий в верхнюю часть функции, которая объясняет синтаксисы функции.
function Z = predict(layer, X)
% Z = predict(layer, X) forwards the input data X through the
% layer and outputs the result Z.
Z = max(0, X) + layer.Alpha .* min(0, X);
end
Реализуйте производные потери относительно входных данных и learnable параметров в функции backward
.
Синтаксис для backward
[dLdX1,…,dLdXn,dLdW1,…,dLdWk] = backward(layer,X1,…,Xn,Z1,…,Zm,dLdZ1,…,dLdZm,memory)
X1,…,Xn
является входными параметрами слоя n
, Z1,…,Zm
m
выходные параметры forward
, dLdZ1,…,dLdZm
является градиентами, назад распространенными от следующего слоя, и memory
является вывод memory forward
. Для выходных параметров dLdX1,…,dLdXn
является производными потери относительно входных параметров слоя, и dLdW1,…,dLdWk
производные потери относительно k
learnable параметры. Чтобы уменьшать использование памяти путем предотвращения неиспользуемых переменных, являющихся сохраненным между прямым и обратным проходом, замените соответствующие входные параметры на ~
.Если количество входных параметров к backward
может отличаться, то используйте varargin
вместо входных параметров после layer
. В этом случае varargin
является массивом ячеек входных параметров, где varargin{i}
соответствует Xi
для i
=1, …, NumInputs
, varargin{NumInputs+j}
и varargin{NumInputs+NumOutputs+j}
соответствуют Zj
и dLdZj
, соответственно, для j
=1, …, NumOutputs
, и varargin{end}
соответствует memory
.
Если количество выходных параметров может отличаться, то используйте varargout
вместо выходных аргументов. В этом случае varargout
является массивом ячеек выходных параметров, где varargout{i}
соответствует dLdXi
для i
=1, …, NumInputs
и varargout{NumInputs+t}
соответствуют dLdWt
для t
=1, …, k
, где k
является количеством learnable параметров.
Поскольку слой PReLU имеет только один вход, один вывод и один learnable параметр, синтаксисом для backward
для слоя PReLU является [dLdX,dLdAlpha] = backward(layer,X,Z,dLdZ,memory)
. Размерности X
и Z
эквивалентны в прямых функциях. Размерности dLdZ
совпадают с размерностями Z
. Размерности и тип данных dLdX
совпадают с размерностями и типом данных X
. Размерность и тип данных dLdAlpha
совпадают с размерностью и типом данных learnable параметра Alpha
.
Во время обратного прохода слой автоматически обновляет learnable параметры с помощью соответствующих производных.
Чтобы включать пользовательский слой в сеть, слой, прямые функции должны принять выходные параметры предыдущего слоя и вперед распространить массивы с размером, ожидаемым следующим слоем. Точно так же backward
должен принять входные параметры с тем же размером как соответствующий вывод прямой функции и назад распространить производные с тем же размером.
Производная потери относительно входных данных
где градиент, распространенный от следующего слоя, и производная активации
Производная потери относительно learnable параметров
где i индексирует каналы, j индексирует элементы по высоте, ширине и наблюдениям, и градиент, распространенный от более глубокого слоя, и градиент активации
В backward
шаблона слоя замените вывод dLdW
на вывод dLdAlpha
, где dLdAlpha
соответствует . В backward
вход X
соответствует x. Вход Z
соответствует . Вход dLdZ
соответствует . Вывод dLdX
соответствует .
Добавьте комментарий в верхнюю часть функции, которая объясняет синтаксисы функции. Чтобы уменьшать использование памяти путем предотвращения неиспользуемых переменных, являющихся сохраненным между прямым и обратным проходом, замените соответствующие входные параметры на ~
. Поскольку функция уровня не требует входных параметров Z
и memory
, замените эти аргументы на ~
.
function [dLdX, dLdAlpha] = backward(layer, X, ~, dLdZ, ~)
% [dLdX, dLdAlpha] = backward(layer, X, ~, dLdZ, ~)
% backward propagates the derivative of the loss function
% through the layer.
% Inputs:
% layer - Layer to backward propagate through
% X - Input data
% dLdZ - Gradient propagated from the deeper layer
% Outputs:
% dLdX - Derivative of the loss with respect to the
% input data
% dLdAlpha - Derivative of the loss with respect to the
% learnable parameter Alpha
dLdX = layer.Alpha .* dLdZ;
dLdX(X>0) = dLdZ(X>0);
dLdAlpha = min(0,X) .* dLdZ;
dLdAlpha = sum(sum(dLdAlpha,1),2);
% Sum over all observations in mini-batch.
dLdAlpha = sum(dLdAlpha,4);
end
Просмотрите завершенный файл класса слоя.
classdef preluLayer < nnet.layer.Layer % Example custom PReLU layer. properties (Learnable) % Layer learnable parameters % Scaling coefficient Alpha end methods function layer = preluLayer(numChannels, name) % layer = preluLayer(numChannels, name) creates a PReLU layer % with numChannels channels and specifies the layer name. % Set layer name. layer.Name = name; % Set layer description. layer.Description = "PReLU with " + numChannels + " channels"; % Initialize scaling coefficient. layer.Alpha = rand([1 1 numChannels]); end function Z = predict(layer, X) % Z = predict(layer, X) forwards the input data X through the % layer and outputs the result Z. Z = max(0, X) + layer.Alpha .* min(0, X); end function [dLdX, dLdAlpha] = backward(layer, X, ~, dLdZ, ~) % [dLdX, dLdAlpha] = backward(layer, X, ~, dLdZ, ~) % backward propagates the derivative of the loss function % through the layer. % Inputs: % layer - Layer to backward propagate through % X - Input data % dLdZ - Gradient propagated from the deeper layer % Outputs: % dLdX - Derivative of the loss with respect to the % input data % dLdAlpha - Derivative of the loss with respect to the % learnable parameter Alpha dLdX = layer.Alpha .* dLdZ; dLdX(X>0) = dLdZ(X>0); dLdAlpha = min(0,X) .* dLdZ; dLdAlpha = sum(sum(dLdAlpha,1),2); % Sum over all observations in mini-batch. dLdAlpha = sum(dLdAlpha,4); end end end
Для совместимости графического процессора функции уровня должны поддержать входные параметры и возвратить выходные параметры типа gpuArray
. Любые другие функции использование слоя должны сделать то же самое. Много встроенных функций MATLAB поддерживают входные параметры gpuArray
. Если вы вызываете какую-либо из этих функций по крайней мере с одним входом gpuArray
, то функция выполняется на графическом процессоре и возвращает gpuArray
вывод. Для списка функций, которые выполняются на графическом процессоре, смотрите функции MATLAB Выполнения на графическом процессоре (Parallel Computing Toolbox). Чтобы использовать графический процессор для глубокого обучения, у вас должен также быть CUDA®, включенный NVIDIA®, графический процессор с вычисляет возможность 3.0 или выше. Для получения дополнительной информации о работе с графическими процессорами в MATLAB смотрите, что графический процессор Вычисляет в MATLAB (Parallel Computing Toolbox).
Функции MATLAB использовали в predict
, forward
и backward
вся поддержка входные параметры gpuArray
, таким образом, слоем является совместимый графический процессор.
checkLayer
Проверяйте валидность слоя пользовательского слоя preluLayer
.
Задайте пользовательский слой PReLU. Чтобы создать этот слой, сохраните файл preluLayer.m
в текущей папке.
Создайте экземпляр слоя и проверяйте его валидность с помощью checkLayer
. Задайте допустимый входной размер, чтобы быть размером одного наблюдения за типичным входом к слою. Слой ожидает 4-D входные параметры массивов, где первые три измерения соответствуют высоте, ширине и количеству каналов предыдущего слоя вывод, и четвертая размерность соответствует наблюдениям.
Задайте типичный размер входа наблюдения и установите 'ObservationDimension'
на 4.
layer = preluLayer(20,'prelu'); validInputSize = [24 24 20]; checkLayer(layer,validInputSize,'ObservationDimension',4)
Skipping GPU tests. No compatible GPU device found. Running nnet.checklayer.TestCase .......... ........ Done nnet.checklayer.TestCase __________ Test Summary: 18 Passed, 0 Failed, 0 Incomplete, 6 Skipped. Time elapsed: 63.9349 seconds.
Здесь, функция не обнаруживает проблем со слоем.
Можно использовать пользовательский слой таким же образом в качестве любого другого слоя в Deep Learning Toolbox. Этот раздел показывает, как создать и обучить сеть для классификации цифр с помощью слоя PReLU, который вы создали ранее.
Загрузите данные тренировки в качестве примера.
[XTrain,YTrain] = digitTrain4DArrayData;
Задайте пользовательский слой PReLU. Чтобы создать этот слой, сохраните файл preluLayer.m
в текущей папке. Создайте массив слоя включая пользовательский слой preluLayer
.
layers = [
imageInputLayer([28 28 1])
convolution2dLayer(5,20)
batchNormalizationLayer
preluLayer(20,'prelu')
fullyConnectedLayer(10)
softmaxLayer
classificationLayer];
Установите опции обучения и обучите сеть.
options = trainingOptions('adam','MaxEpochs',10); net = trainNetwork(XTrain,YTrain,layers,options);
Training on single CPU. Initializing input data normalization. |========================================================================================| | Epoch | Iteration | Time Elapsed | Mini-batch | Mini-batch | Base Learning | | | | (hh:mm:ss) | Accuracy | Loss | Rate | |========================================================================================| | 1 | 1 | 00:00:00 | 7.03% | 3.3828 | 0.0010 | | 2 | 50 | 00:00:03 | 74.22% | 0.7206 | 0.0010 | | 3 | 100 | 00:00:06 | 89.84% | 0.3583 | 0.0010 | | 4 | 150 | 00:00:08 | 88.28% | 0.4036 | 0.0010 | | 6 | 200 | 00:00:11 | 96.88% | 0.2033 | 0.0010 | | 7 | 250 | 00:00:14 | 96.88% | 0.1368 | 0.0010 | | 8 | 300 | 00:00:17 | 100.00% | 0.0608 | 0.0010 | | 9 | 350 | 00:00:19 | 100.00% | 0.0533 | 0.0010 | | 10 | 390 | 00:00:22 | 99.22% | 0.0528 | 0.0010 | |========================================================================================|
Оцените производительность сети путем предсказания на новых данных и вычисления точности.
[XTest,YTest] = digitTest4DArrayData; YPred = classify(net,XTest); accuracy = sum(YTest==YPred)/numel(YTest)
accuracy = 0.9194
[1] Он, Kaiming, Сянюй Чжан, Шаоцин Жэнь и Цзянь Сунь. "Копаясь глубоко в выпрямителях: Превосходная производительность человеческого уровня на классификации ImageNet". В Продолжениях международной конференции IEEE по вопросам компьютерного зрения, стр 1026-1034. 2015.