exponenta event banner

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

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

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

  1. Имя слоя - присвойте слою имя, чтобы его можно было использовать в MATLAB ®.

  2. Объявить свойства слоя (Declare the layer properties) - укажите свойства слоя и параметры, которые будут изучены во время обучения.

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

  4. Создать функции прямой передачи - укажите способ передачи данных через уровень (прямое распространение) во время прогнозирования и во время обучения.

  5. Создать обратную функцию (необязательно) - укажите производные потери относительно входных данных и обучаемых параметров (обратное распространение). Если функция обратного направления не указана, то функции прямого направления должны поддерживать dlarray объекты.

Чтобы создать пользовательский слой, поддерживающий создание кода, выполните следующие действия.

  • Слой должен указывать прагматику %#codegen в определении слоя.

  • Входы predict должно быть:

    • Согласовано в измерении. Каждый вход должен иметь одинаковое количество размеров.

    • Согласован по размеру партии. Каждый ввод должен иметь одинаковый размер партии.

  • Выходные данные predict должен быть согласован по размеру и размеру партии с входными данными слоя.

  • Нескалярные свойства должны иметь однотипный, двойной или символьный массив.

  • Скалярные свойства должны иметь тип numeric, logical или string.

Генерация кода поддерживает промежуточные слои только с 2-D вводом изображения.

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

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

Слой с шаблоном обучаемых параметров

Скопируйте слой с шаблоном обучаемых параметров в новый файл в MATLAB. Этот шаблон описывает структуру слоя с обучаемыми параметрами и включает функции, определяющие поведение слоя.

classdef myLayer < nnet.layer.Layer % & nnet.layer.Formattable (Optional) 

    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 custom backward propagation

            % Layer forward function for training goes here.
        end

        function [dLdX1, …, dLdXn, dLdW1, …, dLdWk] = ...
                backward(layer, X1, …, Xn, Z1, …, Zm, dLdZ1, …, dLdZm, memory)
            % (Optional) 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 с codegenPreluLayer и добавьте комментарий, описывающий слой.

classdef codegenPreluLayer < nnet.layer.Layer
    % Example custom PReLU layer with codegen support.

    ...
end

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

    methods
        function layer = codegenPreluLayer()           
            ...
        end

        ...
     end

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

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

Указать прагматику создания кода

Добавить %#codegen директиву (или pragma) для определения слоя, указывающую, что предполагается создать код для этого слоя. Добавление этой директивы дает команду анализатору кода MATLAB помочь в диагностике и устранении нарушений, которые приводят к ошибкам при создании кода.

classdef codegenPreluLayer < nnet.layer.Layer
    % Example custom PReLU layer with codegen support.

    %#codegen

    ...
end

Объявление свойств и обучаемых параметров

Объявление свойств слоя в properties и объявить обучаемые параметры, перечислив их в 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 свойства в конструкторе слоев. Пример см. в разделе Определение пользовательского слоя глубокого обучения с несколькими входами.

Для поддержки создания кода:

  • Нескалярные свойства должны иметь однотипный, двойной или символьный массив.

  • Скалярные свойства должны быть числовыми или иметь тип logical или string.

Слой PReLU не требует дополнительных свойств, поэтому можно удалить properties раздел.

Уровень PReLU имеет только один обучаемый параметр, коэффициент масштабирования a. Объявите этот обучаемый параметр в properties (Learnable) раздел и вызовите параметр Alpha.

    properties (Learnable)
        % Layer learnable parameters
            
        % Scaling coefficient
        Alpha
    end

Создать функцию конструктора

Создайте функцию, которая создает слой и инициализирует свойства слоя. Укажите все переменные, необходимые для создания слоя в качестве входных данных функции конструктора.

Функция конструктора уровня PReLU требует два входных аргумента: количество каналов ожидаемых входных данных и имя слоя. Количество каналов определяет размер обучаемого параметра Alpha. Укажите два входных аргумента с именем numChannels и name в codegenPreluLayer функция. Добавьте комментарий в верхней части функции, объясняющий синтаксис функции.

        function layer = codegenPreluLayer(numChannels, name)
            % layer = codegenPreluLayer(numChannels) creates a PReLU layer with
            % numChannels channels and specifies the layer name.

            ...
        end

Создание кода не поддерживает arguments блоки.

Инициализация свойств слоя

Инициализируйте свойства слоя, включая обучаемые параметры, в функции конструктора. Заменить комментарий % 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. Инициализация обучаемого параметра Alpha как случайный вектор размера 1 на 1-by-numChannels. С третьим размером, указанным как размер numChannels, слой может использовать элементное умножение входного сигнала в прямой функции. Alpha является свойством объекта слоя, поэтому необходимо назначить вектор layer.Alpha.

            % Initialize scaling coefficient.
            layer.Alpha = rand([1 1 numChannels]);

Просмотр завершенной функции конструктора.

        function layer = codegenPreluLayer(numChannels, name) 
            % layer = codegenPreluLayer(numChannels, name) creates a PReLU
            % layer for 2-D image input 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

С помощью этой функции конструктора команда codegenPreluLayer(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).

