1. Deep SVDD란?
- Deep SVDD는 Deep Support Vectormachine Data Description의 줄임말로, 기존에 알아봤었던 SVDD의 딥러닝으로 확장한 버전이라고 보시면 되겠습니다.
[딥러닝 with Python] Anomaly Detection(이상탐지) : SVDD(Support Vector Data Description)
- 기존 SVDD는 신경망을 활용해 복잡한 Feature Representation을 학습하는 방식으로, 특히 고차원 데이터나 비선형 데이터서에서 매우 효과적인 방법입니다.
* 예를 들어, 이미지, 센서 데이터, 비정형 데이터에서의 이상 탐지에 매우 유용합니다.
출처 : https://www.researchgate.net/figure/Deep-SVDD-configuration-diagram-10_fig1_366774625
- Deep SVDD의 주요 원리
* Deep SVDD의 목표는 데이터를 Latent space로 매핑하여, 대부분의 정상 데이터가 밀집된 중심 주변의 영역을 형성하게 하는 것입니다. 이때 데이터가 중심에서 멀어질수록 이상 데이터일 가능성이 높은 것입니다.
- Loss function
* Deep SVDD의 Loss Function은 입력 데이터 x를 중심 c에 가까이 매핑하는 신경망을 학습하는 것이며 이를 식으로 표현하면 아래와 같습니다.
2. 파이썬 코드를 활용한 Deep SVDD 구현
- 이번에는 예제 데이터를 생성해서 Deep SVDD를 구현해보겠습니다.
* 이때 활용한 Neural Network는 간단한 2층의 Linear 신경망이며, 중심 벡터인 c는 정상 데이터의 평균으로 초기화 한 뒤 신경망이 학습하는 동안 데이터들이 중심과의 거리를 최소화 할 수 있도록 학습이 됩니다.
* 손실 함수는 중심과의 유클리디안 거리가 최소화 되게하는 손실 함수로, 정상 데이터가 중심에 가깝게 위치하도록 매핑을 합니다.
* Threshold는 정상 데이터의 95%를 포함하는 거리를 기준으로 임계값을 설정하여 이 거리 밖에 위치한 데이터에 대해서는 이상으로 간주하게 합니다.
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# Deep SVDD 모델 정의
class DeepSVDDNet ( nn . Module ) :
def __init__ ( self , input_dim , hidden_dim , output_dim ) :
super ( DeepSVDDNet , self ) . __init__ ()
self .fc1 = nn.Linear ( input_dim , hidden_dim )
self .fc2 = nn.Linear ( hidden_dim , output_dim )
def forward ( self , x ) :
x = torch.relu ( self .fc1 ( x ))
x = self .fc2 ( x )
return x
# 데이터 생성
np.random.seed ( 0 )
X_normal , _ = make_blobs ( n_samples= 100 , centers= [[ 0 , 0 ]], cluster_std= 0.5 )
X_outliers = np.random.uniform ( low= -5 , high= 5 , size= ( 20 , 2 ))
X_train = np.concatenate ([ X_normal , X_outliers ], axis= 0 )
X_train = torch.tensor ( X_train , dtype=torch.float32 )
# Deep SVDD 모델 초기화
input_dim = 2
hidden_dim = 16
output_dim = 2
net = DeepSVDDNet ( input_dim , hidden_dim , output_dim )
# 중심 벡터 초기화
with torch.no_grad ():
c = net ( X_train ) .mean ( dim= 0 )
# 손실 함수와 최적화 설정
def deep_svdd_loss ( output , c ) :
dist = torch. sum (( output - c ) ** 2 , dim= 1 )
return torch.mean ( dist )
optimizer = optim.Adam ( net.parameters (), lr= 0.001 )
# 학습
num_epochs = 100
for epoch in range ( num_epochs ):
net.train ()
optimizer.zero_grad ()
output = net ( X_train )
loss = deep_svdd_loss ( output , c )
loss.backward ()
optimizer.step ()
if ( epoch + 1 ) % 20 == 0 :
print ( f "Epoch [ { epoch + 1 } / { num_epochs } ], Loss: { loss.item () :.4f } " )
# 예측 및 시각화
with torch.no_grad ():
net. eval ()
output = net ( X_train ) .numpy ()
distances = np.sqrt ( np. sum (( output - c.numpy ()) ** 2 , axis= 1 ))
threshold = np.percentile ( distances [: 100 ], 95 ) # 정상 데이터의 95%를 기준으로 임계값 설정
plt.figure ( figsize= ( 8 , 8 ))
plt.scatter ( output [: 100 , 0 ], output [: 100 , 1 ], color= 'blue' , label= "Normal Data" )
plt.scatter ( output [ 100 :, 0 ], output [ 100 :, 1 ], color= 'red' , label= "Anomaly Data" )
circle = plt.Circle ( c.numpy (), threshold , color= 'green' , fill= False , linestyle= '--' , label= "Decision Boundary" )
plt.gca () .add_artist ( circle )
plt.legend ()
plt.xlabel ( "Latent Dimension 1" )
plt.ylabel ( "Latent Dimension 2" )
plt.title ( "Deep SVDD - Normal and Anomaly Data" )
plt.show ()
* 파란색이 정상 데이터이고, 빨간색이 비정상 데이터이며 위의 논리를 기준으로 학습을 진행하였을때 그림과 같은 초록색 점선의 구가 나오게 됩니다. 이때 비정상 데이터를 많이 구분해내기도 하지만 일부 비정상 데이터는 잘 구분해내지 못하는 한계를 가지고 있는 것을 알 수 있습니다.
댓글