일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- datascience
- DeepLearning
- python
- 프로그래머스
- pep8
- autoencoder
- 네이버AItech
- torchserve
- GCP
- Matplotlib
- leetcode
- GIT
- Kubernetes
- github
- docker
- vscode
- GitHub Action
- wandb
- NaverAItech
- 알고리즘
- 백준
- PytorchLightning
- Kaggle
- 완전탐색
- pytorch
- 코딩테스트
- FastAPI
- NLP
- FDS
- rnn
- Today
- Total
Sangmun
Anomaly detection with Autoencoders ( 오토인코더를 이용한 이상치 탐지) 본문
저번에 리뷰한 논문과 맥을 같이 하는 블로그 글이 있어서 읽고 리뷰를 해보았다.
# 출처 : https://medium.com/swlh/anomaly-detection-with-autoencoders-2bd23dedbd9e
해당 글은 간단하게 오토인코더를 이용하여 한쪽 클래스의 데이터 세트만을 학습시켜 다른 클래스를 탐지하는 방법에 대하여 기술을 하고 있다.
x, y = datasets.make_blobs(
n_samples=500,
n_features=15,
centers=2,
center_box=(-4.0,4.0),
cluster_std=1.75,
random_state=42
)
x = preprocessing.MinMaxScaler().fit_transform(x)
pca = decomposition.PCA(n_components=3)
pca_result = pca.fit_transform(x)
print(pca.explained_variance_ratio_)
pca_df = pd.DataFrame(data=pca_result, columns=['pc_1','pc_2','pc_3'])
pca_df = pd.concat([pca_df, pd.DataFrame({'label':y})], axis=1)
ax = Axes3D(plt.figure(figsize=(8,8)))
ax.scatter(xs=pca_df['pc_1'], ys=pca_df['pc_2'], zs=pca_df['pc_3'], c=pca_df['label'], s=25)
ax.set_xlabel("pc_1")
ax.set_ylabel('pc_2')
ax.set_zlabel('pc_3')
plt.show()
위 코드는 두 가지의 클래스를 가진 데이터 세트를 발생시키는 코드이며 아래는 만들어진 데이터 세트를 3차원으로 차원 축소하여 시각화한 모습이다.
데이터 세트에 대한 확인 후 아래와 같은 신경망 구조를 거쳐 한쪽 클래스의 데이터만을 학습시킨다
encoder = keras.models.Sequential([
keras.layers.Dense(10, activation='relu', input_shape=[n_features]),
keras.layers.Dense(5, activation='relu'),
keras.layers.Dense(2, activation='relu')
])
decoder = keras.models.Sequential([
keras.layers.Dense(5, activation='relu', input_shape=[2]),
keras.layers.Dense(10, activation='relu'),
keras.layers.Dense(n_features, activation='sigmoid')
])
autoencoder = keras.models.Sequential([encoder, decoder])
autoencoder.compile(
loss='mean_squared_error', optimizer=keras.optimizers.Adam(), metrics=['mse'])
결과는 아래와 같다.
클래스 0의 데이터에 해당하는 데이터들을 학습하였음으로 모델을 오토인코더 모델을 통과시켰을 때 클래스 0의 데이터들은 손실 값이 적게 나오고 클래스 1의 데이터들은 손실값이 상대적으로 높게 나오며 해당 차이는 두 클래스를 분류할 수 있을 정도로 유의미하다고 볼 수 있다.
대략 임계치를 0.35를 기준으로 하여 클래스 0과, 클래스 1을 구분할 수 있다고 볼 수 있다.
아래는 반대로 실시한 결과이다. 클래스 1의 데이터들은 손실 값이 적고 클래스 0의 데이터들은 손실값이 높으며 대략 임계치 0.25를 기준으로 두 클래스를 구분하는 것이 가능해 보인다.
또한 다른 블로그의 글은 위에서 기술한 기법을 바탕으로 캐글의 Credit Card Fraud Detection 데이터 세트에 적용한 결과를 자신의 블로그에 포스팅하였다.
우선 해당 데이터 세트를 위의 블로그 포스트와 같이 3차원으로 축소한 모습을 시각화한 모습이다.
사기로 분류된 거래의 건수가 너무나 적고(492건) 정상거래와 구분이 어려운 탓에 정상거래건에 거의 뒤덮여있는 모습이다(왼쪽).
따라서 정상거래건을 어느 정도 걸러내고 시각화를 실시하니 정상과 사기 거래가 어느정도 구분이 되는 모습이다(오른쪽)
그리고 아래와 같은 신경망 구조로 한쪽의 클래스의 데이터에 대해서만 학습을 시킨다.
keras.backend.clear_session()
encoder = keras.models.Sequential([
keras.layers.Dense(25, activation='relu', input_shape=[29]),
keras.layers.Dropout(rate=0.1),
keras.layers.Dense(20, activation='relu'),
keras.layers.Dropout(rate=0.1),
keras.layers.Dense(10, activation='relu'),
keras.layers.Dense(5, activation='relu')
])
decoder = keras.models.Sequential([
keras.layers.Dense(10, activation='relu', input_shape=[5]),
keras.layers.Dense(20, activation='relu'),
keras.layers.Dropout(rate=0.1),
keras.layers.Dense(25, activation='relu'),
keras.layers.Dropout(rate=0.1),
keras.layers.Dense(29, activation='sigmoid')
])
autoencoder = keras.models.Sequential([encoder, decoder])
autoencoder.compile(
loss='mean_squared_error', optimizer=keras.optimizers.Adam(), metrics=['mse'])
결과는 아래와 같다.
각 클래스의 100개의 샘플의 손실 값을 비교한 결과 유의미하게 손실 값이 차이가 나는 것을 확인할 수 있었다.
따라서 반대의 경우도 같은 결과를 보이는지 실험을 해보았다. 즉 492건의 사기거래만을 학습시켰을 때 정상거래와 유의미한 손실 값 차이를 보이는지 확인을 해보았다.
하지만 반대의 경우는 그렇지 않았다. 이유로는 아마 492건의 데이터가 너무나도 적었기 때문으로 보인다. 또한 사기거래가 정상거래와 유사한 모습을 많이 보인다는 CCFD 데이터 세트의 특성도 또 다른 원인으로 보인다.
경우에 따라서는 이상행위탐지 시스템을 구축하기 위해서는 양성(사기 데이터)만을 오토인코더에 학습시켜 이상치를 탐지하는 모델을 구축할 필요가 있는데 위와 같은 한계점을 극복하기 위해서는 오버샘플링이나 이전에 기술하였던 denoising autoencoder를 이용하여 양성 데이터의 부족 문제를 보완하는 기법을 연구해 보아야 할 것 같다.