Создание кода поддерживает пользовательские промежуточные слои только с 2-D вводом изображения. Входными данными являются массивы h-by-w-by-c-by-N, где h, w и c соответствуют высоте, ширине и количеству каналов изображений соответственно, а N - количество наблюдений. Размер наблюдения равен 4.

Для поддержки генерации кода все входы слоев должны иметь одинаковое количество размеров и размер партии.

По умолчанию слой использует predict в качестве прямой функции во время обучения. Чтобы использовать другую прямую функцию во время обучения или сохранить значение, необходимое для пользовательской обратной функции, необходимо также создать функцию с именем forward. Программное обеспечение не генерирует код для forward функция должна быть совместима с генерацией кода.

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) = xif xi >  0αixiif xi≤0

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

Реализовать эту операцию в predict. В predict, вход X соответствует x в уравнении. Продукция Z соответствует f (xi).

Добавьте комментарий в верхнюю часть функции, который объясняет синтаксисы функции.

Совет

При предварительном назначении массивов с использованием таких функций, как zeros, то необходимо убедиться, что типы данных этих массивов согласуются с входами функции уровня. Чтобы создать массив нулей того же типа данных, что и другой массив, используйте 'like' вариант zeros. Например, для инициализации массива нулей размера sz с тем же типом данных, что и массив X, использовать Z = zeros(sz,'like',X).

Реализация backward является необязательной, когда функции прямой передачи полностью поддерживают dlarray вход. Для поддержки генерации кода, predict функция также должна поддерживать числовой ввод.

Одним из способов вычисления выходных данных операции PReLU является использование следующего кода.

Z = max(X,0) + layer.Alpha .* min(0,X);
Поскольку генерация кода не поддерживает неявное расширение через .* , вы можете использовать bsxfun вместо этого функция.
Z = max(X,0) + bsxfun(@times, layer.Alpha, min(0,X));
Тем не менее, bsxfun не поддерживает dlarray вход. Для реализации predict функция, которая поддерживает как генерацию кода, так и dlarray ввод, использование if оператор с isdlarray для выбора соответствующего кода для типа ввода.

        function Z = predict(layer, X)
            % Z = predict(layer, X) forwards the input data X through the
            % layer and outputs the result Z.
            
            if isdlarray(X)
                Z = max(X,0) + layer.Alpha .* min(0,X);
            else
                Z = max(X,0) + bsxfun(@times, layer.Alpha, min(0,X));
            end
        end

Потому что predict функция полностью поддерживает dlarray объекты, определение backward является необязательной функцией. Список функций, поддерживающих dlarray см. Список функций с поддержкой dlarray.

Завершенный слой

Просмотр завершенного файла класса слоев.

classdef codegenPreluLayer < nnet.layer.Layer
    % Example custom PReLU layer with codegen support.

    %#codegen

    properties (Learnable)
        % Layer learnable parameters
            
        % Scaling coefficient
        Alpha
    end
    
    methods
        function layer = codegenPreluLayer(numChannels, name) 
            % layer = codegenPreluLayer(numChannels, name) creates a PReLU
            % layer for 2-D image input 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.
            
            if isdlarray(X)
                Z = max(X,0) + layer.Alpha .* min(0,X);
            else
                Z = max(X,0) + bsxfun(@times, layer.Alpha, min(0,X));
            end
        end
    end
end

Проверка совместимости создания кода на уровне

Проверка совместимости создания кода пользовательского слоя codegenPreluLayer.

Определите пользовательский уровень PReLU с поддержкой генерации кода. Чтобы создать этот слой, сохраните файл codegenPreluLayer.m в текущей папке.

Создание экземпляра слоя и проверка его действительности с помощью checkLayer. Укажите допустимый размер ввода в качестве размера одного наблюдения за типовым вводом в слой. Слой ожидает 4-D входов массива, где первые три размера соответствуют высоте, ширине и количеству каналов предыдущего выхода слоя, а четвертый размер соответствует наблюдениям.

Укажите типичный размер входных данных наблюдения и установите значение 'ObservationDimension' опция 4. Чтобы проверить совместимость генерации кода, установите 'CheckCodegenCompatibility' опция для true.

layer = codegenPreluLayer(20,'prelu');
validInputSize = [24 24 20];
checkLayer(layer,validInputSize,'ObservationDimension',4,'CheckCodegenCompatibility',true)
Skipping GPU tests. No compatible GPU device found.
 
Running nnet.checklayer.TestLayerWithoutBackward
.......... ........
Done nnet.checklayer.TestLayerWithoutBackward
__________

Test Summary:
	 18 Passed, 0 Failed, 0 Incomplete, 4 Skipped.
	 Time elapsed: 0.53879 seconds.

Функция не обнаруживает никаких проблем со слоем.

Ссылки

[1] «Углубление в выпрямители: превышение производительности на уровне человека при классификации ImageNet». В 2015 году Международная конференция IEEE по компьютерному зрению (ICCV), 1026-34. Сантьяго, Чили: IEEE, 2015. https://doi.org/10.1109/ICCV.2015.123.

См. также

|

Связанные темы