다운로드
작성자: admin 작성일시: 2018-10-26 19:14:27 조회수: 1132 다운로드: 158
카테고리: 머신 러닝 태그목록:

딥드림

이 절의 코드는 tensorflow 2.0을 사용한다.

In [1]:
import tensorflow as tf

tf.__version__
Out:
'2.0.0'

딥드림은 2015년, 구글에서 발표된, CNN을 이용한 이미지 변환 기술이다. 결과물에서 벌레나, 개, 새 등의 사물이 추상적으로 표현되고, 결과물의 전체적인 분위기가 몽환적인 분위기로 바뀐다. 덕분에, 당시 인터넷에 크게 유행 하기도 했다.

딥드림은 기존의 CNN의 필터를 시각화하는 작업과 맥을 같이 한다. 이 책에서는 Inception-v3 모델을 이용해 이를 구현한다.

필터 시각화

딥드림의 기본 원리는 그레디언트 어센트(gradient ascent) 방법을 이용한 필터 시각화다. 필터가 어떤 이미지 프로세싱을 하는지 알아보기 위해 필터값이 가장 크게 나오는 입력 이미지를 찾는 방법이다.

여기에서는 훈련종료된 인셉션 V3 모형 중 필터 하나를 시각화해본다. 우선 인셉션 V3 모형을 로드한다.

In [2]:
%%time
from tensorflow.keras.applications.inception_v3 import InceptionV3

base_model = InceptionV3(include_top=False, weights='imagenet')
CPU times: user 3.45 s, sys: 160 ms, total: 3.61 s
Wall time: 3.56 s

특정 필터의 출력을 뽑기 위해 keras의 functional API를 사용한다. 여기에서는 mixed2 레이어의 출력을 뽑는다.

In [3]:
layer_output = base_model.get_layer("mixed2").output
filterview_model = tf.keras.Model(inputs=base_model.input, outputs=layer_output)

입력 이미지값과 필터 출력값의 관계를 구하고 출력값의 크기(손실함수)를 입력값으로 미분한 그레디언트 벡터를 구한다.

In [4]:
def filterview_iterate(img, filter_index, step_size=10):
    with tf.GradientTape() as tape:
        tape.watch(img)
        output = filterview_model(img)
        # 특정 필터의 출력값의 크기
        loss = tf.math.reduce_mean(tf.math.square(output[:, :, :, filter_index]))

    # 출력값의 크기를 입력값으로 미분한 그레디언트 벡터
    grads = tape.gradient(loss, img)
    
    # 그레디언트 벡터의 크기를 정규화한다.
    grads /= (tf.math.sqrt(tf.math.reduce_mean(tf.math.square(grads))) + 1e-5)
    
    img += grads * step_size
    img = tf.clip_by_value(img, 0, 255)
    return loss, grads, img

시각화를 하려면 초기 이미지가 있어야 한다. 초기 이미지는 랜덤한 값을 가지는 행렬을 사용한다.

In [5]:
input_img = tf.constant(np.random.random((1, 150, 150, 3)) * 20 + 128, dtype=tf.float32)

plt.imshow(input_img[0, :, :, :] / 255)
plt.show()

이 이미지에 필터 출력을 최대화하는 방향 그레디언트 벡터를 더해서 이미지를 변형시킨다. 10번을 반복하면 이미지는 다음과 같아진다. 이 이미지가 초기 이미지보다는 해당 필터의 값을 훨씬 더 크게 한다.

In [6]:
img = input_img
for step in range(10):
    loss, grads, img = filterview_iterate(img, filter_index=2)
    print("loss :", loss.numpy())

plt.imshow(img[0, :, :, :] / 255)
plt.show()
loss : 27715.656
loss : 35215.062
loss : 61083.34
loss : 100249.22
loss : 143825.98
loss : 195106.77
loss : 250728.56
loss : 304664.5
loss : 364907.28
loss : 423898.25

간단한 딥드림

딥드림은 초기 이미지로 랜덤한 이미지를 사용하지않고 일반적인 사진 이미지를 사용한다. 여기에서는 scikit-learn이 제공하는 꽃 이미지를 사용한다.

In [7]:
from sklearn.datasets import load_sample_image

raw_img = load_sample_image('flower.jpg')

다음과 같이 전처리 및 후처리 코드를 만든다.

In [8]:
from tensorflow.keras.applications.inception_v3 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array

def preprocess_image(raw_img):
    img = img_to_array(raw_img)
    img = preprocess_input(img)
    img = np.expand_dims(img, axis=0)
    return img

img = preprocess_image(raw_img)

def deprocess_image(img):
    img = np.array(img)
    img = img.reshape((img.shape[1], img.shape[2], 3))
    img /= 2.
    img += 0.5
    img *= 255.
    img = np.clip(img, 0, 255).astype("uint8")
    return img

plt.imshow(deprocess_image(img))
Out: