Main Content

새로운 영상을 분류하도록 딥러닝 신경망 훈련시키기

이 예제에서는 새로운 영상 세트를 분류할 수 있도록 전이 학습을 사용하여 컨벌루션 신경망을 다시 훈련시키는 방법을 보여줍니다.

사전 훈련된 영상 분류 신경망은 1백만 개가 넘는 영상에 대해 훈련되었으며 영상을 키보드, 커피 머그잔, 연필, 각종 동물 등 1,000가지 사물 범주로 분류할 수 있습니다. 분류 신경망은 다양한 영상을 대표하는 다양한 특징을 학습했습니다. 이 신경망은 영상을 입력값으로 받아서 영상에 있는 사물에 대한 레이블과 각 사물 범주의 확률을 출력합니다.

전이 학습은 딥러닝 응용 분야에서 널리 사용됩니다. 사전 훈련된 신경망을 새로운 작업을 학습하기 위한 출발점으로 사용할 수 있습니다. 일반적으로 전이 학습으로 신경망을 미세 조정하는 것이 무작위로 초기화된 가중치를 사용하여 신경망을 처음부터 훈련시키는 것보다 훨씬 쉽고 빠릅니다. 학습된 특징을 보다 적은 개수의 훈련 영상을 사용하여 새로운 작업으로 빠르게 전이할 수 있습니다.

데이터 불러오기

새 영상의 압축을 풀고 영상 데이터저장소로 불러옵니다. 이 데이터 세트는 75개의 영상만을 갖는 매우 작은 데이터 세트입니다. 데이터를 훈련 데이터 세트와 검증 데이터 세트로 나눕니다. 영상의 70%를 훈련용으로 사용하고 30%를 검증용으로 사용합니다.

unzip('MerchData.zip');
imds = imageDatastore('MerchData', ...
    'IncludeSubfolders',true, ...
    'LabelSource','foldernames'); 
[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7);

사전 훈련된 신경망 불러오기

사전 훈련된 GoogLeNet 신경망을 불러옵니다. Deep Learning Toolbox™ Model for GoogLeNet Network 지원 패키지가 설치되어 있지 않으면 이를 다운로드할 수 있는 링크가 제공됩니다.

사전 훈련된 다른 신경망을 사용해 보려면 MATLAB®에서 이 예제를 연 다음 다른 신경망을 선택하십시오. 예를 들어, googlenet보다 빠른 squeezenet 신경망을 사용해 볼 수 있습니다. 사전 훈련된 다른 신경망을 사용하여 이 예제를 실행할 수 있습니다. 사용 가능한 신경망 목록은 사전 훈련된 신경망 불러오기 항목을 참조하십시오.

net = googlenet;

analyzeNetwork를 사용하여 신경망 아키텍처에 대한 대화형 방식 시각화와 신경망 계층에 대한 상세한 정보를 표시합니다.

analyzeNetwork(net)

신경망의 Layers 속성의 첫 번째 요소는 영상 입력 계층입니다. GoogLeNet 신경망의 경우, 이 계층에 입력되는 영상은 크기가 224×224×3이어야 합니다. 여기서 3은 색 채널의 개수입니다. 다른 신경망의 경우 입력 영상의 크기가 저마다 다를 수 있습니다. 예를 들어, Xception 신경망의 입력 영상은 크기가 299×299×3이어야 합니다.

net.Layers(1)
ans = 
  ImageInputLayer with properties:

                      Name: 'data'
                 InputSize: [224 224 3]

   Hyperparameters
          DataAugmentation: 'none'
             Normalization: 'zerocenter'
    NormalizationDimension: 'auto'
                      Mean: [224×224×3 single]

inputSize = net.Layers(1).InputSize;

마지막 계층 바꾸기

신경망의 컨벌루션 계층은 마지막 학습 가능한 계층과 마지막 분류 계층이 입력 영상을 분류하는 데 사용하는 영상 특징을 추출합니다. GoogLeNet의 두 계층 'loss3-classifier''output'은 신경망이 추출하는 특징을 클래스 확률, 손실 값 및 예측된 레이블로 조합하는 방법에 대한 정보를 포함합니다. 사전 훈련된 신경망을 새로운 영상을 분류하도록 다시 훈련시키려면 이 두 계층을 새 데이터 세트에 맞게 조정된 새로운 계층으로 바꾸십시오.

사전 훈련된 신경망을 계층 그래프로 변환합니다.

lgraph = layerGraph(net);

