머신러닝

Keras 기초 예제: Time series anomaly detection using an Autoencoder

coding art 2021. 12. 28. 20:26
728x90

 

파이선 코딩 초보자를 위한 텐서플로우∙OpenCV 머신 러닝 2차 개정판 발행

http://blog.daum.net/ejleep1/1175

 

파이선 코딩 초보자를 위한 텐서플로우∙OpenCV 머신 러닝 2차 개정판 (하이퍼링크) 목차 pdf 파일

본서는 이미 2021년 11월 초부터 POD코너에서 주문 구입이 가능합니다. 참고로 책 목차에 따른 내용별 학습을 위한 코드는 이미 대부분 다음(Daum)블로그에 보관되어 있으며 아래에서 클릭하면 해당

blog.daum.net

https://keras.io/examples/timeseries/timeseries_anomaly_detection/

본 블로그의 내용은 위 url 주소에 있는 일차원  CNN  기법에 의한 기계이상을 알아내는 keras 머신러닝 예제코드에 대한 해설입니다. 야후에서 keras example 이란 검색어로 위 사이트에 들어가 보면 수많은 Keras 예제들이 있음을 알 수 있다. 어느 예제도 공부하기에 만만한 쉬운 예제는 없는 듯하다. 필요에 의해서 Timeseries 에 대한 머신러닝 기법 적용 의뢰를 받은김에 이 주제에 대해서 해설해 보기로 한다.

 

헤더 영역의 라이브러리를 불러 들인 후 아래의 코드를 사용하여 NAB 웹사이트에서 예제 데이터를 불러 로딩한다. 한편으로는 https://~에서 데이터세트를 직접 다운로드 설치하여 폴더를 준비하면 master_url_root 부분을 생략할 수도 있다.

 

pandas 로 csv 데이터를 읽은 후 df_small_noise.shape값을 출력해 보면 다음 값이 얻어진다.

(4032, 1)

즉 5분마다 샘플링하면 시간당 12개 하루 24시간에 288개가 얻어지며 14일간 4032개가 됨을 알 수 있다.

일단 아무런 기계이상이 없는 데이터세트 df_small_noise를 읽어서 출력해보자.

그래프로 출력된 값을 살펴 보면 모두가 양의 값을 가짐을 알 수 있다. 만약 가속도계로 기계의 진동을 모니터링 했다면 3차원 각 방향별로 +/-를 포함한 양음의 값이 나타날 수도 있지만 여기서는 각 방향 벡터의 값을 각각 제곱하여 합한 후 루트를 취하면 양의 값이 어어질 수 있음에 유의하자. 

반면에 기계 이상으로 인해 측정 레벨값이 크게 튀는 경우인 df_daily_jumpsup 데이터를 살펴보자. 측정 레벨 값이 거의 두배로 상승하였다.

학습 데이터를 준비하자. 아래와 같이 즉 5분마다 샘플링하면 시간당 12개 하루 24시간에 288개가 얻어지며 14일간 4032개가 됨을 알 수 있다. 

  • 24 * 60 / 5 = 288 timesteps per day
  • 288 * 14 = 4032 data points in total   
  • df_training_value.shape을 출력하면 (4032,1)
  • 이와같은 normalization 과정을 통해서 mean squared error 가 cost 함수가 될 수 있다.
  •  

이 일차원적인 4032개의 데이터를 그냥 학습시키는 것이 아니라 288개 단위로 데이터 하나씩 인접한 데이터 묶음을 3795개 만들도록 한다. 즉 shape이 (288,1)인 데이터 단위로 3095개가 준비된다. 

여기서 인접한(contiguous) 데이터의 의미는 아래 그림에서 처럼 4032개에서 첫데이터부터 288개를 첫번째로 하고 그 다음에는 4032개 데이터 중에서 두번째 데이터부터 288개를 취하고 ... 이런 방식으로 하면 3745번째부터 4032까지가 마지막 contiguous 한 데이터가 된다. 이 부분의 코드 의미를 잘 이해하기 바란다.

Keras 딥러닝 라이브러리 명령은  [샘플수, time steps, 특징수]로 이루어지는 3차원적인 데이터 구조가 요구된다. 따라서 앞서 준비했던 shape이 (288,1)인 3745개의 데이터를 STACK 명령을 사용하여 shape이 (3795,288,1)이 되도록 한다. 여기서 샘플수는 3795, time steps=288, 특징수는 1이 된다.

보편적으로 많이 사용되는 2단 레이어를 갖는 Keras convolutional autoencoder 모델을 준비하자. Autoencoder에 관해서는 별도의 검토가 필요함을 지적해 두며 여기서는 주어진 코드를 대상으로 간략히 해설하기로 한다.

