본문 바로가기
딥러닝 with Python

[딥러닝 with Python] Anomaly Detection(이상탐지) : Deep SVDD

by CodeCrafter 2024. 11. 28.
반응형

 

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()

 

 * 파란색이 정상 데이터이고, 빨간색이 비정상 데이터이며 위의 논리를 기준으로 학습을 진행하였을때 그림과 같은 초록색 점선의 구가 나오게 됩니다. 이때 비정상 데이터를 많이 구분해내기도 하지만 일부 비정상 데이터는 잘 구분해내지 못하는 한계를 가지고 있는 것을 알 수 있습니다.

반응형

댓글