바꿀 두 계층의 이름을 찾습니다. 이 작업은 수동으로 할 수도 있고 지원 함수 findLayersToReplace를 사용하여 계층을 자동으로 찾을 수도 있습니다.

[learnableLayer,classLayer] = findLayersToReplace(lgraph);
[learnableLayer,classLayer] 
ans = 
  1×2 Layer array with layers:

     1   'loss3-classifier'   Fully Connected         1000 fully connected layer
     2   'output'             Classification Output   crossentropyex with 'tench' and 999 other classes

대부분의 신경망에서, 학습 가능한 가중치를 갖는 마지막 계층은 완전 연결 계층입니다. 이 완전 연결 계층을 출력값의 개수가 새 데이터 세트의 클래스 개수와 같은(이 예제에서는 5) 새로운 완전 연결 계층으로 바꿉니다. SqueezeNet과 같은 일부 신경망에서는 학습 가능한 마지막 계층은 1×1 컨벌루션 계층이 됩니다. 이 경우 컨벌루션 계층을 필터의 개수가 클래스 개수와 같은 새로운 컨벌루션 계층으로 바꿉니다. 전이된 계층보다 새로운 계층에서 더 빠르게 학습할 수 있도록 하려면 계층의 학습률 인자 값을 높이십시오.

numClasses = numel(categories(imdsTrain.Labels));

if isa(learnableLayer,'nnet.cnn.layer.FullyConnectedLayer')
    newLearnableLayer = fullyConnectedLayer(numClasses, ...
        'Name','new_fc', ...
        'WeightLearnRateFactor',10, ...
        'BiasLearnRateFactor',10);
    
elseif isa(learnableLayer,'nnet.cnn.layer.Convolution2DLayer')
    newLearnableLayer = convolution2dLayer(1,numClasses, ...
        'Name','new_conv', ...
        'WeightLearnRateFactor',10, ...
        'BiasLearnRateFactor',10);
end

lgraph = replaceLayer(lgraph,learnableLayer.Name,newLearnableLayer);

분류 계층은 신경망의 출력 클래스를 지정합니다. 분류 계층을 클래스 레이블이 없는 새로운 계층으로 바꿉니다. trainNetwork는 훈련을 진행할 때 계층의 출력 클래스를 자동으로 설정합니다.

newClassLayer = classificationLayer('Name','new_classoutput');
lgraph = replaceLayer(lgraph,classLayer.Name,newClassLayer);

새로운 계층이 올바르게 연결되었는지 확인하려면 새로운 계층 그래프를 플로팅하고 신경망의 마지막 계층을 확대하십시오.

figure('Units','normalized','Position',[0.3 0.3 0.4 0.4]);
plot(lgraph)
ylim([0,10])

초기 계층 고정하기

새로운 영상 세트를 사용하여 신경망을 다시 훈련시킬 준비가 되었습니다. 선택적으로 신경망의 앞쪽 계층의 학습률을 설정하여 이전 계층의 가중치를 "고정"할 수 있습니다. 훈련 중에 trainNetwork는 고정된 계층의 파라미터를 업데이트하지 않습니다. 고정된 계층의 기울기를 계산할 필요가 없으므로 전반부에 있는 여러 계층의 가중치를 고정하면 신경망 훈련 속도를 대폭 높일 수 있습니다. 새로운 데이터 세트의 크기가 작다면 이전 신경망 계층을 고정함으로써 해당 계층이 새로운 데이터 세트에 과적합되지 않도록 할 수도 있습니다.

계층 그래프의 계층과 연결을 추출한 다음 고정할 계층을 선택합니다. GoogLeNet에서는 처음 10개의 계층이 신경망의 초기 '줄기'가 됩니다. 지원 함수 freezeWeights를 사용하여 처음 10개 계층의 학습률을 0으로 설정합니다. 지원 함수 createLgraphUsingConnections를 사용하여 모든 계층을 원래 순서대로 다시 연결합니다. 새로운 계층 그래프는 동일한 계층을 포함하지만 앞쪽 계층의 학습률이 0으로 설정되어 있습니다.

layers = lgraph.Layers;
connections = lgraph.Connections;

layers(1:10) = freezeWeights(layers(1:10));
lgraph = createLgraphUsingConnections(layers,connections);

신경망 훈련시키기

