Main Content

parfor를 사용하여 다중 딥러닝 신경망 훈련시키기

이 예제에서는 parfor 루프를 사용하여 훈련 옵션에 대해 파라미터 스윕을 수행하는 방법을 보여줍니다.

딥러닝 훈련에는 종종 몇 시간이나 며칠이 소요되므로 양질의 훈련 옵션을 찾기가 어려울 수 있습니다. 양질의 모델을 찾을 때 병렬 연산을 사용하여 검색 속도를 높이고 검색을 자동화할 수 있습니다. 복수의 GPU(그래픽 처리 장치)가 장착된 컴퓨터를 사용하는 경우에는 로컬 parpool을 사용하여 이 예제를 데이터 세트의 로컬 복사본에 대해 실행할 수 있습니다. 더 많은 리소스를 사용하기 위해 딥러닝 훈련을 클라우드로 확장할 수 있습니다. 이 예제에서는 parfor 루프를 사용하여 클라우드에 있는 클러스터에서 훈련 옵션 MiniBatchSize에 대해 파라미터 스윕을 수행하는 방법을 보여줍니다. 다른 훈련 옵션에 대해 파라미터 스윕을 수행하도록 스크립트를 수정할 수 있습니다. 이 예제에서는 DataQueue를 사용하여 연산 중에 워커로부터 피드백을 받는 방법도 보여줍니다. 이 스크립트는 클러스터에 일괄 처리 작업으로 전송할 수도 있으므로 작업을 계속 진행할 수도 있고 MATLAB을 닫은 후 나중에 결과를 가져올 수도 있습니다. 자세한 내용은 딥러닝 일괄 처리 작업을 클러스터로 보내기 항목을 참조하십시오.

요구 사항

이 예제를 실행하려면 먼저 클러스터를 구성하고 데이터를 클라우드로 업로드해야 합니다. MATLAB에서는 MATLAB 데스크탑에서 직접 클라우드에 클러스터를 만들 수 있습니다. 탭의 병렬연산 메뉴에서 클러스터 생성 및 관리를 선택합니다. 클러스터 프로파일 관리자에서 클라우드 클러스터 생성을 클릭합니다. 또는 MathWorks Cloud Center를 사용하여 계산 클러스터를 만들고 액세스할 수도 있습니다. 자세한 내용은 Getting Started with Cloud Center를 참조하십시오. 이 예제에서는 MATLAB 탭의 병렬연산 > 디폴트 클러스터 선택에서 방금 만든 클러스터가 디폴트 값으로 설정되어 있는지 확인하십시오. 그런 다음 Amazon S3 버킷으로 데이터를 업로드하면 MATLAB에서 직접 사용할 수 있습니다. 이 예제에서는 기존에 Amazon S3에 저장되어 있는 CIFAR-10 데이터 세트 복사본을 사용합니다. 자세한 지침은 AWS에서 딥러닝 데이터 사용하기 항목을 참조하십시오.

클라우드에서 데이터 세트 불러오기

imageDatastore를 사용하여 클라우드에서 훈련 데이터 세트와 테스트 데이터 세트를 불러옵니다. 훈련 데이터 세트를 훈련용 세트와 검증용 세트로 분할하고, 테스트 데이터 세트는 파라미터 스윕에서 얻게 될 가장 좋은 신경망을 테스트할 용도로 보관해 둡니다. 훈련 데이터의 클래스 이름을 확인합니다. 이 예제에서는 Amazon S3에 저장되어 있는 CIFAR-10 데이터 세트 복사본을 사용합니다. 워커가 클라우드의 데이터저장소에 액세스할 수 있도록 하려면 AWS 자격 증명의 환경 변수가 올바르게 설정되었는지 확인하십시오. AWS에서 딥러닝 데이터 사용하기 항목을 참조하십시오.

imds = imageDatastore("s3://cifar10cloud/cifar10/train", ...
     IncludeSubfolders=true, ...
     LabelSource="foldernames");
 
imdsTest = imageDatastore("s3://cifar10cloud/cifar10/test", ...
    IncludeSubfolders=true, ...
    LabelSource="foldernames");

[imdsTrain,imdsValidation] = splitEachLabel(imds,0.9);
classNames = categories(imdsTrain.Labels)
classNames = 10×1 cell
    {'airplane'  }
    {'automobile'}
    {'bird'      }
    {'cat'       }
    {'deer'      }
    {'dog'       }
    {'frog'      }
    {'horse'     }
    {'ship'      }
    {'truck'     }

augmentedImageDatastore 객체 생성을 이용하여 증대 영상 데이터로 신경망을 훈련시킵니다. 이때 무작위 평행 이동 및 가로 반사를 사용합니다. 데이터 증대는 신경망이 과적합되는 것을 방지하고 훈련 영상의 정확한 세부 정보가 기억되지 않도록 하는 데 도움이 됩니다.

