이 페이지의 최신 내용은 아직 번역되지 않았습니다. 최신 내용은 영문으로 볼 수 있습니다.

학습 가능한 파라미터를 갖는 사용자 지정 딥러닝 계층 정의하기

Deep Learning Toolbox™가 분류 또는 회귀 문제에 필요한 계층을 제공하지 않을 경우, 이 예제를 가이드로 참고하여 자신만의 고유한 사용자 지정 계층을 정의할 수 있습니다. 내장 계층 목록은 딥러닝 계층 목록 항목을 참조하십시오.

사용자 지정 딥러닝 계층을 정의하려면 이 예제에서 제공하는 템플릿을 사용할 수 있습니다. 이 예제에서는 다음과 같은 단계를 수행합니다.

  1. 계층에 이름 지정하기 – MATLAB®에서 사용할 수 있도록 계층에 이름을 지정합니다.

  2. 계층 속성 선언하기 – 계층의 속성과 훈련 중에 학습될 파라미터를 지정합니다.

  3. 생성자 함수 만들기(선택 사항) – 계층을 생성하고 속성을 초기화하는 방법을 지정합니다. 생성자 함수를 지정하지 않으면 생성 시점에 Name, Description, Type 속성이 []로 초기화되고 계층 입력값 개수와 출력값 개수가 1로 설정됩니다.

  4. 순방향 함수 만들기 – 예측 시점과 훈련 시점에 데이터가 계층을 어떻게 순방향으로 통과하는지(순방향 전파) 지정합니다.

  5. 역방향 함수 만들기(선택 사항) – 입력 데이터와 학습 가능한 파라미터에 대한 손실의 도함수를 지정합니다(역방향 전파). 역방향 함수를 지정하지 않을 경우 순방향 함수가 dlarray 객체를 지원해야 합니다.

이 예제에서는 학습 가능한 파라미터가 있는 계층인 PReLU 계층을 만들고 이를 컨벌루션 신경망에서 사용하는 방법을 보여줍니다. PReLU 계층은 각 채널마다 0보다 작은 입력값을 훈련 시점에 학습한 스칼라로 곱하는 임계값 연산을 수행합니다.[1] 0보다 작은 값의 경우, PReLU 계층은 입력값의 각 채널에 스케일링 계수 αi를 적용합니다. 이 계수는 학습 가능한 파라미터를 형성하며, 훈련 중에 계층이 이 학습 가능한 파라미터를 학습합니다.

[1]에 나오는 다음 그림은 ReLU 계층 함수와 PReLU 계층 함수를 비교합니다.

학습 가능한 파라미터를 갖는 계층 템플릿

학습 가능한 파라미터를 갖는 계층 템플릿을 MATLAB에서 새 파일에 복사합니다. 이 템플릿은 학습 가능한 파라미터를 갖는 계층의 구조를 제공하며 계층 동작을 정의하는 함수를 포함합니다.

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 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

계층에 이름 지정하기

먼저 계층에 이름을 지정합니다. 클래스 파일의 첫 번째 줄에서 기존 이름 myLayerpreluLayer로 바꿉니다.

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

다음으로, myLayer 생성자 함수(methods 섹션에 있는 첫 번째 함수)가 계층과 동일한 이름을 갖도록 이름을 변경합니다.

    methods
        function layer = preluLayer()           
            ...
        end

        ...
     end

계층 저장하기

계층 클래스 파일을 새 파일 preluLayer.m에 저장합니다. 파일 이름은 계층 이름과 일치해야 합니다. 계층을 사용하려면 파일을 현재 폴더 또는 MATLAB 경로의 폴더에 저장해야 합니다.

속성과 학습 가능한 파라미터 선언하기

properties 섹션에서 계층 속성을 선언하고 properties (Learnable) 섹션에서 학습 가능한 파라미터를 나열하여 선언합니다.

기본적으로 사용자 지정 중간 계층은 다음과 같은 속성을 갖습니다.

속성설명
Name 계층 이름으로, 문자형 벡터 또는 string형 스칼라로 지정됩니다. 계층 그래프에 계층을 포함하려면 비어 있지 않은 고유한 계층 이름을 지정해야 합니다. 이 계층을 사용하여 시리즈 네트워크를 훈련시킬 때 Name''로 설정하면, 소프트웨어가 훈련 시점에 해당 계층에 자동으로 이름을 할당합니다.
Description

