Big Ben
Big Ben's Log
Big Ben
전체 방문자
오늘
어제
  • 전체 글 (80)
    • 파이썬 (23)
      • 파이썬 기초 (5)
      • 클래스 (6)
      • 자료구조 (4)
      • Tensorflow (3)
      • PyTorch (2)
      • konlpy (1)
      • anaconda (1)
    • 머신러닝 (3)
      • 선형회귀 (1)
      • Tree 기반 (1)
    • 딥러닝 (6)
      • NLP (2)
      • VISION (2)
      • TABULAR (0)
      • 딥러닝 서버 구축 (2)
    • 그래프 이론 (1)
      • 그래프마이닝 (1)
      • GNN (0)
    • 강화학습 (3)
      • 강화학습 기본 (3)
    • 인공지능 (5)
    • 추천시스템 (2)
      • 추천시스템 기초 (2)
    • Competitions (1)
    • 빅데이터 (8)
      • 하둡 (3)
      • 스파크 (4)
      • 클라우드 (1)
    • SQL (7)
      • MariaDB (2)
    • 논문 리뷰 (2)
    • 대학원 (0)
      • 데이터 사이언스 (0)
      • 경제학 (0)
    • 선형대수학 (7)
      • 선형대수 ICE BREAKING (1)
      • 벡터 (5)
      • 고윳값 (1)
    • 개인프로젝트 (0)
      • 포트폴리오 대시보드 + AI기반 주식 자동매매 (0)
    • 재테크 (1)
    • 자동차 (0)
    • 알고리즘 (11)

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

공지사항

인기 글

태그

  • MariaDB
  • 객체
  • 선형대수
  • 선형대수학
  • 하둡
  • 코딩테스트
  • AI
  • Baekjoon
  • 딥러닝
  • 빅데이터
  • 머신러닝
  • PYTHON
  • 자료구조
  • 데이터
  • 파이썬
  • mysql
  • 프로그래머스
  • 프로그래밍
  • 데이터베이스
  • 백준
  • sql
  • 데이터사이언스
  • class
  • TensorFlow
  • 객체지향
  • 인공지능
  • pytorch
  • 파이썬기초
  • 코테
  • 알고리즘

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Big Ben

Big Ben's Log

[Tensorflow] AutoEncoder 오토인코더 구현하기
딥러닝/VISION

[Tensorflow] AutoEncoder 오토인코더 구현하기

2023. 2. 26. 15:01
반응형

본 포스팅은 Applied Deep Learning - Autoencoders 편을 참고하였습니다.

오토인코드는 입력과 출력이 동일한 피드포워드 신경망의 한 유형입니다.

입력을 의도적으로 낮은 차원의 '코드'로 압축, 이후에 이 압축된 '코드'라는 표현을 기반으로 출력을 재구성(reconstruct)합니다.

코드는 입력의 간결한 "요약" 또는 "압축"이며 '잠재 공간 포현 (latent space representation)'이라고도 합니다.

 

오토인코더의 구성요소

오토 인코더는 [ 인코더, 코드, 디코더 ] 총 3개의 요소로 구성되어 있습니다.

인코더는 입력을 압축하고, 

압축된 입력은 코드가 됩니다.

디코더는 이 코드를 사용하여 입력을 재구성합니다.

 

아래는 오토인코더의 동작 예시입니다.

MNIST의 데이터인 숫자 4가 Encoder를 통과 -> code라는 직관적으로 알 수 없게 표현 -> 디코더가 code를 해독 & 재구성하여 출력 -> 4라는 숫자로 출력되는 것을 볼 수 있음

 

이미지 출처: https://towardsdatascience.com/applied-deep-learning-part-3-autoencoders-1c083af4d798

 

오토인코더를 구축하기 위해서는 크게 3개가 필요합니다 --> [ 인코딩 방법, 디코딩 방법, 입출력을 비교할 손실함수(loss function) ] 

 

오토인코더의 특징

오토인코더를 왜 사용할까요? 

어차피 입력과 출력이 동일한 것을 의미하고, 비슷한 형태라면 굳이 사용해야할 필요가 있을까요?

 

오토인코더는 차원을 축소하는데 의미가 있습니다. 차원은 추후 모델링을 할 때 연산시간을 비롯한 모델링의 전반적인 부분에 큰 영향을 미치는 요소입니다. 따라서 저차원일 경우 어느정도 정보 손실은 있겠지만, 경우에 따라서 효율적으로 실무에 맞는 속도로 데이터를 학습할 수 있습니다.

 

또한 오토인코더는 노이즈를 제거하는 효과가 있습니다. 

아래와 같이 노이즈가 가득한 이미지를 선명하게 만들 수 있습니다. 

위에서는 "오토인코더가 어떻길래 사용하고 배워야하는가?"에 대해서 다뤘다면, 아래는 오토인코더 자체에 대한 특징입니다. 크게 세가지 포인트를 말할 수 있습니다.

  1. 데이터 특정(data speicific): 오토인코더는 학습된 데이터와 유사한 데이터를 의미 있게 압축할 수 있습니다. 주어진 학습 데이터에 대해 특징을 학습하기 때문에 gzip과 같은 표준 데이터 압축 알고리즘과 다릅니다. 따라서 손글씨 숫자로 학습한 오토인코더가 풍경 사진을 압축하는 것을 기대할 수는 없습니다.
  2. 손실(Loss): 오토인코더의 출력은 입력과 정확히 동일하지 않을 것입니다. 출력은 가까운 대신에 손상된 표현이 될 것입니다. 완전한 손실 없는 압축을 원한다면 오토인코더는 적합하지 않습니다.
  3. 비지도 학습(unsupervised): 오토인코더를 학습시키기 위해서는 별다른 방법이 필요하지 않습니다. 입력 데이터를 그냥 넣어주기만 하면 됩니다. 오토인코더는 명시적인 라벨이 필요하지 않으므로 비지도 학습 기술로 간주됩니다. 하지만 더 정확하게 말하면, 오토인코더는 학습 데이터로부터 자체 라벨을 생성하기 때문에 자기 지도 학습 기술입니다.

오토인코더 코드 구현

Tensorflow를 활용하여 오토인코더를 구현해보겠습니다.

우선 아래 코드를 추가하여 필요 라이브러리와 함수를 불러오겠습니다.

# 시각화를 위한 matplotlib 호출
# 연산을 위한 numpy 호출
import matplotlib.pyplot as plt
import numpy as np

# autoencoder 결과물 플롯 함수
def plot_autoencoder_outputs(autoencoder, x, n, dims):
    """
    
    :param autoencoder: 학습된 autoencoder 모델  
    :param x: image를 그려볼 데이터
    :param n: 몇 개의 image를 그릴것인지 n을 통해 전달 
    :param dims: 이미지 plot을 위해 1차원 배열을 2차원으로 바꿔주어야 함 
    :return: 
    """
    decoded_imgs = autoencoder.predict(x)

    plt.figure(figsize=(10, 5))
    for i in range(n):
        # plot original image
        ax = plt.subplot(2, n, i + 1)
        plt.imshow(x[i].reshape(*dims))
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        # ax.set_title('Original Images')
        if i == n // 2:
            ax.set_title('Original Images')

        # plot reconstruction
        ax = plt.subplot(2, n, i + 1 + n)
        plt.imshow(decoded_imgs[i].reshape(*dims))
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        # ax.set_title('Reconstructed Images')
        if i == n // 2:
            ax.set_title('Reconstructed Images')

    plt.show()

데이터는 mnist를 이용할 것입니다.

Tensorflow 내장 데이터셋을 활용하겠습니다.

# 내장 데이터셋 호출을 위한 함수 호출
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# 데이터 차원 확인
print(X_train.shape) # (60000, 28, 28)
print(y_train.shape) # (60000, )
print(X_test.shape) # (10000, 28, 28)
print(y_test.shape) # (10000, )

예제 데이터를 하나 그려보겠습니다.

plt.imshow(X_train[1])

숫자 0이 플롯된 것을 확인할 수 있습니다.

 

Autoencoder는 기본적으로 Dense Layer를 활용합니다.

해당 레이어를 활용하기 위해서 2차원 데이터를 1차원 데이터인 배열로 바꿔주어야 합니다.

Tensorflow를 활용하면 Flatten을 통해서 펼쳐줄 수 있지만, 여기서는 numpy 를 통해 reshape을 진행하고, 데이터를 float 형태로 바꿔주겠습니다.

 

# 데이터 형태 및 유형 변경
X_train = X_train.reshape(-1, 28 * 28).astype(np.float32) / 255.0
X_test = X_test.reshape(-1, 28 * 28).astype(np.float32) / 255.0

 

이젠 모델링을 진행하겠습니다.

from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model

# dimension 설정
input_dim = X_train.shape[-1]
hidden_dim = 128
code_dim = 32

