Задайте пользовательский слой глубокого обучения с параметрами Learnable

Если Deep Learning Toolbox™ не обеспечивает слой, вы требуете для своей классификации или проблемы регрессии, то можно задать собственный слой с помощью этого примера в качестве руководства. Для списка встроенных слоев смотрите Список слоев глубокого обучения.

Чтобы задать пользовательский слой глубокого обучения, можно использовать шаблон, обеспеченный в этом примере, который берет вас через следующие шаги:

  1. Назовите слой – дают слою имя так, чтобы это могло использоваться в MATLAB®.

  2. Объявите, что свойства слоя – задают свойства слоя и какие параметры изучены во время обучения.

  3. Создайте (дополнительную) функцию конструктора – задают, как создать слой и инициализировать его свойства. Если вы не задаете функцию конструктора, то при создании, программное обеспечение инициализирует Name, Description и свойства Type с [] и определяет номер вводов и выводов слоя к 1.

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

  5. Создайте обратную функцию – задают производные потери относительно входных данных и learnable параметров (обратное распространение).

Этот пример показывает, как создать слой PReLU, который является слоем с learnable параметром, и используйте его в сверточной нейронной сети. Слой PReLU выполняет пороговую операцию, где для каждого канала, любое входное значение меньше, чем нуль умножаются на скаляр, изученный в учебное время. [1] Для значений меньше, чем нуль, слой PReLU применяет масштабные коэффициенты αi к каждому каналу входа. Эти коэффициенты формируют learnable параметр, который слой изучает во время обучения.

Эта фигура от [1] сравнивает функции уровня ReLU и PReLU.

Слой с шаблоном параметров 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 на preluLayer.

classdef preluLayer < nnet.layer.Layer
    ...
end

Затем, переименуйте функцию конструктора myLayer (первая функция в разделе methods) так, чтобы это имело то же имя как слой.

    methods
        function layer = preluLayer()           
            ...
        end

        ...
     end

Сохраните слой

Сохраните файл класса слоя в новом файле с именем preluLayer.m. Имя файла должно совпадать с именем слоя. Чтобы использовать слой, необходимо сохранить файл в текущей папке или в папке на пути MATLAB.

Объявите свойства и параметры Learnable

Объявите свойства слоя в разделе properties и объявите learnable параметры путем листинга их в разделе properties (Learnable).

По умолчанию пользовательские промежуточные слои имеют эти свойства:

СвойствоОписание
Name Имя слоя, заданное как вектор символов или скаляр строки. Чтобы включать слой в график слоя, необходимо задать непустое уникальное имя слоя. Если вы обучаете серийную сеть со слоем, и Name установлен в '', то программное обеспечение автоматически присваивает имя к слою в учебное время.
Description

Короткое описание слоя, заданного как вектор символов или скаляр строки. Это описание появляется, когда слой отображен в массиве Layer. Если вы не задаете описание слоя, то программное обеспечение отображает имя класса слоя.

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(xi)={xiесли xi>0αixiесли xi0

где xi вход нелинейной активации f на канале i, и αi коэффициент, управляющий наклоном отрицательной части. Нижний i в αi указывает, что нелинейная активация может отличаться на различных каналах.

Реализуйте эту операцию в predict. В predict вход X соответствует x в уравнении. Вывод Z соответствует f(xi). Слой 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 должен принять входные параметры с тем же размером как соответствующий вывод прямой функции и назад распространить производные с тем же размером.

Производная потери относительно входных данных

Lxi=Lf(xi)f(xi)xi

где L/f(xi) градиент, распространенный от следующего слоя, и производная активации

f(xi)xi={1если xi0αiесли xi<0.

Производная потери относительно learnable параметров

Lαi=jLf(xij)f(xij)αi

где i индексирует каналы, j индексирует элементы по высоте, ширине и наблюдениям, и L/f(xi) градиент, распространенный от более глубокого слоя, и градиент активации

f(xi)αi={0если xi0xiесли xi<0.

В backward шаблона слоя замените вывод dLdW на вывод dLdAlpha, где dLdAlpha соответствует L/αi. В backward вход X соответствует x. Вход Z соответствует f(xi). Вход dLdZ соответствует L/f(xi). Вывод dLdX соответствует L/xi.

Добавьте комментарий в верхнюю часть функции, которая объясняет синтаксисы функции. Чтобы уменьшать использование памяти путем предотвращения неиспользуемых переменных, являющихся сохраненным между прямым и обратным проходом, замените соответствующие входные параметры на ~. Поскольку функция уровня не требует входных параметров 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.

Смотрите также

|

Похожие темы

Для просмотра документации необходимо авторизоваться на сайте