Main Content

딥러닝을 사용한 sequence-to-sequence 회귀

이 예제에서는 딥러닝을 사용하여 엔진의 잔여 수명(RUL)을 예측하는 방법을 보여줍니다.

시계열 또는 시퀀스 데이터로부터 숫자형 값을 예측하도록 심층 신경망을 훈련시키기 위해 장단기 기억(LSTM) 신경망을 사용할 수 있습니다.

이 예제에서는 [1]에서 설명한 Turbofan Engine Degradation Simulation Data Set를 사용합니다. 이 예제에서는 엔진의 여러 센서를 나타내는 시계열 데이터를 준 다음, 예측 정비 관점에서 엔진의 잔여 수명(단위: 주기)을 예측하도록 LSTM 신경망을 훈련시킵니다. 훈련 데이터는 엔진 100개의 시뮬레이션된 시계열 데이터를 포함합니다. 각 시퀀스는 길이가 다양하며, 하나의 완전한 RTF(run to failure) 인스턴스에 대응됩니다. 테스트 데이터는 100개의 부분 시퀀스를 포함합니다. 각 시퀀스의 마지막에는 잔여 수명에 대응되는 값이 포함됩니다.

데이터 세트는 100개의 훈련 관측값과 100개의 테스트 관측값을 포함합니다.

데이터 다운로드하기

Turbofan Engine Degradation Simulation 데이터 세트를 다운로드하고 압축을 풉니다.

Turbofan Engine Degradation Simulation 데이터 세트의 각 시계열은 서로 다른 엔진을 나타냅니다. 각 엔진은 알려지지 않은 초기 마모 및 제작 편차가 있는 상태에서 구동되기 시작합니다. 각 시계열의 시작 시에 엔진은 정상적으로 동작하며, 시계열의 어느 시점에서 결함이 발생합니다. 훈련 세트에서 결함의 크기는 시스템 결함이 발생할 때까지 커집니다.

데이터는 공백으로 구분된 26개 숫자 열의 형태로 압축 텍스트 파일에 들어 있습니다. 각 행은 1회의 동작 주기 동안 캡처한 데이터 스냅샷이고, 각 열은 다른 변수입니다. 열은 다음에 대응됩니다.

  • 1열 – 유닛 번호

  • 2열 – 시간(단위: 주기)

  • 3–5열 – 동작 설정

  • 6–26열 – 센서 측정값 1–21

Turbofan Engine Degradation Simulation 데이터 세트를 저장할 디렉터리를 만듭니다.

dataFolder = fullfile(tempdir,"turbofan");
if ~exist(dataFolder,'dir')
    mkdir(dataFolder);
end

Turbofan Engine Degradation Simulation 데이터 세트를 다운로드하고 추출합니다.

filename = matlab.internal.examples.downloadSupportFile("nnet","data/TurbofanEngineDegradationSimulationData.zip");
unzip(filename,dataFolder)

훈련 데이터 준비하기

이 예제에 첨부된 함수 processTurboFanDataTrain을 사용하여 데이터를 불러옵니다. 함수 processTurboFanDataTrainfilenamePredictors에서 데이터를 추출하고, 훈련 예측 변수 시퀀스와 응답 변수 시퀀스를 포함하는 셀형 배열 XTrainYTrain을 반환합니다.

filenamePredictors = fullfile(dataFolder,"train_FD001.txt");
[XTrain,YTrain] = processTurboFanDataTrain(filenamePredictors);

상수 값을 갖는 특징 제거하기

모든 시간 스텝에 대해 변하지 않는 특징은 훈련의 성능을 저하할 수 있습니다. 동일한 최솟값과 최댓값을 갖는 데이터 행을 찾아서 제거합니다.

m = min([XTrain{:}],[],2);
M = max([XTrain{:}],[],2);
idxConstant = M == m;

for i = 1:numel(XTrain)
    XTrain{i}(idxConstant,:) = [];
end

시퀀스에 남아 있는 특징의 개수를 봅니다.

