Если Deep Learning Toolbox™ не обеспечивает слой, вы требуете для своей классификации или проблемы регрессии, то можно задать собственный слой с помощью этого примера в качестве руководства. Для списка встроенных слоев смотрите Список слоев глубокого обучения.
Чтобы задать пользовательский слой глубокого обучения, можно использовать шаблон, обеспеченный в этом примере, который берет вас через следующие шаги:
Назовите слой – дают слою имя так, чтобы это могло использоваться в MATLAB®.
Объявите, что свойства слоя – задают свойства слоя и какие параметры изучены во время обучения.
Создайте (дополнительную) функцию конструктора – задают, как создать слой и инициализировать его свойства. Если вы не задаете функцию конструктора, то при создании, программное обеспечение инициализирует Name
, Description
и свойства Type
с []
и определяет номер вводов и выводов слоя к 1.
Создайте прямые функции – задают, как данные передают вперед через слой (прямое распространение) во время прогноза и в учебное время.
Создайте обратную функцию – задают производные потери относительно входных данных и learnable параметров (обратное распространение).
Этот пример показывает, как создать взвешенный слой сложения, который является слоем с несколькими входными параметрами и learnable параметром, и используйте его в сверточной нейронной сети. Взвешенный слой сложения масштабирует и добавляет входные параметры от нескольких поэлементных слоев нейронной сети.
Скопируйте слой с 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
на weightedAdditionLayer
.
classdef weightedAdditionLayer < nnet.layer.Layer ... end
Затем, переименуйте функцию конструктора myLayer
(первая функция в разделе methods
) так, чтобы это имело то же имя как слой.
methods function layer = weightedAdditionLayer() ... end ... end
Сохраните файл класса слоя в новом файле с именем weightedAdditionLayer.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
в конструкторе слоя.
Взвешенный слой сложения не требует никаких дополнительных свойств, таким образом, можно удалить раздел properties
.
Взвешенный слой сложения имеет только один learnable параметр, веса. Объявите этот learnable параметр в разделе properties (Learnable)
и вызовите параметр Weights
.
properties (Learnable)
% Layer learnable parameters
% Scaling coefficients
Weights
end
Создайте функцию, которая создает слой и инициализирует свойства слоя. Задайте любые переменные, требуемые создать слой как входные параметры к функции конструктора.
Взвешенная функция конструктора слоя сложения требует двух входных параметров: количество входных параметров к слою и имени слоя. Это количество входных параметров к слою задает размер learnable параметра Weights
. Задайте два входных параметра под названием numInputs
и name
в функции weightedAdditionLayer
. Добавьте комментарий в верхнюю часть функции, которая объясняет синтаксис функции.
function layer = weightedAdditionLayer(numInputs,name) % layer = weightedAdditionLayer(numInputs,name) creates a % weighted addition layer and specifies the number of inputs % and the layer name. ... end
Инициализируйте свойства слоя, включая learnable параметры, в функции конструктора. Замените комментарий % Layer constructor function goes here
на код, который инициализирует свойства слоя.
Установите свойство NumInputs
на входной параметр numInputs
.
% Set number of inputs.
layer.NumInputs = numInputs;
Установите свойство Name
на входной параметр name
.
% Set layer name.
layer.Name = name;
Дайте слою короткое описание путем установки свойства Description
слоя. Установите описание описывать тип слоя и его размера.
% Set layer description. layer.Description = "Weighted addition of " + numInputs + ... " inputs";
Взвешенный слой сложения умножает каждый слой, введенный соответствующим коэффициентом в Weights
, и добавляет получившиеся значения вместе. Инициализируйте learnable параметр Weights
, чтобы быть случайным вектором размера 1 numInputs
. Weights
является свойством расположенного на слое объекта, таким образом, необходимо присвоить вектор layer.Weights
.
% Initialize layer weights
layer.Weights = rand(1,numInputs);
Просмотрите завершенную функцию конструктора.
function layer = weightedAdditionLayer(numInputs,name)
% layer = weightedAdditionLayer(numInputs,name) creates a
% weighted addition layer and specifies the number of inputs
% and the layer name.
% Set number of inputs.
layer.NumInputs = numInputs;
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "Weighted addition of " + numInputs + ...
" inputs";
% Initialize layer weights.
layer.Weights = rand(1,numInputs);
end
С этой функцией конструктора команда weightedAdditionLayer(3,'add')
создает взвешенный слой сложения с тремя входными параметрами и именем 'add'
.
Создайте слой вперед функции, чтобы использовать во время прогноза и учебное время.
Создайте функцию с именем 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
.
Поскольку взвешенный слой сложения имеет только один вывод и переменное количество входных параметров, синтаксисом для predict
для взвешенного слоя сложения является Z = predict(layer,varargin)
, где varargin{i}
соответствует Xi
для положительных целых чисел i
, меньше чем или равный NumInputs
.
По умолчанию слой использует 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
.
Прямая функция взвешенного слоя сложения
где X(1), …, X(n) соответствует входным параметрам слоя и W1, …, Wn веса слоя.
Реализуйте прямую функцию в predict
. В predict
вывод Z
соответствует . Взвешенный слой сложения не требует памяти или различной прямой функции для обучения, таким образом, можно удалить функцию forward
из файла класса. Добавьте комментарий в верхнюю часть функции, которая объясняет синтаксисы функции.
Если вы предварительно выделяете массивы с помощью функций как zeros
, то необходимо гарантировать, что типы данных этих массивов сопоставимы с входными параметрами функции уровня. Чтобы создать массив нулей совпадающего типа данных другого массива, используйте опцию 'like'
zeros
. Например, чтобы инициализировать массив нулей размера sz
с совпадающим типом данных как массив X
, используйте Z = zeros(sz,'like',X)
.
function Z = predict(layer, varargin)
% Z = predict(layer, X1, ..., Xn) forwards the input data X1,
% ..., Xn through the layer and outputs the result Z.
X = varargin;
W = layer.Weights;
% Initialize output
X1 = X{1};
sz = size(X1);
Z = zeros(sz,'like',X1);
% Weighted addition
for i = 1:layer.NumInputs
Z = Z + W(i)*X{i};
end
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 параметров.
Поскольку взвешенный слой сложения имеет тот вывод, один learnable параметр и переменное количество входных параметров, синтаксисом для backward
для взвешенного слоя сложения является varargout = backward(layer, varargin)
. В этом случае varargin{i}
соответствует Xi
для положительных целых чисел i
, меньше чем или равный NumInputs
, varargin{NumInputs+1}
соответствует Z
, и varargin{NumInputs+2}
соответствует dLdZ
. Для выходных параметров varargout{i}
соответствует dLdXi
для положительных целых чисел, i
, меньше чем или равный NumIntputs
и varargout{NumInputs+1}
, соответствует dLdW
.
Размерности X1,...,Xn
и Z
эквивалентны в прямых функциях. Размерности dLdZ
совпадают с размерностями Z
. Размерности и типы данных dLdX1,...,dLdXn
совпадают с размерностями и типом данных X1,...,Xn
. Размерность и тип данных dLdW
совпадают с размерностью и типом данных learnable параметра W
.
Во время обратного прохода слой автоматически обновляет learnable параметры с помощью соответствующих производных.
Чтобы включать пользовательский слой в сеть, слой, прямые функции должны принять выходные параметры предыдущего слоя и вперед распространить массивы с размером, ожидаемым следующим слоем. Точно так же backward
должен принять входные параметры с тем же размером как соответствующий вывод прямой функции и назад распространить производные с тем же размером.
Для взвешенного слоя сложения производные потери относительно каждого входа
где k индексирует в каждый X(i) линейно, , градиент, распространенный от следующего слоя, индексов j в к Z линейно, и производная активации
Производная потери относительно каждого learnable параметра Wi
где j индексирует элементы Z линейно, и градиент активации
Реализуйте обратную функцию в backward
и добавьте комментарий в верхнюю часть функции, которая объясняет синтаксисы функции.
function varargout = backward(layer, varargin)
% [dLdX1,…,dLdXn,dLdW] = backward(layer,X1,…,Xn,Z,dLdZ,~)
% backward propagates the derivative of the loss function
% through the layer.
numInputs = layer.NumInputs;
W = layer.Weights;
X = varargin(1:numInputs);
dLdZ = varargin{numInputs+2};
% Calculate derivatives
dLdX = cell(1,numInputs);
dLdW = zeros(1,numInputs,'like',W);
for i = 1:numInputs
dLdX{i} = dLdZ * W(i);
dLdW(i) = sum(dLdZ .* X{i},'all');
end
% Pack output arguments.
varargout(1:numInputs) = dLdX;
varargout{numInputs+1} = dLdW;
end
Просмотрите завершенный файл класса слоя.
classdef weightedAdditionLayer < nnet.layer.Layer % Example custom weighted addition layer. properties (Learnable) % Layer learnable parameters % Scaling coefficients Weights end methods function layer = weightedAdditionLayer(numInputs,name) % layer = weightedAdditionLayer(numInputs,name) creates a % weighted addition layer and specifies the number of inputs % and the layer name. % Set number of inputs. layer.NumInputs = numInputs; % Set layer name. layer.Name = name; % Set layer description. layer.Description = "Weighted addition of " + numInputs + ... " inputs"; % Initialize layer weights. layer.Weights = rand(1,numInputs); end function Z = predict(layer, varargin) % Z = predict(layer, X1, ..., Xn) forwards the input data X1, % ..., Xn through the layer and outputs the result Z. X = varargin; W = layer.Weights; % Initialize output X1 = X{1}; sz = size(X1); Z = zeros(sz,'like',X1); % Weighted addition for i = 1:layer.NumInputs Z = Z + W(i)*X{i}; end end function varargout = backward(layer, varargin) % [dLdX1,…,dLdXn,dLdW] = backward(layer,X1,…,Xn,Z,dLdZ,~) % backward propagates the derivative of the loss function % through the layer. numInputs = layer.NumInputs; W = layer.Weights; X = varargin(1:numInputs); dLdZ = varargin{numInputs+2}; % Calculate derivatives dLdX = cell(1,numInputs); dLdW = zeros(1,numInputs,'like',W); for i = 1:numInputs dLdX{i} = dLdZ * W(i); dLdW(i) = sum(dLdZ .* X{i},'all'); end % Pack output arguments. varargout(1:numInputs) = dLdX; varargout{numInputs+1} = dLdW; end end end
Проверяйте валидность слоя пользовательского слоя weightedAdditionLayer
.
Задайте пользовательский взвешенный слой сложения. Чтобы создать этот слой, сохраните файл weightedAdditionLayer.m
в текущей папке.
Создайте экземпляр слоя и проверяйте его валидность с помощью checkLayer
. Задайте допустимые входные размеры, чтобы быть типичными размерами одного наблюдения для каждого входа к слою. Слой ожидает 4-D входные параметры массивов, где первые три измерения соответствуют высоте, ширине и количеству каналов предыдущего слоя вывод, и четвертая размерность соответствует наблюдениям.
Задайте типичный размер входа наблюдения и установите 'ObservationDimension'
на 4.
layer = weightedAdditionLayer(2,'add'); validInputSize = {[24 24 20],[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: 123.7138 seconds.
Здесь, функция не обнаруживает проблем со слоем.
Можно использовать пользовательский слой таким же образом в качестве любого другого слоя в Deep Learning Toolbox. Этот раздел показывает, как создать и обучить сеть для классификации цифр с помощью взвешенного слоя сложения, который вы создали ранее.
Загрузите данные тренировки в качестве примера.
[XTrain,YTrain] = digitTrain4DArrayData;
Задайте пользовательский взвешенный слой сложения. Чтобы создать этот слой, сохраните файл weightedAdditionLayer.m
в текущей папке.
Создайте график слоя включая пользовательский слой weightedAdditionLayer
.
layers = [ imageInputLayer([28 28 1],'Name','in') convolution2dLayer(5,20,'Name','conv1') reluLayer('Name','relu1') convolution2dLayer(3,20,'Padding',1,'Name','conv2') reluLayer('Name','relu2') convolution2dLayer(3,20,'Padding',1,'Name','conv3') reluLayer('Name','relu3') weightedAdditionLayer(2,'add') fullyConnectedLayer(10,'Name','fc') softmaxLayer('Name','softmax') classificationLayer('Name','classoutput')]; lgraph = layerGraph(layers); lgraph = connectLayers(lgraph, 'relu1', 'add/in2');
Установите опции обучения и обучите сеть.
options = trainingOptions('adam','MaxEpochs',10); net = trainNetwork(XTrain,YTrain,lgraph,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.81% | 2.3117 | 0.0010 | | 2 | 50 | 00:00:05 | 79.69% | 0.6953 | 0.0010 | | 3 | 100 | 00:00:10 | 91.41% | 0.2488 | 0.0010 | | 4 | 150 | 00:00:15 | 96.09% | 0.0991 | 0.0010 | | 6 | 200 | 00:00:21 | 99.22% | 0.0299 | 0.0010 | | 7 | 250 | 00:00:26 | 98.44% | 0.0609 | 0.0010 | | 8 | 300 | 00:00:32 | 100.00% | 0.0186 | 0.0010 | | 9 | 350 | 00:00:38 | 100.00% | 0.0155 | 0.0010 | | 10 | 390 | 00:00:43 | 100.00% | 0.0143 | 0.0010 | |========================================================================================|
Просмотрите веса, изученные взвешенным слоем сложения.
net.Layers(8).Weights
ans = 1x2 single row vector
1.0092 0.9914
Оцените производительность сети путем предсказания на новых данных и вычисления точности.
[XTest,YTest] = digitTest4DArrayData; YPred = classify(net,XTest); accuracy = sum(YTest==YPred)/numel(YTest)
accuracy = 0.9824
analyzeNetwork
| checkLayer
| trainNetwork