사쿠의 데이터 블로그

Anomaly Detection with AE (2) 본문

Python(데이터 분석, 딥러닝)

Anomaly Detection with AE (2)

토스트먹어 2019. 5. 26. 18:08

★★ 이상점 탐지 ★★

0. Auto Encoder 개념 -링크

1. Anomaly Detection with AE (1) - 링크

 

 

이번 포스팅에서는 오토 인코더를 이용해 Mnist 데이터와 노이즈를 구분해 보겠습니다.

 

그전에, Auto Encoder는 만능이 아닙니다.

다른 알고리즘과 비교 후 더 나은 알고리즘을 택했으면 좋겠습니다.

 

[대표적인 방법]

백 분위 점수와 상위 [1%, 0.1%, 0.01%] 점수를 비교

--> 이 방법은 상위 데이터에 이상점이 있을 경우 훨씬 저렴하게 탐지할 수 있습니다. 

 

 

그림1. AE가 이상점 탐지 만능은 아니다

 

AE로 이상점을 탐지하는 방법

항상 그렇듯, 가설을 세우고 문제를 해결해야 합니다. 

이번에 세울 가설은 "AE는 비 정상 데이터가 들어오면 Error를 높게 배출한다" 입니다.

딥러닝이 마법도 아닌데 어떻게 이런 일이 가능할까?

 

 

그림2. AE의 MSE는 Recontruction Error라고도 한다.

잘 학습된 AE는 정상 데이터가 들어왔다면 낮은 MSE값을 출력할 것이다. 

--> input과 output의 차이를 줄이도록 학습한 AE의 MSE는 당연히 낮을 것이다

 

이에 반해, AE는 비 정상 데이터를 제대로 복원하지 못한다는 가정이다. 

--> 이에 대한 원인은 뒷부분에(다음 포스팅)에 설명하도록 하겠습니다.

 

AE는 특이하게 MSE를 Recontruction Error라고도 부른다.

정상과 비정상은 MSE에서 차이가 날 것이다. 
 = 정상 데이터는 Recontruction Error가 낮지만 비정상은 그렇지 못할 것이다. 

 

어떻게 AE로 가능해!?!

이전 포스팅에서 AE는 input과 output을 동일하게 만든다고 했다.

그런데 생각해보면, 잘 학습된 AE

  • 정상 데이터를 Input으로 받고 정상 데이터를 Output으로 뱉을 것이다. 
  • 그렇다면 MSE는 (정상 - 정상)^2 = 0

 

  • 비정상 데이터를 Input으로 받고 비정상 데이터를 Output 으로 나올 것이다.
    • MSE = (비정상 - 비정상)^2 = 0

 

그럼 대체 어떻게 구분이 가능할까?

미리 힌트를 드리자면 Latent Space(=manifold)에 정답이 있습니다.

 

자세한 내용은 다음 포스팅을 참조 부탁드립니다.

 

코드를 보면서 


데이터 불러오기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os
import torch
from torch import nn
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
from torchvision.utils import save_image
import numpy as np
 
# python - m visdom.server
import visdom
 
#  미리 만들어둔 모델 불러오기
from AE_model import encoder, decoder
 
#  데이터 불러오기
dataset = MNIST('./data', transform=img_transform)
dataloader = DataLoader(dataset, batch_size=batch_size , shuffle=True)
 
cs

이전에 다운로드했던 mnist 데이터를 불러오고 Dataloader에 탑재(?)합니다. 

혹시라도 다운로드 하지 못했다면 download = True 옵션을 추가하면 된다.

1
dataset = MNIST('./data', transform=img_transform, download=True)
cs

 

visdom은 tensorflow의 tensor board와 같은 역할을 합니다. (시각화)

 

torchvision에서 제공하는 MNIST 데이터는 총 6만 장이 train으로 제공됩니다.

이번 실험에서는 6만 장의 0.1%60장의 노이즈 이미지를 탐지해보려 합니다.

 

 

노이즈 이미지 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
def make_fake_img():
    img_size = 28
    n_fake_img = 60
    fake_img  = []
    for i in range(n_fake_img):
        fake_img.append( np.random.randn(img_size * img_size).reshape(1, img_size, img_size) )
 
    fake_img = torch.FloatTensor(fake_img)
    fake_img = fake_img.view(n_fake_img, img_size * img_size)
    fake_img = Variable(fake_img).cuda()
 
    return fake_img
 
 
fake_img = make_fake_img()
cs

 

AE 학습

그림3. AE 학습과정

 

 위 그림과 같이 학습을 진행했습니다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
 
for epoch in range(num_epochs):
    for data in dataloader:
        img, _ = data  # label 은 가져오지 않는다.
        img = img.view(img.size(0), -1)
        img = Variable(img).cuda()
        # ===================forward=====================
        latent_z = encoder(img)
        output = decoder(latent_z )
        # ===================backward====================
        loss = criterion(output, img)
 
        encoder_optimizer.zero_grad()
        decoder_optimizer.zero_grad()
        loss.backward()
        encoder_optimizer.step()
        decoder_optimizer.step()
    # ===================log========================
    print('epoch [{}/{}], loss:{:.4f}' .format(epoch + 1, num_epochs, float(loss.data) ))
    vis.line(Y=[loss.data.cpu().numpy()], X=np.array([epoch]), win=normal, update='append')
    
    if epoch % 10 == 0:
        pic = to_img(output.cpu().data)
        save_image(pic, './AE_img/output_image_{}.png'.format(epoch))
 
    # ===================forward=====================
    latent_z = encoder(fake_img)
    output = decoder(latent_z )
 
    # ===================backward====================
    loss = criterion(output, fake_img)
 
    encoder_optimizer.zero_grad()
    decoder_optimizer.zero_grad()
    loss.backward()
    encoder_optimizer.step()
    decoder_optimizer.step()
    # ===================log========================
    print('##### fake epoch [{}/{}], loss:{:.4f} #### '.format(epoch + 1, num_epochs, float(loss.data) ))
    vis.line(Y=[loss.data.cpu().numpy()], X=np.array([epoch]), win=anomaly, update='append')
    if epoch % 10 == 0:
        pic = to_img(output.cpu().data)
        save_image(pic, './AE_img/fake_image_{}.png'.format(epoch))
cs

 

결과 확인

 

그림4. 정상데이터와 비정상 데이터의 Loss 

정상 데이터와 비정상 데이터간 Loss(=MSE)를 비교해 봤습니다.

 

비정상 데이터는 감소하지 않는 모습을 확인 할 수 있습니다.

 

 

그림5. 정상과 비정상 데이터의 MSE dist plot

 

정상과 비정상 데이터가 제대로 분리되는 모습을 확인 했습니다. 

 

다음 포스트에서는 왜 작동이 되는지 확인 해보도록 하겠습니다. 

(너무 길어서 다음으로 넘기겠습니다.)

요약. 
1. 데이터 속 이상점(anomaly data)이 있는 걸 알지만 탐지 방법을 모른다.
2. 오토 인코더를 사용하면 정상과 비정상 데이터를 분리 할 수 있다. 

 

 

위 예시에서 사용한 코드는 깃허브에서 확인 할 수 있습니다. 

(링크)

'Python(데이터 분석, 딥러닝)' 카테고리의 다른 글

Python에서 Bigquery 연동하기  (0) 2022.01.23
변수 중요도 측정 - Permutation importance  (0) 2019.10.27
Anomaly Detection with AE (1)  (1) 2019.05.25
Auto Encoder(개념)  (1) 2019.05.25
Pytorch 설치  (0) 2019.05.19