numFeatures = size(XTrain{1},1)
numFeatures = 17

훈련 예측 변수 정규화하기

훈련 예측 변수가 평균 0과 단위 분산을 갖도록 정규화합니다. 모든 관측값에 대해 평균과 표준편차를 계산하려면 시퀀스 데이터를 가로로 결합하십시오.

mu = mean([XTrain{:}],2);
sig = std([XTrain{:}],0,2);

for i = 1:numel(XTrain)
    XTrain{i} = (XTrain{i} - mu) ./ sig;
end

응답 변수 자르기

엔진 결함이 임박했을 때 시퀀스 데이터로부터 더 많이 학습할 수 있도록 응답 변수를 임계값 150에서 자르십시오. 이렇게 하면 신경망이 이보다 더 높은 RUL 값을 갖는 인스턴스들을 동일하게 처리합니다.

thr = 150;
for i = 1:numel(YTrain)
    YTrain{i}(YTrain{i} > thr) = thr;
end

이 그림에서는 첫 번째 관측값과 여기에 대응하는 잘린 응답 변수를 보여줍니다.

채우기를 위해 데이터 준비하기

미니 배치에 추가되는 채우기의 양을 최소화하려면 시퀀스 길이를 기준으로 훈련 데이터를 정렬하십시오. 그런 다음 훈련 데이터를 균등하게 나누고 미니 배치의 채우기 양을 줄이는 미니 배치 크기를 선택합니다.

시퀀스 길이를 기준으로 훈련 데이터를 정렬합니다.

for i=1:numel(XTrain)
    sequence = XTrain{i};
    sequenceLengths(i) = size(sequence,2);
end

[sequenceLengths,idx] = sort(sequenceLengths,'descend');
XTrain = XTrain(idx);
YTrain = YTrain(idx);

정렬된 시퀀스 길이를 막대 차트로 표시합니다.

figure
bar(sequenceLengths)
xlabel("Sequence")
ylabel("Length")
title("Sorted Data")

훈련 데이터를 균등하게 나누고 미니 배치의 채우기 양을 줄이는 미니 배치 크기를 선택합니다. 미니 배치 크기를 20으로 지정합니다. 이 그림에서는 정렬된 시퀀스와 정렬되지 않은 시퀀스에 더해진 채우기를 보여줍니다.

miniBatchSize = 20;

신경망 아키텍처 정의하기

신경망 아키텍처를 정의합니다. 은닉 유닛 200개를 갖는 LSTM 계층, 크기가 50인 완전 연결 계층, 드롭아웃 확률이 0.5인 드롭아웃 계층으로 구성된 LSTM 신경망을 만듭니다.

numResponses = size(YTrain{1},1);
numHiddenUnits = 200;

layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','sequence')
    fullyConnectedLayer(50)
    dropoutLayer(0.5)
    fullyConnectedLayer(numResponses)
    regressionLayer];

훈련 옵션을 지정합니다. 솔버 'adam'을 사용하여 크기가 20인 미니 배치로 Epoch 60회만큼 훈련을 진행합니다. 학습률을 0.01로 지정합니다. 기울기가 한없이 증가하지 않도록 하려면 기울기 임계값을 1로 설정하십시오. 시퀀스가 길이를 기준으로 정렬된 상태를 유지하도록 하려면 'Shuffle''never'로 설정하십시오.

maxEpochs = 60;
miniBatchSize = 20;

options = trainingOptions('adam', ...
    'MaxEpochs',maxEpochs, ...
    'MiniBatchSize',miniBatchSize, ...
    'InitialLearnRate',0.01, ...
    'GradientThreshold',1, ...
    'Shuffle','never', ...
    'Plots','training-progress',...
    'Verbose',0);

신경망 훈련시키기

trainNetwork를 사용하여 신경망을 훈련시킵니다.

net = trainNetwork(XTrain,YTrain,layers,options);

신경망 테스트하기

