Main Content

메모리에 다 담을 수 없는 큰 시퀀스 데이터를 사용하여 신경망 훈련시키기

이 예제에서는 데이터저장소를 변환하고 결합하여 메모리에 다 담을 수 없을 정도로 큰 시퀀스 데이터를 대상으로 딥러닝 신경망을 훈련시키는 방법을 보여줍니다.

변환된 데이터저장소는 기본 데이터저장소에서 읽어 들인 데이터를 변환하거나 처리합니다. 변환된 데이터저장소는 딥러닝 애플리케이션을 위한 훈련, 검증, 테스트 및 예측 데이터 세트의 소스로 사용할 수 있습니다. 변환된 데이터저장소를 사용하여 메모리에 다 담을 수 없을 정도로 큰 데이터를 읽어 들이거나, 데이터를 배치 단위로 읽어 들일 때 특정 전처리 연산을 수행할 수 있습니다. 예측 변수가 담긴 데이터저장소와 레이블이 담긴 데이터저장소가 따로 있는 경우, 딥러닝 신경망에 데이터를 입력할 수 있도록 이 둘을 결합할 수 있습니다.

신경망을 훈련시킬 때 소프트웨어는 입력 데이터를 채우거나 자르거나 분할하여 동일한 길이의 시퀀스로 구성된 미니 배치를 만듭니다. 메모리 내 데이터에 대해서는 trainingOptions 함수가 입력 시퀀스를 채우고 자르기 위한 옵션을 제공하지만 메모리에 다 담을 수 없을 정도로 큰 데이터의 경우에는 시퀀스를 직접 채우고 잘라야 합니다.

훈련 데이터 불러오기

[1]과 [2]에서 설명한 Japanese Vowels 데이터 세트를 불러옵니다. zip 파일 japaneseVowels.zip은 다양한 길이의 시퀀스를 포함합니다. 이 시퀀스는 각각 훈련 시퀀스와 테스트 시퀀스를 포함하는 TrainTest라는 두 폴더로 나뉘어 있습니다. 각 폴더에서 시퀀스는 1부터 9까지 번호가 지정된 하위 폴더로 나뉘어 있습니다. 하위 폴더의 이름은 레이블 이름입니다. 하나의 MAT 파일은 각 시퀀스를 나타냅니다. 각 시퀀스는 각 특징에 대해 하나의 행을 갖는 12개의 행과 각 시간 스텝에 대해 하나의 열을 갖는 가변 개수의 열로 이루어진 행렬입니다. 행 개수는 시퀀스 차원이고, 열 개수는 시퀀스 길이입니다.

시퀀스 데이터의 압축을 풉니다.

filename = "japaneseVowels.zip";
outputFolder = fullfile(tempdir,"japaneseVowels");
unzip(filename,outputFolder);

훈련 예측 변수에 사용할 파일 데이터저장소를 만들고 load 함수를 읽기 함수로 지정합니다. load 함수는 데이터를 MAT 파일에서 구조체형 배열로 불러옵니다. 훈련 폴더에 있는 하위 폴더에서 파일을 읽어 들이려면 'IncludeSubfolders' 옵션을 true로 설정하십시오.

folderTrain = fullfile(outputFolder,"Train");
fdsPredictorTrain = fileDatastore(folderTrain, ...
    'ReadFcn',@load, ...
    'IncludeSubfolders',true);

데이터저장소를 미리 봅니다. 반환된 구조체는 첫 번째 파일 내 단일 시퀀스를 포함합니다.

preview(fdsPredictorTrain)
ans = struct with fields:
    X: [12×20 double]

레이블에 사용할 파일 데이터저장소를 만들고 이 예제의 마지막 부분에 정의되어 있는 readLabel 함수를 읽기 함수로 지정합니다. readLabel 함수는 하위 폴더 이름에서 레이블을 추출합니다.

classNames = string(1:9);
fdsLabelTrain = fileDatastore(folderTrain, ...
    'ReadFcn',@(filename) readLabel(filename,classNames), ...
    'IncludeSubfolders',true);

데이터저장소를 미리 봅니다. 출력값은 첫 번째 파일의 레이블에 대응됩니다.

preview(fdsLabelTrain)
ans = categorical
     1 

데이터저장소를 변환하고 결합하기

예측 변수 데이터저장소의 시퀀스 데이터를 딥러닝 신경망에 입력하려면 시퀀스로 구성된 미니 배치들의 길이가 동일해야 합니다. 데이터저장소 마지막 부분에 정의된 padSequence 함수를 사용하여 데이터저장소를 변환합니다. 이 함수는 시퀀스의 길이가 20이 되도록 시퀀스를 채우거나 자릅니다.

sequenceLength = 20;
tdsTrain = transform(fdsPredictorTrain,@(data) padSequence(data,sequenceLength));

변환된 데이터저장소를 미리 봅니다. 출력값은 첫 번째 파일의 채워진 시퀀스에 대응됩니다.

X = preview(tdsTrain)
X = 1×1 cell array
    {12×20 double}

두 데이터저장소의 예측 변수와 레이블을 모두 딥러닝 신경망에 입력하려면 combine 함수를 사용하여 결합하십시오.

cdsTrain = combine(tdsTrain,fdsLabelTrain);

결합된 데이터저장소를 미리 봅니다. 데이터저장소가 1×2 셀형 배열을 반환합니다. 첫 번째 요소는 예측 변수에 대응됩니다. 두 번째 요소는 레이블에 대응됩니다.