계층에 대한 한 줄 설명으로, 문자형 벡터 또는 string형 스칼라로 지정됩니다. 이 설명은 계층이 Layer 배열에 표시되는 경우에 나타납니다. 계층 설명을 지정하지 않으면 계층 클래스 이름이 표시됩니다.

Type계층 유형으로, 문자형 벡터 또는 string형 스칼라로 지정됩니다. Type의 값은 계층이 Layer 배열에 표시되는 경우에 나타납니다. 계층 유형을 지정하지 않을 경우 계층 클래스 이름이 표시됩니다.
NumInputs계층에 대한 입력값의 개수로, 양의 정수로 지정됩니다. 이 값을 지정하지 않으면 NumInputsInputNames의 이름 개수로 자동으로 설정됩니다. 디폴트 값은 1입니다.
InputNames계층의 입력값 이름으로, 문자형 벡터로 구성된 셀형 배열로 지정됩니다. 이 값을 지정하지 않았고 NumInputs가 1보다 크면, InputNames{'in1',...,'inN'}으로 자동으로 설정됩니다. 여기서 NNumInputs와 동일합니다. 디폴트 값은 {'in'}입니다.
NumOutputs계층에 대한 출력값의 개수로, 양의 정수로 지정됩니다. 이 값을 지정하지 않으면 NumOutputsOutputNames의 이름 개수로 자동으로 설정됩니다. 디폴트 값은 1입니다.
OutputNames계층의 출력값 이름으로, 문자형 벡터로 구성된 셀형 배열로 지정됩니다. 이 값을 지정하지 않았고 NumOutputs가 1보다 크면, OutputNames{'out1',...,'outM'}으로 자동으로 설정됩니다. 여기서 MNumOutputs와 동일합니다. 디폴트 값은 {'out'}입니다.

계층에 다른 속성이 없는 경우 properties 섹션을 생략할 수 있습니다.

입력값이 여러 개인 계층을 만들 때는 계층 생성자에서 NumInputs 또는 InputNames를 설정해야 합니다. 출력값이 여러 개인 계층을 만들 때는 계층 생성자에서 NumOutputs 또는 OutputNames를 설정해야 합니다. 예제는 Define Custom Deep Learning Layer with Multiple Inputs 항목을 참조하십시오.

PReLU 계층에는 추가 속성이 필요하지 않으므로 properties 섹션을 제거해도 됩니다.

PReLU 계층에는 단 하나의 학습 가능한 파라미터가 있습니다. 바로 스케일링 계수 a입니다. 이 학습 가능한 파라미터를 properties (Learnable) 섹션에서 선언하고 파라미터 Alpha를 호출합니다.

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

생성자 함수 만들기

계층을 생성하고 계층 속성을 초기화하는 함수를 만듭니다. 계층을 만드는 데 필요한 변수를 생성자 함수의 입력값으로 지정합니다.

PReLU 계층 생성자 함수에는 예상 입력 데이터의 채널 개수와 계층 이름, 이렇게 2개의 입력 인수가 필요합니다. 채널 개수는 학습 가능한 파라미터 Alpha의 크기를 지정합니다. preluLayer 함수에 2개의 입력 인수 numChannelsname을 지정합니다. 함수 상단에 함수의 구문에 대해 설명하는 주석을 추가합니다.

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

            ...
        end

계층 속성 초기화하기

생성자 함수에서 학습 가능한 파라미터와 계층 속성을 초기화합니다. 주석 % 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가 크기가 1x1xnumChannels인 확률 벡터가 되도록 초기화합니다. 세 번째 차원을 크기 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')는 이 생성자 함수를 사용하여 3개의 채널을 갖고 이름이 'prelu'인 PReLU 계층을 만듭니다.

순방향 함수 만들기

예측 시점과 훈련 시점에 사용할 계층 순방향 함수를 만듭니다.

예측 시점에 데이터를 계층에 순방향으로 전파하고 결과를 출력하는 함수 predict를 만듭니다.

predict의 구문은 다음과 같습니다.

[Z1,…,Zm] = predict(layer,X1,…,Xn)
여기서 X1,…,Xnn개의 계층 입력값이고 Z1,…,Zmm개의 계층 출력값입니다. 값 nm은 각각 계층의 NumInputs 속성, NumOutputs 속성과 일치해야 합니다.