이 예제에 첨부된 함수 processTurboFanDataTest를 사용하여 테스트 데이터를 준비합니다. 함수 processTurboFanDataTestfilenamePredictorsfilenameResponses에서 데이터를 추출하고, 각각 훈련 예측 변수 시퀀스와 응답 변수 시퀀스를 포함하는 셀형 배열 XTestYTest를 반환합니다.

filenamePredictors = fullfile(dataFolder,"test_FD001.txt");
filenameResponses = fullfile(dataFolder,"RUL_FD001.txt");
[XTest,YTest] = processTurboFanDataTest(filenamePredictors,filenameResponses);

훈련 데이터로부터 계산한 idxConstant를 사용하여 상수 값을 갖는 특징을 제거합니다. 훈련 데이터와 동일한 파라미터를 사용하여 테스트 예측 변수를 정규화합니다. 훈련 데이터에 사용된 임계값과 동일한 임계값에서 테스트 응답 변수를 자릅니다.

for i = 1:numel(XTest)
    XTest{i}(idxConstant,:) = [];
    XTest{i} = (XTest{i} - mu) ./ sig;
    YTest{i}(YTest{i} > thr) = thr;
end

predict를 사용하여 테스트 데이터에 대해 예측을 수행합니다. 함수가 데이터에 채우기를 추가하지 않도록 하려면 미니 배치 크기를 1로 지정하십시오.

YPred = predict(net,XTest,'MiniBatchSize',1);

LSTM 신경망은 한 번에 시간 스텝 하나씩 부분 시퀀스에 대해 예측을 수행합니다. 각 시간 스텝마다 신경망은 이번 시간 스텝의 값과 이전 시간 스텝들로부터 계산한 신경망 상태만을 사용하여 예측을 수행합니다. 신경망은 각 예측 사이에 신경망 상태를 업데이트합니다. predict 함수는 이러한 예측으로 구성된 시퀀스를 반환합니다. 예측의 마지막 요소는 해당 부분 시퀀스에 대해 예측된 RUL에 대응합니다.

또는 predictAndUpdateState를 사용하여 한 번에 시간 스텝 하나씩 예측을 수행할 수도 있습니다. 이 방법은 시간 스텝의 값이 스트림으로 수신되는 경우에 유용합니다. 일반적으로 한 번에 시간 스텝 하나씩 예측을 수행하는 것보다 전체 시퀀스에 대해 예측을 수행하는 것이 빠릅니다. 단일 시간 스텝 예측들 사이에서 신경망을 업데이트하여 미래의 시간 스텝을 전망하는 방법에 대한 예제는 딥러닝을 사용한 시계열 전망 항목을 참조하십시오.

예측 중 일부를 플롯으로 시각화합니다.

idx = randperm(numel(YPred),4);
figure
for i = 1:numel(idx)
    subplot(2,2,i)
    
    plot(YTest{idx(i)},'--')
    hold on
    plot(YPred{idx(i)},'.-')
    hold off
    
    ylim([0 thr + 25])
    title("Test Observation " + idx(i))
    xlabel("Time Step")
    ylabel("RUL")
end
legend(["Test Data" "Predicted"],'Location','southeast')

주어진 부분 시퀀스에서 예측된 현재 RUL은 예측된 시퀀스의 마지막 요소입니다. 예측의 RMSE(제곱평균제곱근 오차)를 계산하고, 예측 오차를 히스토그램으로 시각화합니다.

for i = 1:numel(YTest)
    YTestLast(i) = YTest{i}(end);
    YPredLast(i) = YPred{i}(end);
end
figure
rmse = sqrt(mean((YPredLast - YTestLast).^2))
rmse = single
    20.7202
histogram(YPredLast - YTestLast)
title("RMSE = " + rmse)
ylabel("Frequency")
xlabel("Error")

참고 문헌

  1. Saxena, Abhinav, Kai Goebel, Don Simon, and Neil Eklund. "Damage propagation modeling for aircraft engine run-to-failure simulation." In Prognostics and Health Management, 2008. PHM 2008. International Conference on, pp. 1-9. IEEE, 2008.

참고 항목

| | | |

관련 항목