Skip to content

Commit

Permalink
#175 : 수정!
Browse files Browse the repository at this point in the history
  • Loading branch information
mike2ox committed Oct 25, 2018
2 parents 5f0ac8f + 4ce2f79 commit 619ab44
Show file tree
Hide file tree
Showing 19 changed files with 2,113 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## 케라스 예제 3(Keras examples)
[원문 링크](https://github.com/keras-team/keras/tree/master/examples)
> 현 디렉토리에는 케라스를 활용한 예제들 중 Generative 모델을 다루는 코드들이 있습니다. style transfer, auto encoder 등 generator 이론을 알고있는 전제하에 실제 구현에 초점을 맞춰져 있으므로 코드에 첨가된 주석 외 정보는 직접 찾아보셔야 합니다.
* keras
* neural style transfer
* auto encoder
* lstm
* visualization

### Generative models examples

[lstm_text_generation.py](lstm_text_generation.py)
니체풍의 문장을 생성하기

[conv_filter_visualization.py](conv_filter_visualization.py)
입력공간의 기울기를 통해 VGG16 필터들을 시각화

[deep_dream.py](deep_dream.py)
케라스로 Deep Dream.

[neural_doodle.py](neural_doodle.py)
Keras를 이용해 신경망으로 낙서하기

[neural_style_transfer.py](neural_style_transfer.py)
Neural style transfer.

[variational_autoencoder.py](variational_autoencoder.py)
variational autoencoder를 만드는 방법을 보여줍니다.

[variational_autoencoder_deconv.py](variational_autoencoder_deconv.py)
Deconvolution 레이어와 케라스를 사용해 variational autoencoder를 만드는 방법을 보여줍니다.


> 이 글은 2018 컨트리뷰톤에서 [`Contributue to Keras`](https://github.com/KerasKorea/KEKOxTutorial) 프로젝트로 진행했습니다.
> Translator : [mike2ox](https://github.com/mike2ox) (Moonhyeok Song)
> Translator Email : <[email protected]>
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
'''입력공간의 기울기를 통해 VGG16 필터들을 시각화
이 글은 CPU환경에서 몇분이면 실행할 수 있습니다.
결과 예시 : http://i.imgur.com/4nj4KjN.jpg
'''
from __future__ import print_function

import numpy as np
import time
from keras.preprocessing.image import save_img
from keras.applications import vgg16
from keras import backend as K

# 각 필터들을 위한 생성 이미지의 차원 설정합니다
img_width = 128
img_height = 128

# 시각화하고 싶은 레이어의 이름을 설정합니다
# (모델에 대한 정의는 keras/applications/vgg16.py에서 볼 수 있습니다.)
layer_name = 'block5_conv1'

# 텐서(tensor)를 확인된 이미지로 변환해주는 함수입니다.
def deprocess_image(x):

# 텐서를 정규화합니다 : 중심은 0, 편차는 0.1
x -= x.mean()
x /= (x.std() + K.epsilon())
x *= 0.1

# clip to [0, 1]
x += 0.5
x = np.clip(x, 0, 1)

# RGB 배열로 변환합니다
x *= 255
if K.image_data_format() == 'channels_first':
x = x.transpose((1, 2, 0))
x = np.clip(x, 0, 255).astype('uint8')
return x


# ImageNet의 가중치를 VGG16에 적용, 설계합니다
model = vgg16.VGG16(weights='imagenet', include_top=False)
print('Model loaded.')

model.summary()

# 이미지를 입력받기 위한 placeholder를 설정합니다
input_img = model.input

# (앞서 이름을 지정한)각 핵심 레이어의 출력들을 가져옵니다.
layer_dict = dict([(layer.name, layer) for layer in model.layers[1:]])


def normalize(x):
# L2 norm으로 텐서를 정규화 해주는 함수
return x / (K.sqrt(K.mean(K.square(x))) + K.epsilon())


kept_filters = []
for filter_index in range(200):

# 실제론 512개의 필터가 있지만 처음 200개의 필터만 스캔합니다.
print('Processing filter %d' % filter_index)
start_time = time.time()

# 관심을 두고 있는 레이어의 n번째 필터의 활성화를 최대치로 하는 손실 함수를 설계합니다.
layer_output = layer_dict[layer_name].output
if K.image_data_format() == 'channels_first':
loss = K.mean(layer_output[:, filter_index, :, :])
else:
loss = K.mean(layer_output[:, :, :, filter_index])

# 손실 함수를 통해 입력 이미지의 기울기를 계산합니다
grads = K.gradients(loss, input_img)[0]

# 정규화 기법 : 기울기를 정규화 합니다.
grads = normalize(grads)

# 입력 이미지의 손실과 기울기를 반환합니다.
iterate = K.function([input_img], [loss, grads])

# 기울기 상승을 위해 스탭 크기 지정합니다.
step = 1.

# 몇 개의 임의의 노이즈와 같이 회색 이미지부터 시작합니다.
if K.image_data_format() == 'channels_first':
input_img_data = np.random.random((1, 3, img_width, img_height))
else:
input_img_data = np.random.random((1, img_width, img_height, 3))
input_img_data = (input_img_data - 0.5) * 20 + 128

# 20 스텝동안 기울기 상승을 시도합니다.
for i in range(20):
loss_value, grads_value = iterate([input_img_data])
input_img_data += grads_value * step

print('Current loss value:', loss_value)
if loss_value <= 0.:
# 몇가지 필터가 0을 가질 때는 넘어갑니다.
break

# 입력 이미지의 결과물을 디코드(decode)합니다.
if loss_value > 0:
img = deprocess_image(input_img_data[0])
kept_filters.append((img, loss_value))
end_time = time.time()
print('Filter %d processed in %ds' % (filter_index, end_time - start_time))

# 8 X 8 격자인 64개의 필터들을 사용할 겁니다.
n = 8

# 가장 큰 손실값을 가진 필터는 더 잘보일 것입니다.
# 상위 64개의 필터는 유지시킬 겁니다.
kept_filters.sort(key=lambda x: x[1], reverse=True)
kept_filters = kept_filters[:n * n]

# 128 x 128 크기의 8 x 8 필터를 저장할 수 있는 충분한 공간이 있는 검정 이미지를 만듭니다.
# 5px의 여유공간도 둬야합니다.
margin = 5
width = n * img_width + (n - 1) * margin
height = n * img_height + (n - 1) * margin
stitched_filters = np.zeros((width, height, 3))

# 필터와 이미지를 저장합니다.
for i in range(n):
for j in range(n):
img, loss = kept_filters[i * n + j]
width_margin = (img_width + margin) * i
height_margin = (img_height + margin) * j
stitched_filters[
width_margin: width_margin + img_width,
height_margin: height_margin + img_height, :] = img

# 결과를 디스크에 저장합니다.
save_img('stitched_filters_%dx%d.png' % (n, n), stitched_filters)
195 changes: 195 additions & 0 deletions 25_Keras_examples_3_Generative_models_examples/deep_dream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
'''케라스로 Deep Dreaming 하기
원문 : https://github.com/keras-team/keras/tree/master/examples/deep_dream.py
> 현 스크립트는 케라스를 이용해 입력 이미지의 특징들을 pareidolia 알고리즘으로 분석, 강화시켜
> 마치 꿈, 환각같은 이미지 형태로 출력해주는 튜토리얼입니다.
* deepdream
* keras
* CNN
현 스크립트를 실행하기 위해선:
```
python deep_dream.py path_to_your_base_image.jpg prefix_for_results
```
예 :
```
python deep_dream.py img/mypic.jpg results/dream
```
'''
from __future__ import print_function

from keras.preprocessing.image import load_img, save_img, img_to_array
import numpy as np
import scipy
import argparse

from keras.applications import inception_v3
from keras import backend as K

# 입출력 이미지 경로 설정합니다.
parser = argparse.ArgumentParser(description='Deep Dreams with Keras.')
parser.add_argument('base_image_path', metavar='base', type=str,
help='Path to the image to transform.')
parser.add_argument('result_prefix', metavar='res_prefix', type=str,
help='Prefix for the saved results.')

args = parser.parse_args()
base_image_path = args.base_image_path
result_prefix = args.result_prefix

# 아래 코드는 마지막 손실에서 가중치와 활성화를 최대로 하는 계층들의 이름입니다
# 이제 최대화를 시도해봅시다.
# 밑의 설정들을 수정해서 새로운 시각효과를 얻어봅시다.
settings = {
'features': {
'mixed2': 0.2,
'mixed3': 0.5,
'mixed4': 2.,
'mixed5': 1.5,
},
}


def preprocess_image(image_path):
# 이미지들을 열어서 적절한 tensor에 resize, format 해주는 함수
img = load_img(image_path)
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = inception_v3.preprocess_input(img)
return img


def deprocess_image(x):
# 하나의 tensor를 검증 이미지로 변환해주는 함수
if K.image_data_format() == 'channels_first':
x = x.reshape((3, x.shape[2], x.shape[3]))
x = x.transpose((1, 2, 0))
else:
x = x.reshape((x.shape[1], x.shape[2], 3))
x /= 2.
x += 0.5
x *= 255.
x = np.clip(x, 0, 255).astype('uint8')
return x

K.set_learning_phase(0)

# 실험하실 placehorder(입력 데이터)기반으로 InceptionV3 network를 설계합니다.
# 해당 모델은 ImageNet으로 선행학습된 가중치를 가져올 겁니다.
model = inception_v3.InceptionV3(weights='imagenet',
include_top=False)
dream = model.input
print('Model loaded.')

# 각 핵심 계층의 상징적인 결과를 가져옵니다(고유한 이름을 부여해야 합니다.).
layer_dict = dict([(layer.name, layer) for layer in model.layers])

# 손실을 정의합니다.
loss = K.variable(0.)
for layer_name in settings['features']:
# 계층의 특징들에 대한 L2 norm을 손실에 추가합니다.
assert (layer_name in layer_dict.keys(),
'Layer ' + layer_name + ' not found in model.')
coeff = settings['features'][layer_name]
x = layer_dict[layer_name].output
# 손실에서 경계부분을 제외한 픽셀만 포함시키도록 artifacts(예술작품?) 경계를 피해줍니다.
scaling = K.prod(K.cast(K.shape(x), 'float32'))
if K.image_data_format() == 'channels_first':
loss += coeff * K.sum(K.square(x[:, :, 2: -2, 2: -2])) / scaling
else:
loss += coeff * K.sum(K.square(x[:, 2: -2, 2: -2, :])) / scaling

# 손실에 대해 실제 'dream' 모델의 기울기를 계산합니다.
grads = K.gradients(loss, dream)[0]
# 기울기들을 표준화합니다
grads /= K.maximum(K.mean(K.abs(grads)), K.epsilon())

# 주어진 입력이미지의 기울기들과 손실 값을 검색하는 함수를 설정합니다.
outputs = [loss, grads]
fetch_loss_and_grads = K.function([dream], outputs)


def eval_loss_and_grads(x):
outs = fetch_loss_and_grads([x])
loss_value = outs[0]
grad_values = outs[1]
return loss_value, grad_values


def resize_img(img, size):
img = np.copy(img)
if K.image_data_format() == 'channels_first':
factors = (1, 1,
float(size[0]) / img.shape[2],
float(size[1]) / img.shape[3])
else:
factors = (1,
float(size[0]) / img.shape[1],
float(size[1]) / img.shape[2],
1)
return scipy.ndimage.zoom(img, factors, order=1)


def gradient_ascent(x, iterations, step, max_loss=None):
for i in range(iterations):
loss_value, grad_values = eval_loss_and_grads(x)
if max_loss is not None and loss_value > max_loss:
break
print('..Loss value at', i, ':', loss_value)
x += step * grad_values
return x


"""진행과정
- 원본 이미지를 불러옵니다.
- 아주 작은것부터 가장 큰 것까지,
- 여러가지의 처리 구조를 정의합니다(예: 이미지 형태)
- 원본 이미지를 가장작은 규모로 크기 변경합니다.
- 모든 계층 구조를 위해, 가장 작은 단위에서 시작합니다.(예, 현재 척도):
- 기울기 상승 진행
- 이미지를 다음 규모로 업그레이드
- 업그레이드시 손실된 세부정보를 재입력
- 원래 크기로 돌아갔을 때, 정지합니다.
업그레이드 동안 손실된 세부정보를 얻기 위해, 그저 원본 이미지를 가져와,
축소, 확장하고, 그 결과를 원래 (크기 변경된) 이미지와 비교합니다
"""


# 아래 하이퍼파라미터들을 사용하면 새로운 효과들을 얻을 수 있습니다.
step = 0.01 # 기울기 상승 step의 크기
num_octave = 3 # 기울기 상승을 실행할 때, 계층 구조의 수(?)
octave_scale = 1.4 # 계층들 간 비율
iterations = 20 # 계층마다 (기울기) 상승 step의 횟수
max_loss = 10.

img = preprocess_image(base_image_path)
if K.image_data_format() == 'channels_first':
original_shape = img.shape[2:]
else:
original_shape = img.shape[1:3]
successive_shapes = [original_shape]
for i in range(1, num_octave):
shape = tuple([int(dim / (octave_scale ** i)) for dim in original_shape])
successive_shapes.append(shape)
successive_shapes = successive_shapes[::-1]
original_img = np.copy(img)
shrunk_original_img = resize_img(img, successive_shapes[0])

for shape in successive_shapes:
print('Processing image shape', shape)
img = resize_img(img, shape)
img = gradient_ascent(img,
iterations=iterations,
step=step,
max_loss=max_loss)
upscaled_shrunk_original_img = resize_img(shrunk_original_img, shape)
same_size_original = resize_img(original_img, shape)
lost_detail = same_size_original - upscaled_shrunk_original_img

img += lost_detail
shrunk_original_img = resize_img(original_img, shape)

save_img(result_prefix + '.png', deprocess_image(np.copy(img)))
Loading

0 comments on commit 619ab44

Please sign in to comment.