predict에 대한 입력값의 개수가 가변인 경우에는 X1,…,Xn 대신 varargin을 사용하십시오. 이 경우 varargin은 입력값으로 구성된 셀형 배열입니다. 여기서 varargin{i}Xi에 대응됩니다. 출력값의 개수가 가변인 경우에는 Z1,…,Zm 대신 varargout을 사용하십시오. 이 경우 varargout은 출력값으로 구성된 셀형 배열입니다. 여기서 varargout{j}Zj에 대응됩니다.

PReLU 계층에는 입력값 1개와 출력값 1개밖에 없으므로 PReLU 계층에 대한 predict의 구문은 Z = predict(layer,X)입니다.

기본적으로 계층은 predict를 훈련 시점에 순방향 함수로 사용합니다. 훈련 시점에 다른 순방향 함수를 사용하거나 사용자 지정 역방향 함수에 필요한 값을 유지하려면 forward라는 이름의 함수도 만들어야 합니다.

입력값의 차원은 데이터의 유형 및 연결된 계층의 출력값에 따라 달라집니다.

계층 입력값입력 크기관측값 차원
2차원 영상hxwxcxN. 여기서 h, w, c는 영상의 높이, 너비, 채널 개수이고 N은 관측값 개수입니다.4
3차원 영상hxwxDxcxN. 여기서 h, w, D, c는 3차원 영상의 높이, 너비, 깊이, 채널 개수이고 N은 관측값 개수입니다.5
벡터 시퀀스cxNxS. 여기서 c는 시퀀스의 특징 개수이고 N은 관측값 개수이고 S는 시퀀스 길이입니다.2
2차원 영상 시퀀스hxwxcxNxS. 여기서 h, w, c는 영상의 높이, 너비, 채널 개수이고 N은 관측값 개수이고 S는 시퀀스 길이입니다.4
3차원 영상 시퀀스hxwxdxcxNxS. 여기서 h, w, d, c는 3차원 영상의 높이, 너비, 깊이, 채널 개수이고 N은 관측값 개수이고 S는 시퀀스 길이입니다.5

forward 함수는 훈련 시점에 데이터를 계층에 순방향으로 전파하고 메모리 값도 출력합니다.

forward의 구문은 다음과 같습니다.

[Z1,…,Zm,memory] = forward(layer,X1,…,Xn)
여기서 X1,…,Xnn개의 계층 입력값이고 Z1,…,Zmm개의 계층 출력값이고 memory는 계층의 메모리입니다.

forward에 대한 입력값의 개수가 가변인 경우에는 X1,…,Xn 대신 varargin을 사용하십시오. 이 경우 varargin은 입력값으로 구성된 셀형 배열입니다. 여기서 varargin{i}Xi에 대응됩니다. 출력값의 개수가 가변인 경우에는 Z1,…,Zm 대신 varargout을 사용하십시오. 이 경우 varargout은 출력값으로 구성된 셀형 배열입니다. 여기서 varargout{j}j=1,…,NumOutputs인 경우 Zj에 대응되고 varargout{NumOutputs+1}memory에 대응됩니다.

PReLU 연산은 다음과 같이 지정됩니다.