입력 데이터 즉 layers.Input()은 구 텐서플로우 버전(tensorflow version 1.15 그 이전)에서 불특정한 수의 MNIST 데이터를 읽어들일 때 처럼 즉 (None, 28, 28)과 같이 shape 인덱스 중 첫번째인 즉 shape[0]=3745를 None 으로 처리하면 shape[1]과 shape[2]를 읽으면 될 것이다.

입력 데이터 준비 이후에 1차원 CNN 명령인 Conv1D 를 적용하자. 사용되는 디지털 필터수는 MNIST 문제에서도 흔히 그랬던 것처럼 32 또는 64개가 흔히 사용되며 여기서는 계산량을 줄일 수 있도록 32개로 한다. 이 디지털 필터는 서로 다른 랜덤 넘버들로 초기화 됨에 유의하자.  

kernel_size는 Conv2D 에서는 2차원 매트릭스 형태를 사용하지만 여기서는 1차원 문제이므로 1차원적으로 7로 두기로 한다. 이 kernel_size는 경험적으로 결정할 수 있는데 우선 7을 사용해 보고 차 후에 값을 변경할 수도 있을 것이다. 활성화 함수는 deep learning에서 높은 효율을 보여주는 relu 를 사용하기로 한다. 아울러 스트라이딩을 2로 두게 되면 아래 그림과 같이 144회 convolution 계산이 이루어진다. 따라서 첫번째 레이어 계산 결과 shape 은 (None, 144, 32)가 된다.

1단 레이어 convolution 모델 후 Overfitting 을 방지하기 위한 Dropout을 rate=0.2로 실시한다. 이어서 2단 convolution 모델하되 필터수를 16으로 줄여 출력의 크기를 작게 만든다. 여기까지가 엔코딩(encoding)단계이며 디코딩(decoding) 단계에서는 원래 샘플 규모로 엔코딩으로 인해 줄어든 데이터를 원래 규모로 복원하게 된다.

1,2단 처리 후 반대로 필터수 16으로 conv1dTranspose  디코딩 처리하고 다시한번 Dropout 을 실행한다. 아울러 필터수를 32로 늘려 다시 conv1dTranspose 디코딩 처리 후 다시 필터수를 1로 줄여 최종 conv1dTranspose 처리하여 복원된 즉 디코딩된 데이터를 얻어낸다. 다음의 코드를 참조하면서 convolution 과정이 encoder 과정에서부터 어떻게 정확하게 decoding 되는지 살펴보기 바란다. 이 알고리듬에서는 relu까지의 활성화 함수가 사용되므로 convolution 축소과정에서 별다른 정보 손실이 없음에 유의한다.

한편 semantic machine learning 분야에서 흔히  사용되는 알고리듬 에서는 초기의 데이터 사이즈에서 인식이 가능할 정도의 크기까지 convolution 알고리듬에 의해 크기를 줄이는 과정에 Pooling  알고리듬이 사용되어 정보의 손실이 발생할 수도 있으므로 다시 원래의 크기대로 복구하는 과정에 상당한 장해가 있을 수도 있다는 점에 유의하자.

learning rate = 0.001 로 두고 Adam 옵티마이져를 사용하여 컴파일 즉 빌드 작업을 실행한 후 summary 레포트를 출력하자.

 

 

이러한 알고리듬이 autoencoder 기법인데 원 신호 데이터세트들이 있음에도 불구하고 구태여 학습 모델을 만들어 테스트하는 이유는 무엇인가? 그 이유는  학습된 모델은 충분히 많은 수의 샘플 데이타를 대상으로 하기때문에 노이즈가 제거되었으면서 최소화된 표준편차를 가지는 평균적인 모델이 도출되기때문에 학습에 의해서 최적화된 웨이트 값들을 계산 후 이 웨이트 값들을 사용해 테스트 샘플을 사용해 타당성(validation)을 검증 후 unseen 데이터를 대상으로  forcasting 작업을 하기 위한 것이다. 다음은 원 이미지를 autoencoder  알고리듬으로 처리하여 노이즈가 제거되고 표준편차가 최소화되었으며 평균화된 autoencoder reconstruction 모델 사례이다.

Keras.Sequential 모델이 준비되었으면 fit  명령에 의한 학습을 시키도록 하자. 학습에 필요한 입력과 타겟은 동일하게 앞서 모델에 의해 준비된 x_train 을 시용하도록 한다. epoch 값은 임의로 50으로 두고, batch_size는 128로, validation 을 위한 split 비율은 10% 로 두자. 이와같이 split 비율이 10%일때 "loss" 와 "val_loss" 를 모니터링 하면서 Overfitting 여부를 관찰하자. epoch가 1씩 증가함에 따라 "loss"가 자연스레 감소하며 "val_loss" 도 그에 따라 자연스럽게 감소하면 OK 이다. 한편 3745X288X1 크기의 데이터를 사용하면서 training 과 test 비율이 9:1 일때 MNIST 문제에서처럼 정수배로 딱 떨어지는 batch_size를 정하기는 어려우므로 임의의 적절한 크기 값을 사용하도록 하자.

 

 

