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

새로운 이미지를 분류하도록 심층 학습 네트워크 훈련시키기

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

사전 훈련된 이미지 분류 네트워크는 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 속성의 첫 번째 요소는 이미지 입력 계층입니다. 이 계층에 입력되는 이미지는 크기가 224x224x3이어야 합니다. 여기서 3은 색 채널의 개수입니다.

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

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

   Hyperparameters
    DataAugmentation: 'none'
       Normalization: 'zerocenter'
        AverageImage: [224x224x3 single]

inputSize = net.Layers(1).InputSize;

마지막 계층 바꾸기

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

훈련된 네트워크에서 계층 그래프를 추출합니다. 네트워크가 AlexNet, VGG-16 또는 VGG-19와 같은 SeriesNetwork 객체라면 net.Layers의 계층 목록을 계층 그래프로 변환합니다.

if isa(net,'SeriesNetwork') 
  lgraph = layerGraph(net.Layers); 
else
  lgraph = layerGraph(net);
end 

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

[learnableLayer,classLayer] = findLayersToReplace(lgraph);
[learnableLayer,classLayer] 
ans = 
  1x2 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과 같은 일부 네트워크에서는 학습 가능한 마지막 계층은 1x1 컨벌루션 계층이 됩니다. 이 경우 컨벌루션 계층을 필터의 개수가 클래스 개수와 같은 새로운 컨벌루션 계층으로 바꿉니다. 전이된 계층보다 새로운 계층에서 더 빠르게 학습할 수 있도록 하려면 계층의 학습률 인자 값을 높이십시오.

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

네트워크 훈련시키기

이 네트워크의 입력 이미지는 크기가 224x224x3이어야 하는데 이미지 데이터저장소의 이미지는 이와 크기가 다릅니다. 증대 이미지 데이터저장소를 사용하여 훈련 이미지의 크기를 자동으로 조정합니다. 훈련 이미지에 대해 추가로 수행할 증대 연산을 지정합니다. 즉, 세로 축을 따라 훈련 이미지를 무작위로 뒤집고, 최대 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를 사용합니다(Parallel Computing Toolbox™와 Compute Capability 3.0 이상의 CUDA® 지원 GPU 필요). 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.

참고 항목

| | | | | | | | | |

관련 항목