NeuroWhAI의 잡블로그

수알못의 '딥 드림(Deep Dream)' 원리 파헤치기 본문

개발 및 공부

수알못의 '딥 드림(Deep Dream)' 원리 파헤치기

NeuroWhAI 2019. 1. 7. 21:23


(귀여운 고양이 사진을 혐짤로 만드는 예시)

지금 보는 케라스 책의 VGG16을 이용한 딥 드림 이미지 생성 예제를 실습하고 있는데 결과물이 이렇게 나오는 이유가 뭘까 생각한 것을 정리 해봅니다.
수알못이라 설명이 실제와는 많이 다를 것 같습니다 ㅠ
수알, 딥알님들의 설명을 기다립니다..!

코드는 다 필요없고 핵심만 남기면 아래와 같습니다.
for i in range(num_pool_layers):
  layer_name = "block{:d}_pool".format(i+1)
  print("Pooling layer: {:s}".format(layer_name))
  layer_output = layer_dict[layer_name].output
  # Loss
  loss = K.mean(layer_output)
  # Grad
  grads = K.gradients(loss, dream)[0]
  grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
  # Optimizer
  f = K.function([dream], [grads])
  img_value = p_img.copy()
  fig, axes = plt.subplots(1, num_iters_per_layer, figsize=(20, 10))
  for it in range(num_iters_per_layer):
    [grads_value] = f([img_value])
    img_value += grads_value * step
    axes[it].imshow(deprocess(img_value))
  plt.show()
각 풀링 레이어에 대해 여러번(num_iters_per_layer번) 딥 드림 이미지를 생성하는 부분입니다.
일단 기울기(grads)를 구하는데 무엇에 대한 기울기냐 하면 dream의 변화량에 대한 loss의 변화량이 됩니다.
loss는 현재 레이어 출력의 평균이죠.
현재 레이어 출력의 평균이 무엇을 의미할까 생각을 해봤습니다.
CNN의 커널은 흔히 어떤 특징을 추출하는, 특정한 특징에 활성화 되는 역할을 합니다.
그러니까 입력과 커널의 합성곱 결과가 클수록 입력이 커널이 나타내는 특징을 강하게 가지고 있다고 해석을 할 수 있을겁니다.
그러니까 다시 현재 레이어 출력의 평균이라고 함은 입력이 커널들의 특징을 평균적으로 얼마나 강하게 가지고 있는가가 될겁니다.
그렇기 때문에 위에서 구한 기울기는 입력 이미지(dream)의 각 픽셀이 변화할 때 (커널들을 평균적으로 활성화 시키는) 이미지의 특징이 얼마나 강해지느냐를 뜻하는 값이 됩니다.
그렇다면 이 값을 기존 이미지에 더하는 것은 그런 특징들을 그대로 이미지에 추가하는 행동이 될 것입니다.
예를 들어 고양이에 활성화 되는 커널에 대해 위 방법으로 각 픽셀별 기울기를 구했다면 고양이와 관련된 픽셀이 더 큰 기울기 값을 가지고 있을 겁니다.
이 값을 그대로 해당 픽셀에 더하면 그 특징을 이미지에서 더 강조하는 행동이 될 것이죠.
그래서 딥 드림이 과도하게 특징을 강조한 것 같은 이미지를 만드는게 아닌가 추측을 해봤습니다.
단순한 원인데 눈으로 만들어 내는 것도 원이 눈을 인식하는 커널의 활성화에 기여하기 때문인 것일테죠..
딥 드림이 신경망 속에서 대체 무슨 일이 일어나고 있는 것인지를 알기 위한 연구에서 나온 것이라는 설명과도 앞뒤가 맞는 것 같네요.
위 코드에선 모든 커널에 대한 평균 특징을 강조하니 이것저것 다 섞인 결과물이 나오는 것 같습니다.

사실 이 추측에 따르면 `grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)` 이 부분은 필요가 없는데 뭐 수학적인 이유가 있겠죠... ㅠ
실제로 해당 부분을 주석처리하고 step을 수만배 늘려줘도 비슷한 결과가 나오더라구요.

제 추측이 맞나 모르겠네요.
참 머리 아픕니다 ㅠㅠ
실습하는 것은 어렵지 않은데 대체 무슨 원리로 이 코드가 저런 결과물을 만드는지 신기하기만 합니다..

가르침은 언제나 환영합니다!




Comments