학습 후에 training loss 와 validation loss를 작도해 보면 다음과 같이 질 줄어들므로 OK 라 할 수 있다.

기계이상 검출(Anomaly Detection)

앞서 얻어진 학습 웨이트 값을 사용하여 x_train 전체를 학습시켜 x_train_pred 로 둔 후 x_train과 차이의 절대 값을 취하여 mae(mean absolute error) 를 계산하도록 한다. axis=1은 (3745,288,1)의 shape에서 288개를 뜻하므로 np.mean( np.abs( x_train_ped - x_train), axis=1)은 autoencoding 예측값 288개에서 원 데이터값 288개를 각각 뺀 후 절대값을 계산하여 합산 후 288로 나누어 3745개의 평균값을 취하여 이를 train_mae_loss 로 두고 bin 수를 50으로 하여 막대그래프를 그려보면 아래의 오른쪽 그래프가 얻어진다. 3745개의 train_mae_loss 중에서 상당수가 0.1~0.105 사이에서 정점을 보여준다. 즉 구간 0.1~0.105 사이에서 최대 정점을 보여주는 특정 값이 되풀이 되는 정상 신호의 threshold 값이 될 수 있다. 즉 평균값에 표준편차를 더한 값들을 조사하여 그 최대값을 threshold 로 삼는다. 

지금까지는 정상적인 신호 데이터에 대해서 autoencoding 기법에 의해 처리하여 mae_loss 값의 분포를 작도하였다. 다음은 anomaly를 포함하는 데이터 즉 df_daily_jumpsup 데이터세트에 대해서 동일한 과정을 밟되 학습을 위해서 정상 데이터에 대해 autoencoding 알고리듬에 따라 준비해둔 model을 그대로 사용하여 다음과 같이 test MAE loss 축 범위가 다른 histogram 분포를 얻어내자.

이 histogram을 관찰해보면 mae_loss 가 0.09~0.5 사이에 분포하고 있음을 알 수 있다. 즉 정상신호의 대부분을 차지하고 있는 threshold = 0.11.까지 다소 중복이 있긴하지만 거의 0.09~0.5 사이의 분포를 보여준다. 즉 threshold 값 0.11 이상에서 한참 위인 구간인 0.5에 이르기까지 anomaly 를 포함한 데이터의 특성을 보여주고 있다. 다음과 같이 threshold 값 이상임을 보여주는 즉 anomaly 를 포함하는 데이터세트를 체크해서 출력해보면 399의 anomaly를 포함하는 데이터가 있음을 알 수 있다.

 

즉 이 autoencoder  알고리듬 기법은 준비한 정상 데이터를 1차원 CNN 유사한 히든 레이어 네트워크를 설정하여 적정규모로 줄였다가 다시 원래 데이터 형대로 되돌리는 히든 레이어 네트워크를 설정하여 원복 시키는 과정을 통해서 얻어진 학습 웨이트 값이 준비된다. 결국 anomaly를 포함하는 데이터를 사용해서 정상데이터에서 얻어진 히든 레이어를 사용하여 학습시키게 되면 정상 데이터 학습 결과로부터 최대 threshold 값이 지정되어 있다면  이로부터 많이 벗어난 비정상 데이터가 분포 얻어짐을 확인할 수 있게 된다.

 

추가로 구글 텐서플로우 홈페이지 튜토리어얼 내용 중에도 심전도 데이터 Autoencoder 코드 사례가 있으며 앞의 내용과 거의 동일하게 코드 copy & paste 를 통해 실행해 볼 수 있다.

근본적인 차이점은 위 예제에서는 2개의 hidden 레이어를 채용하고 있는 반면에 아래 사례에서는 1개의 레이어를 채용한다는 점이다. 전통적으로 autoencoding에서는 1개의 레이어만 사용하는 것이 보편적으로 보인다. fashion mnist 및 노이즈를 첨가한 fashion mnist 사례를 볼 수 있으며 아울러 심전도 신호에 대한 예제 문제가 autoencoder 문제를 이해하는데 더욱 큰 도움이 될 것으로 본다.

https://www.tensorflow.org/tutorials/generative/autoencoder

 

심전도 데이터 Time Series Anomaly Detection

http://blog.daum.net/ejleep1/1227

 

심전도 데이터 Time Series Anomaly Detection

Intro to Autoencoders https://developer.habana.ai/tutorials/tensorflow/intro-to-autoencoders/ 기계장치의 Anomaly Detection 보다 흥미로울 수 있는 ECG5000 심전도 데이터세트를 사용하는 시계열상의 Anom..

blog.daum.net