f(xi)={xiif xi>0αixiif xi0

여기서 xi는 채널 i에서의 비선형 활성화 f의 입력값이고 αi는 음의 부분의 기울기를 제어하는 계수입니다. αi의 아래 첨자 i는 서로 다른 채널에서 비선형 활성화가 달라질 수 있음을 나타냅니다.

이 연산을 predict에 구현합니다. predict에서 입력값 X는 방정식의 x에 대응됩니다. 출력값 Zf(xi)에 대응됩니다. PReLU 계층에서는 훈련을 위해 메모리나 다른 순방향 함수가 필요하지 않으므로 클래스 파일에서 forward 함수를 제거해도 됩니다. 함수 상단에 함수의 구문에 대해 설명하는 주석을 추가합니다.

zeros와 같은 함수를 사용하여 배열을 사전할당할 경우, 이들 배열의 데이터형이 계층 함수 입력값에 부합하는지 확인해야 합니다. 다른 배열과 동일한 데이터형을 가진 0으로 구성된 배열을 만들려면 zeros'like' 옵션을 사용하십시오. 예를 들어, 크기가 sz이고 배열 X와 동일한 데이터형을 갖는 0으로 구성된 배열을 만들려면 Z = zeros(sz,'like',X)를 사용하십시오.

        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

predict 함수는 dlarray 객체를 지원하는 함수만 사용하므로 backward 함수를 정의하는 것은 선택 사항입니다. dlarray 객체를 지원하는 함수 목록은 List of Functions with dlarray Support 항목을 참조하십시오.

완성된 계층

완성된 계층 클래스 파일을 확인합니다.

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
    end
end

GPU 호환성

계층 순방향 함수가 dlarray 객체를 완전히 지원하는 경우 이 계층은 GPU와 호환됩니다. 그러지 않은 경우, 계층이 GPU와 호환되려면 계층 함수가 gpuArray 형식의 입력값을 지원하고 출력값을 이 형식으로 반환해야 합니다.

여러 MATLAB 내장 함수는 gpuArray 입력 인수와 dlarray 입력 인수를 지원합니다. dlarray 객체를 지원하는 함수 목록은 List of Functions with dlarray Support 항목을 참조하십시오. GPU에서 실행되는 함수 목록은 GPU에서 MATLAB 함수 실행하기 (Parallel Computing Toolbox) 항목을 참조하십시오. 딥러닝을 위해 GPU를 사용하려면 CUDA® 지원 NVIDIA® GPU(Compute Capability 3.0 이상)도 필요합니다. MATLAB에서 GPU를 사용하는 것에 관한 자세한 내용은 MATLAB에서의 GPU 연산 (Parallel Computing Toolbox) 항목을 참조하십시오.

이 예제에서, predict에 사용된 MATLAB 함수는 모두 dlarray 객체를 지원하므로 이 계층은 GPU와 호환됩니다.

checkLayer를 사용하여 계층의 유효성 검사하기

사용자 지정 계층 preluLayer의 계층 유효성을 검사합니다.

사용자 지정 PReLU 계층을 정의합니다. 이 계층을 만들려면 파일 preluLayer.m을 현재 폴더에 저장하십시오.

계층의 인스턴스를 만들고 checkLayer를 사용하여 유효성을 검사합니다. 계층에 대한 일반적인 입력값의 단일 관측값을 유효한 입력 크기로 지정합니다. 계층에는 4차원 배열 입력값이 필요합니다. 여기서 처음 3개의 차원은 이전 계층 출력값의 높이, 너비, 채널 개수이고 4번째 차원은 관측값입니다.

관측값의 일반적인 입력 크기를 지정하고 '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.TestLayerWithoutBackward
.......... ...
Done nnet.checklayer.TestLayerWithoutBackward
__________

Test Summary:
	 13 Passed, 0 Failed, 0 Incomplete, 4 Skipped.
	 Time elapsed: 0.78326 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 |       10.94% |       3.0526 |          0.0010 |
|       2 |          50 |       00:00:12 |       71.88% |       0.8378 |          0.0010 |
|       3 |         100 |       00:00:24 |       85.94% |       0.4878 |          0.0010 |
|       4 |         150 |       00:00:40 |       88.28% |       0.4068 |          0.0010 |
|       6 |         200 |       00:00:56 |       96.09% |       0.1690 |          0.0010 |
|       7 |         250 |       00:01:10 |       97.66% |       0.1368 |          0.0010 |
|       8 |         300 |       00:01:24 |       99.22% |       0.0744 |          0.0010 |
|       9 |         350 |       00:01:38 |       99.22% |       0.0592 |          0.0010 |
|      10 |         390 |       00:01:48 |      100.00% |       0.0465 |          0.0010 |
|========================================================================================|

새로운 데이터에 대해 예측을 수행하고 정확도를 계산하여 네트워크 성능을 평가합니다.

[XTest,YTest] = digitTest4DArrayData;
YPred = classify(net,XTest);
accuracy = sum(YTest==YPred)/numel(YTest)
accuracy = 0.9188

참고 문헌

[1] He, Kaiming, Xiangyu Zhang, Shaoqing Ren, and Jian Sun. "Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification." In Proceedings of the IEEE international conference on computer vision, pp. 1026-1034. 2015.

참고 항목

|

관련 항목