이 신경망의 입력 영상은 크기가 224×224×3이어야 하는데 영상 데이터저장소의 영상은 이와 크기가 다릅니다. 증대 영상 데이터저장소를 사용하여 훈련 영상의 크기를 자동으로 조정합니다. 훈련 영상에 대해 추가로 수행할 증대 연산을 지정합니다. 즉, 세로 축을 따라 훈련 영상을 무작위로 뒤집고, 최대 30개의 픽셀을 최대 10%까지 가로와 세로 방향으로 무작위로 평행 이동합니다. 데이터 증대는 신경망이 과적합되는 것을 방지하고 훈련 영상의 정확한 세부 정보가 기억되지 않도록 하는 데 도움이 됩니다.

pixelRange = [-30 30];
scaleRange = [0.9 1.1];
imageAugmenter = imageDataAugmenter( ...
    'RandXReflection',true, ...
    'RandXTranslation',pixelRange, ...
    'RandYTranslation',pixelRange, ...
    'RandXScale',scaleRange, ...
    'RandYScale',scaleRange);
augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain, ...
    'DataAugmentation',imageAugmenter);

추가적인 데이터 증대를 수행하지 않고 검증 영상의 크기를 자동으로 조정하려면 증대 영상 데이터저장소를 추가적인 전처리 연산 지정 없이 사용하십시오.

augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);

훈련 옵션을 지정합니다. 아직 고정되지 않은 전이된 계층의 학습을 늦추기 위해 InitialLearnRate를 작은 값으로 설정합니다. 이전 단계에서는 새로운 마지막 계층에서의 학습 속도를 높이기 위해 학습 가능한 마지막 계층의 학습률 인자를 증가시켰습니다. 이러한 조합으로 학습률을 설정하면 새로운 계층에서는 학습이 빨라지고 중간 계층에서는 학습이 느려지며 고정된 앞쪽 계층에서는 학습이 진행되지 않습니다.

훈련을 진행할 Epoch의 횟수를 지정합니다. 전이 학습을 수행할 때는 많은 횟수의 Epoch에 대해 훈련을 진행하지 않아도 됩니다. Epoch 1회는 전체 훈련 데이터 세트에 대한 하나의 완전한 훈련 주기를 의미합니다. 미니 배치 크기와 검증 데이터를 지정합니다. Epoch당 한 번씩 검증 정확도를 계산합니다.

miniBatchSize = 10;
valFrequency = floor(numel(augimdsTrain.Files)/miniBatchSize);
options = trainingOptions('sgdm', ...
    'MiniBatchSize',miniBatchSize, ...
    'MaxEpochs',6, ...
    'InitialLearnRate',3e-4, ...
    'Shuffle','every-epoch', ...
    'ValidationData',augimdsValidation, ...
    'ValidationFrequency',valFrequency, ...
    'Verbose',false, ...
    'Plots','training-progress');

훈련 데이터를 사용하여 신경망을 훈련시킵니다. 기본적으로 trainNetwork는 GPU를 사용할 수 있으면 GPU를 사용합니다. GPU를 사용하려면 Parallel Computing Toolbox™와 지원되는 GPU 장치가 필요합니다. 지원되는 장치에 대한 자세한 내용은 GPU 연산 요구 사항 (Parallel Computing Toolbox) 항목을 참조하십시오. GPU를 사용할 수 없으면 trainNetwork는 CPU를 사용합니다. trainingOptions'ExecutionEnvironment' 이름-값 쌍 인수를 사용하여 실행 환경을 지정할 수도 있습니다. 데이터 세트의 크기가 매우 작기 때문에 훈련이 빠르게 진행됩니다.

net = trainNetwork(augimdsTrain,lgraph,options);

검증 영상 분류하기

미세 조정된 신경망을 사용하여 검증 영상을 분류한 다음 분류 정확도를 계산합니다.

[YPred,probs] = classify(net,augimdsValidation);
accuracy = mean(YPred == imdsValidation.Labels)
accuracy = 0.9000

4개의 샘플 검증 영상을 예측된 레이블 및 이 레이블을 갖는 영상의 예측된 확률과 함께 표시합니다.

idx = randperm(numel(imdsValidation.Files),4);
figure
for i = 1:4
    subplot(2,2,i)
    I = readimage(imdsValidation,idx(i));
    imshow(I)
    label = YPred(idx(i));
    title(string(label) + ", " + num2str(100*max(probs(idx(i),:)),3) + "%");
end

참고 문헌

[1] Szegedy, Christian, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed, Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, and Andrew Rabinovich. "Going deeper with convolutions." In Proceedings of the IEEE conference on computer vision and pattern recognition, pp. 1-9. 2015.

참고 항목

| | | |

관련 항목