Если 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.