# 함수형 API 활용
input_img = Input(shape=(input_dim, ))
hidden_1 = Dense(hidden_dim, activation='relu')(input_img)
code = Dense(code_dim, activation='relu')(hidden_1)
hidden_2 = Dense(hidden_dim, activation='relu')(code)
output_img = Dense(input_dim, activation='sigmoid')(hidden_2)

# input과 output을 모델로 전달
autoencoder = Model(inputs=input_img, outputs=output_img)


# 모델 compile 
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

# 모델 학습 진행
autoencoder.fit(X_train, X_train, epochs=5)

학습 진행 시, 입력데이터와 출력데이터가 X_train으로 동일한 것에 주목합시다.

 

이젠 결과물을 plot 해보겠습니다.

plot_autoencoder_outputs(autoencoder, X_test, 5, (28, 28))

 

이렇게 거의 비슷한 결과물을 출력하는 것을 볼 수 있습니다.

 

Denoising Autoencoder

다음은 디노이징 오토인코더에 대해서 코드 구현해보겠습니다.

# 원본 데이터에 노이즈 추가
noise_factor = 0.4
X_train_w_noise = X_train + noise_factor * np.random.normal(size=X_train.shape)
X_test_w_noise = X_test + noise_factor * np.random.normal(size=X_test.shape)

# clip 함수를 통해 min, max 값을 넘어서는 값은 min과 max로 치환
X_train_w_noise = np.clip(X_train_w_noise, 0.0, 1.0)
X_test_w_noise = np.clip(X_test_w_noise, 0.0, 1.0)


# 노이즈 인풋과 원본 인풋 확인
n = 5

plt.figure(figsize=(10, 4.5))
for i in range(n):
    # plot original image
    ax = plt.subplot(2, n, i + 1)
    plt.imshow(X_test[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    if i == n // 2:
        ax.set_title('Original Images')

    # plot image with noise
    ax = plt.subplot(2, n, i + 1 + n)
    plt.imshow(X_test_w_noise[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    if i == n // 2:
        ax.set_title('Images with Noise')

 

위처럼 원본 데이터에 노이즈가 제대로 추가된 것을 확인할 수 있습니다.

이젠 오토인코더를 구현하여 노이즈를 제거한 상태로 이미지를 재구성해보겠습니다.

 

# 사실상 모델 구조는 일반 오토인코더와 동일합니다.

input_img = Input(shape=(input_dim, ))
hidden_1 = Dense(hidden_dim, activation='relu')(input_img)
code = Dense(code_dim, activation='relu')(hidden_1)
hidden_2 = Dense(hidden_dim, activation='relu')(code)
output_img = Dense(input_dim, activation='sigmoid')(hidden_2)

autoencoder = Model(inputs=input_img, outputs=output_img)

autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

autoencoder.fit(X_train_w_noise, X_train, epochs=5)  # 입력은 노이즈, 출력은 원본

유일한 차이점은 오토인코더를 데이터에 학습(fit)시킬 때, 인풋을 노이즈 인풋으로 넣고, 출력을 원본 데이터로 넣는 것이 다르다고 할 수 있습니다.

 

마찬가지로 원본 - 노이즈 - 재구성 데이터를 플롯해보자면..

n = 5
plt.figure(figsize=(10, 7))

images = autoencoder.predict(X_test_w_noise)

for i in range(n):
    # plot original image
    ax = plt.subplot(3, n, i + 1)
    plt.imshow(X_test[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    if i == n // 2:
        ax.set_title('Original Images')

    # plot noisy image
    ax = plt.subplot(3, n, i + 1 + n)
    plt.imshow(X_test_w_noise[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    if i == n // 2:
        ax.set_title('Noisy Input')

    # plot noisy image
    ax = plt.subplot(3, n, i + 1 + 2*n)
    plt.imshow(images[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    if i == n // 2:
        ax.set_title('Autoencoder Output')

 

이렇게 노이즈를 제거한 채로 출력을 하였습니다.

반응형
저작자표시 (새창열림)

'딥러닝 > VISION' 카테고리의 다른 글

[딥러닝] 합성곱 신경망 - 직관적으로 convolutional layer 깊이에 대해 이해하기  (0) 2023.02.23
    '딥러닝/VISION' 카테고리의 다른 글
    • [딥러닝] 합성곱 신경망 - 직관적으로 convolutional layer 깊이에 대해 이해하기
    Big Ben
    Big Ben
    Data Scientist

    티스토리툴바