parfeval
을 사용하여 다중 딥러닝 신경망 훈련시키기
이 예제에서는 parfeval
을 사용하여 딥러닝 신경망에 대한 신경망 아키텍처의 심도를 기반으로 파라미터 스윕을 수행하고 훈련 중에 데이터를 가져오는 방법을 보여줍니다.
딥러닝 훈련에는 종종 몇 시간 또는 며칠이 소요되며 양질의 아키텍처를 찾기가 어려울 수 있습니다. 양질의 모델을 찾을 때 병렬 연산을 사용하여 검색 속도를 높이고 검색을 자동화할 수 있습니다. 복수의 GPU(그래픽 처리 장치)가 장착된 컴퓨터를 사용하는 경우에는 로컬 병렬 풀로 복사된 로컬 데이터 세트로 이 예제를 실행할 수 있습니다. 더 많은 리소스를 사용하기 위해 딥러닝 훈련을 클라우드로 확장할 수 있습니다. 이 예제에서는 클라우드에 있는 클러스터의 신경망 아키텍처의 심도를 기반으로 파라미터 스윕을 수행하기 위해 parfeval
을 사용하는 방법을 보여줍니다. parfeval
을 사용하면 MATLAB 사용을 차단하지 않으면서 백그라운드에서 훈련시킬 수 있고, 결과가 만족할 만한 수준이면 예정보다 이르게 중단하는 옵션이 제공됩니다. 다른 파라미터를 기반으로 파라미터 스윕을 수행하도록 이 스크립트를 수정할 수 있습니다. 이 예제에서는 DataQueue
를 사용하여 연산 중에 워커로부터 피드백을 받는 방법도 보여줍니다.
요구 사항
이 예제를 실행하려면 먼저 클러스터를 구성하고 데이터를 클라우드로 업로드해야 합니다. 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);
augmentedImageDatastore
객체 생성을 이용하여 증강 영상 데이터로 신경망을 훈련시킵니다. 이때 무작위 평행 이동 및 가로 반사를 사용합니다. 데이터 증강은 신경망이 과적합되는 것을 방지하고 훈련 영상의 정확한 세부 정보가 기억되지 않도록 하는 데 도움이 됩니다.
imageSize = [32 32 3]; pixelRange = [-4 4]; imageAugmenter = imageDataAugmenter( ... RandXReflection=true, ... RandXTranslation=pixelRange, ... RandYTranslation=pixelRange); augmentedImdsTrain=augmentedImageDatastore(imageSize,imdsTrain, ... DataAugmentation=imageAugmenter, ... OutputSizeMode="randcrop");
여러 신경망을 동시에 훈련시키기
훈련 옵션을 지정합니다. 미니 배치 크기를 설정하고, 미니 배치 크기에 비례하여 초기 학습률을 확장합니다. trainnet
이 Epoch당 한 번씩 신경망을 검증하도록 검증 빈도를 설정합니다.
miniBatchSize = 128; initialLearnRate = 1e-1 * miniBatchSize/256; validationFrequency = floor(numel(imdsTrain.Labels)/miniBatchSize); options = trainingOptions("sgdm", ... MiniBatchSize=miniBatchSize, ... % Set the mini-batch size Verbose=false, ... % Do not send command line output. Metrics="accuracy", ... InitialLearnRate=initialLearnRate, ... % Set the scaled learning rate. L2Regularization=1e-10, ... MaxEpochs=30, ... Shuffle="every-epoch", ... ValidationData=imdsValidation, ... ValidationFrequency=validationFrequency);
파라미터 스윕을 수행할 신경망 아키텍처의 심도를 지정합니다. parfeval
을 사용하여 여러 신경망을 동시에 훈련시키는 병렬 파라미터 스윕을 수행합니다. 루프를 사용하여 스윕의 여러 신경망 아키텍처를 모두 반복합니다. 신경망 심도를 제어하는 입력 인수를 받아 CIFAR-10에 대한 아키텍처를 생성하는 헬퍼 함수 createNetworkArchitecture
를 스크립트 끝에 만듭니다. parfeval
을 사용하여 클러스터에 있는 워커로 trainnet
이 수행하는 연산 작업을 넘겨줍니다. parfeval
은 연산이 완료되면 훈련된 신경망과 훈련 정보를 저장할 Future 변수를 반환합니다.
기본적으로 trainnet
함수는 GPU를 사용할 수 있으면 GPU를 사용합니다. GPU에서 훈련시키려면 Parallel Computing Toolbox™ 라이선스와 지원되는 GPU 장치가 필요합니다. 지원되는 장치에 대한 자세한 내용은 GPU 연산 요구 사항 (Parallel Computing Toolbox) 항목을 참조하십시오. GPU를 사용할 수 없는 경우, trainnet
함수는 CPU를 사용합니다. 실행 환경을 지정하려면 ExecutionEnvironment
훈련 옵션을 사용하십시오.
netDepths = 1:4; numExperiments = numel(netDepths); for idx = 1:numExperiments networksFuture(idx) = parfeval(@trainnet,2, ... augmentedImdsTrain,createNetworkArchitecture(netDepths(idx)),"crossentropy",options); end
Starting parallel pool (parpool) using the 'MyCluster' profile ... Connected to parallel pool with 4 workers (PreferredPoolNumWorkers).
parfeval
은 MATLAB 사용을 차단하지 않으므로 명령을 계속해서 실행할 수 있습니다. 여기서는 networksFuture
에 fetchOutputs
를 사용하여 훈련된 신경망과 해당 훈련 정보를 가져옵니다. fetchOutputs
함수는 Future 변수가 끝날 때까지 기다립니다.
[trainedNetworks,trainingInfo] = fetchOutputs(networksFuture);
trainingInfo
구조체에 액세스하여 신경망의 최종 검증 정확도를 가져옵니다.
for idx = 1:numExperiments validationHistory = trainingInfo(idx).ValidationHistory; accuracies(idx) = validationHistory.Accuracy(end); end accuracies
accuracies = 1×4
70.7200 78.8200 76.1000 78.0200
정확도 측면에서 가장 좋은 신경망을 선택합니다.
[~, I] = max(accuracies); bestNetwork = trainedNetworks(I(1));
테스트 데이터 세트를 기준으로 신경망의 성능을 테스트합니다. 여러 개의 관측값을 사용하여 예측을 수행하려면 minibatchpredict
함수를 사용합니다. 예측 점수를 레이블로 변환하려면 scores2label
함수를 사용합니다. minibatchpredict
함수는 GPU를 사용할 수 있으면 자동으로 GPU를 사용합니다.
classNames = categories(imdsTest.Labels); scores = minibatchpredict(bestNetwork,imdsTest); Y = scores2label(scores,classNames); accuracy = sum(Y == imdsTest.Labels)/numel(imdsTest.Labels)
accuracy = 0.7798
테스트 데이터에 대해 혼동행렬을 계산합니다.
figure confusionchart(imdsTest.Labels,Y,RowSummary="row-normalized",ColumnSummary="column-normalized");
훈련 중에 피드백 데이터 보내기
각 워커에서 훈련 진행 상황을 보여주는 플롯을 준비하고 초기화합니다. 변경되는 데이터를 간편하게 보기 위해 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{:}));
파라미터 스윕을 수행할 신경망 아키텍처의 심도를 지정하고 parfeval
을 사용하여 병렬 파라미터 스윕을 수행합니다. 스크립트를 현재 풀에 첨부 파일로 추가하여 워커들이 이 스크립트의 헬퍼 함수에 액세스할 수 있도록 합니다. 워커에서 클라이언트로 훈련 진행 상황을 전송할 출력 함수를 훈련 옵션에 정의합니다. 훈련 옵션은 워커의 인덱스에 따라 달라지며, for
루프 안에 포함되어야 합니다.
netDepths = 1:4; addAttachedFiles(gcp,mfilename); for idx = 1:numel(netDepths) miniBatchSize = 128; initialLearnRate = 1e-1 * miniBatchSize/256; % Scale the learning rate according to the mini-batch size. validationFrequency = floor(numel(imdsTrain.Labels)/miniBatchSize); options = trainingOptions("sgdm", ... OutputFcn=@(state) sendTrainingProgress(D,idx,state), ... % Set an output function to send intermediate results to the client. 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, ... ValidationFrequency=validationFrequency); networksFuture(idx) = parfeval(@trainnet,2, ... augmentedImdsTrain,createNetworkArchitecture(netDepths(idx)),"crossentropy",options); end
parfeval
은 클러스터에 있는 워커에 대해 trainnet
을 호출합니다. 연산이 백그라운드에서 진행되므로 계속해서 MATLAB을 사용할 수 있습니다. parfeval
연산을 중지하려면 연산에 대응되는 Future 변수에 대해 cancel
을 호출하면 됩니다. 예를 들어, 신경망의 성능이 부진한 것을 발견한 경우 해당 신경망의 Future 변수를 취소하면 됩니다. 이렇게 하면 대기 중이던 다음 Future 변수가 연산을 시작합니다.
여기서는 Future 변수에 대해 fetchOutputs
를 호출하여 훈련된 신경망과 해당 훈련 정보를 가져옵니다.
[trainedNetworks,trainingInfo] = fetchOutputs(networksFuture);
각 신경망의 최종 검증 정확도를 가져옵니다.
for idx = 1:numExperiments validationHistory = trainingInfo(idx).ValidationHistory; accuracies(idx) = validationHistory.Accuracy(end); end accuracies
accuracies = 1×4
71.4600 78.3600 74.4000 79.3800
헬퍼 함수
함수를 사용하여 CIFAR-10 데이터 세트에 대한 신경망 아키텍처를 정의하고, 입력 인수를 사용하여 신경망 심도를 조정합니다. 코드를 단순화하려면 입력값을 컨벌루션하는 컨벌루션 블록을 사용하십시오. 풀링 계층은 공간 차원을 다운샘플링합니다.
function layers = createNetworkArchitecture(netDepth) imageSize = [32 32 3]; netWidth = round(16/sqrt(netDepth)); % 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 ]; end
신경망 아키텍처에서 컨벌루션 블록을 만드는 함수를 정의합니다.
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
참고 항목
parfeval
(Parallel Computing Toolbox) | afterEach
| trainnet
| trainingOptions
| dlnetwork
| imageDatastore