imageSize = [32 32 3];
pixelRange = [-4 4];
imageAugmenter = imageDataAugmenter( ...
    RandXReflection=true, ...
    RandXTranslation=pixelRange, ...
    RandYTranslation=pixelRange);
augmentedImdsTrain = augmentedImageDatastore(imageSize,imdsTrain, ...
    DataAugmentation=imageAugmenter, ...
    OutputSizeMode="randcrop");

신경망 아키텍처 정의하기

CIFAR-10 데이터 세트에 대해 신경망 아키텍처를 정의합니다. 코드를 단순화하려면 입력값을 컨벌루션하는 컨벌루션 블록을 사용하십시오. 풀링 계층은 공간 차원을 다운샘플링합니다.

imageSize = [32 32 3];
netDepth = 2; % netDepth controls the depth of a convolutional block
netWidth = 16; % netWidth controls the number of filters in a convolutional block

layers = [
    imageInputLayer(imageSize)
    
    convolutionalBlock(netWidth,netDepth)
    maxPooling2dLayer(2,Stride=2)
    convolutionalBlock(2*netWidth,netDepth)
    maxPooling2dLayer(2,Stride=2)
    convolutionalBlock(4*netWidth,netDepth)
    averagePooling2dLayer(8)
    
    fullyConnectedLayer(10)
    softmaxLayer
    ];

여러 신경망을 동시에 훈련시키기

파라미터 스윕을 수행할 미니 배치 크기를 지정합니다. 결과 신경망과 정확도에 대한 변수를 할당합니다.

miniBatchSizes = [64 128 256 512];
numMiniBatchSizes = numel(miniBatchSizes);
trainedNetworks = cell(numMiniBatchSizes,1);
accuracies = zeros(numMiniBatchSizes,1);

parfor 루프 안에서 미니 배치 크기를 달리하며 여러 신경망을 훈련시키는 병렬 파라미터 스윕을 수행합니다. 클러스터의 워커들이 여러 신경망을 동시에 훈련시키고, 훈련이 완료되면 훈련된 신경망과 정확도를 반환합니다. 훈련이 제대로 진행되고 있는지 확인하려면 훈련 옵션에서 Verbosetrue로 설정하십시오. 워커들은 각각 독립적으로 연산을 수행하므로 명령줄 출력값은 반복이 실행되는 순서와 상관없이 표시됩니다.

parfor idx = 1:numMiniBatchSizes
    
    miniBatchSize = miniBatchSizes(idx);
    initialLearnRate = 1e-1 * miniBatchSize/256; % Scale the learning rate according to the mini-batch size.
    
    % Define the training options. Set the mini-batch size.
    options = trainingOptions("sgdm", ...
        MiniBatchSize=miniBatchSize, ... % Set the corresponding MiniBatchSize in the sweep.
        Verbose=false, ... % Do not send command line output.
        InitialLearnRate=initialLearnRate, ... % Set the scaled learning rate.
        Metrics="accuracy", ...
        L2Regularization=1e-10, ...
        MaxEpochs=30, ...
        Shuffle="every-epoch", ...
        ValidationData=imdsValidation, ...
        LearnRateSchedule="piecewise", ...
        LearnRateDropFactor=0.1, ...
        LearnRateDropPeriod=25);
    
    % Train the network in a worker in the cluster.
    net = trainnet(augmentedImdsTrain,layers,"crossentropy",options);
    
    % To obtain the accuracy of this network, use the trained network to
    % classify the validation images on the worker and compare the predicted labels to the
    % actual labels.
    scores = minibatchpredict(net,imdsValidation);
    Y = scores2label(scores,classNames);
    accuracies(idx) = sum(Y == imdsValidation.Labels)/numel(imdsValidation.Labels);
    
    % Send the trained network back to the client.
    trainedNetworks{idx} = net;
end
Starting parallel pool (parpool) using the 'MyClusterInTheCloud' profile ...
Connected to parallel pool with 4 workers (PreferredPoolNumWorkers).

parfor가 완료되면 trainedNetworks에는 워커들에 의해 훈련된 결과 신경망들이 포함됩니다. 훈련된 신경망과 그 정확도를 표시합니다.

trainedNetworks
trainedNetworks=4×1 cell array
    {1×1 dlnetwork}
    {1×1 dlnetwork}
    {1×1 dlnetwork}
    {1×1 dlnetwork}

accuracies
accuracies = 4×1

    0.8404
    0.8378
    0.8374
    0.8346

정확도 측면에서 가장 좋은 신경망을 선택합니다. 테스트 데이터 세트를 기준으로 신경망의 성능을 테스트합니다.

[~, I] = max(accuracies);
bestNetwork = trainedNetworks{I(1)};

scores = minibatchpredict(bestNetwork,imdsTest);
Y = scores2label(scores,classNames);
accuracy = sum(Y == imdsTest.Labels)/numel(imdsTest.Labels)
accuracy = 0.8374

훈련 중에 피드백 데이터 보내기

각 워커에서 훈련 진행 상황을 보여주는 플롯을 준비하고 초기화합니다. 변경되는 데이터를 간편하게 보기 위해 animatedLine을 사용합니다.

f = figure;
f.Visible = true;
for i=1:4
    subplot(2,2,i)
    xlabel('Iteration');
    ylabel('Training accuracy');
    lines(i) = animatedline;
end

DataQueue를 사용하여 워커에서 클라이언트로 훈련 진행 상황 데이터를 보내고 데이터를 플로팅합니다. afterEach를 사용하여 워커가 훈련 진행 상황 피드백을 보낼 때마다 플롯을 업데이트합니다. 파라미터 opts에는 워커, 훈련 반복 및 훈련 정확도에 대한 정보가 포함됩니다.

D = parallel.pool.DataQueue;
afterEach(D, @(opts) updatePlot(lines, opts{:}));

parfor 루프 안에서 미니 배치 크기를 달리하며 여러 신경망을 훈련시키는 병렬 파라미터 스윕을 수행합니다. 각 반복이 수행될 때마다 클라이언트로 훈련 진행 상황을 보내도록 훈련 옵션에서 OutputFcn이 사용된 것을 볼 수 있습니다.

parfor idx = 1:numMiniBatchSizes
    
    miniBatchSize = miniBatchSizes(idx);
    initialLearnRate = 1e-1 * miniBatchSize/256; % Scale the learning rate according to the miniBatchSize.
    
    % Define the training options. Set an output function to send data back
    % to the client each iteration.
    options = trainingOptions("sgdm", ...
        MiniBatchSize=miniBatchSize, ... % Set the corresponding MiniBatchSize in the sweep.
        Verbose=false, ... % Do not send command line output.
        InitialLearnRate=initialLearnRate, ... % Set the scaled learning rate.
        OutputFcn=@(state) sendTrainingProgress(D,idx,state), ... % Set an output function to send intermediate results to the client.
        Metrics="accuracy", ...
        L2Regularization=1e-10, ...
        MaxEpochs=30, ...
        Shuffle="every-epoch", ...
        ValidationData=imdsValidation, ...
        LearnRateSchedule="piecewise", ...
        LearnRateDropFactor=0.1, ...
        LearnRateDropPeriod=25);
    
    % Train the network in a worker in the cluster. The workers send
    % training progress information during training to the client.
    net = trainnet(augmentedImdsTrain,layers,"crossentropy",options);
    
    % To obtain the accuracy of this network, use the trained network to
    % classify the validation images on the worker and compare the predicted labels to the
    % actual labels.
    scores = minibatchpredict(net,imdsValidation);
    Y = scores2label(scores,classNames);
    accuracies(idx) = sum(Y == imdsValidation.Labels)/numel(imdsValidation.Labels);
    
    % Send the trained network back to the client.
    trainedNetworks{idx} = net;
end

parfor가 완료되면 trainedNetworks에는 워커들에 의해 훈련된 결과 신경망들이 포함됩니다. 훈련된 신경망과 그 정확도를 표시합니다.

trainedNetworks
trainedNetworks=4×1 cell array
    {1×1 dlnetwork}
    {1×1 dlnetwork}
    {1×1 dlnetwork}
    {1×1 dlnetwork}

accuracies
accuracies = 4×1

    0.8388
    0.8288
    0.8326
    0.8226

정확도 측면에서 가장 좋은 신경망을 선택합니다. 테스트 데이터 세트를 기준으로 신경망의 성능을 테스트합니다.

[~, I] = max(accuracies);
bestNetwork = trainedNetworks{I(1)};

scores = minibatchpredict(bestNetwork,imdsTest);
Y = scores2label(scores,classNames);
accuracy = sum(Y == imdsTest.Labels)/numel(imdsTest.Labels)
accuracy = 0.8352

헬퍼 함수

신경망 아키텍처에서 컨벌루션 블록을 만드는 함수를 정의합니다.

function layers = convolutionalBlock(numFilters,numConvLayers)
layers = [
    convolution2dLayer(3,numFilters,Padding="same")
    batchNormalizationLayer
    reluLayer
    ];

layers = repmat(layers,numConvLayers,1);
end

DataQueue를 통해 훈련 진행 상황을 클라이언트로 보내는 함수를 정의합니다.

function stop = sendTrainingProgress(D,idx,info)
if info.State == "iteration" && ~isempty(info.TrainingAccuracy)
    send(D,{idx,info.Iteration,info.TrainingAccuracy});
end
stop = false;
end

워커가 중간 결과를 전송하면 이에 따라 플롯을 업데이트하는 업데이트 함수를 정의합니다.

function updatePlot(lines,idx,iter,acc)
addpoints(lines(idx),iter,acc);
drawnow limitrate nocallbacks
end

참고 항목

| | | (Parallel Computing Toolbox) |

관련 예제

세부 정보