preview(cdsTrain)
ans=1×2 cell array
    {12×20 double}    {[1]}

LSTM 신경망 아키텍처 정의하기

LSTM 신경망 아키텍처를 정의합니다. 입력 데이터의 특징 개수를 입력 크기로 지정합니다. 은닉 유닛 100개를 갖는 LSTM 계층을 지정하고 시퀀스의 마지막 요소를 출력합니다. 마지막으로, 출력 크기가 클래스 개수와 같은 완전 연결 계층을 지정하고 그 뒤에 소프트맥스 계층을 지정합니다.

numFeatures = 12;
numClasses = numel(classNames);
numHiddenUnits = 100;

layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','last')
    fullyConnectedLayer(numClasses)
    softmaxLayer];

훈련 옵션을 지정합니다. 옵션 중에서 선택하려면 경험적 분석이 필요합니다. 실험을 실행하여 다양한 훈련 옵션 구성을 살펴보려면 실험 관리자 앱을 사용합니다.

  • Adam 최적화 함수를 사용하여 훈련시킵니다.

  • 훈련 데이터는 행과 열이 각각 채널과 시간 스텝에 대응하는 시퀀스를 가지므로 입력 데이터 형식 "CTB"(채널, 시간, 배치)를 지정합니다.

  • 최대 Epoch 횟수를 75로 설정합니다.

  • 미니 배치 크기로 27을 사용합니다.

  • 기울기 임계값 2로 훈련시킵니다.

  • 데이터저장소가 섞기를 지원하지 않으므로 데이터를 섞지 않도록 합니다.

  • CPU를 사용하여 훈련시킵니다. 신경망과 데이터가 작으므로 CPU가 더 적절합니다. GPU를 사용할 수 있는 경우 GPU에서 훈련시키려면 'ExecutionEnvironment' option'auto'(디폴트 값)로 설정하십시오.

  • 상세 출력값을 비활성화합니다.

  • 훈련 진행 상황을 플롯으로 표시하고 정확도를 모니터링합니다.

miniBatchSize = 27;

options = trainingOptions('adam', ...
    'InputDataFormats','CTB', ...
    'MaxEpochs',75, ...
    'MiniBatchSize',miniBatchSize, ...
    'GradientThreshold',2, ...
    'Shuffle','never',...
    'ExecutionEnvironment','cpu', ...
    'Verbose',0, ...
    'Plots','training-progress');

trainnet 함수를 사용하여 신경망을 훈련시킵니다. 분류에는 교차 엔트로피 손실을 사용합니다.

net = trainnet(cdsTrain,layers,"crossentropy",options);

신경망 테스트하기

훈련 데이터와 동일한 단계를 사용하여, 홀드아웃 테스트 데이터를 포함하는 변환된 데이터저장소를 만듭니다.

folderTest = fullfile(outputFolder,"Test");

fdsPredictorTest = fileDatastore(folderTest, ...
    'ReadFcn',@load, ...
    'IncludeSubfolders',true);
tdsTest = transform(fdsPredictorTest,@(data) padSequence(data,sequenceLength));

minibatchpredict 함수를 사용하여 예측을 수행합니다. 기본적으로 minibatchpredict 함수는 GPU를 사용할 수 있으면 GPU를 사용합니다. GPU를 사용하려면 Parallel Computing Toolbox™ 라이선스와 지원되는 GPU 장치가 필요합니다. 지원되는 장치에 대한 자세한 내용은 GPU 연산 요구 사항 (Parallel Computing Toolbox) 항목을 참조하십시오. GPU를 사용할 수 없는 경우, 함수는 CPU를 사용합니다. 실행 환경을 지정하려면 ExecutionEnvironment 옵션을 사용하십시오.

데이터는 행과 열이 각각 채널과 시간 스텝에 대응하는 시퀀스를 가지므로 입력 데이터 형식 "CTB"(채널, 시간, 배치)를 지정합니다.

scores = minibatchpredict(net,tdsTest,MiniBatchSize=miniBatchSize,InputDataFormats="CTB");
YPred = scores2label(scores,classNames);

테스트 데이터에 대한 분류 정확도를 계산합니다. 테스트 세트의 레이블을 얻으려면 읽기 함수 readLabel을 사용하여 파일 데이터저장소를 만들고 하위 폴더를 포함하도록 지정하십시오. 'UniformRead' 옵션을 true로 설정하여 출력값의 세로 결합이 가능하도록 지정합니다.

fdsLabelTest = fileDatastore(folderTest, ...
    'ReadFcn',@(filename) readLabel(filename,classNames), ...
    'IncludeSubfolders',true, ...
    'UniformRead',true);
YTest = readall(fdsLabelTest);

accuracy = mean(YPred == YTest)
accuracy = 
0.9432

함수

readLabel 함수는 classNames의 범주에 대해 지정된 파일 이름에서 레이블을 추출합니다.

function label = readLabel(filename,classNames)

filepath = fileparts(filename);
[~,label] = fileparts(filepath);

label = categorical(string(label),classNames);

end

padSequence 함수는 data.X의 시퀀스가 지정된 길이를 갖도록 시퀀스를 채우거나 자르고 결과를 1×1 셀에 반환합니다.

function sequence = padSequence(data,sequenceLength)

sequence = data.X;
[C,S] = size(sequence);

if S < sequenceLength
    padding = zeros(C,sequenceLength-S);
    sequence = [sequence padding];
else
    sequence = sequence(:,1:sequenceLength);
end

sequence = {sequence};

end

참고 항목

| | | | | |

관련 항목