구글colab을 이용했다.
from google.colab import drive
drive.mount('/content/drive')
구글 colab은 구글드라이브와 연동이 가능하다. 연동하기 위해서는 google.colab의 drive를 임포트 해줘야한다.
drive.mount함수를 이용해 내 계정의 구글드라이브를 마운트 시켜준다
# 8.42 원본 텍스쳐 이미지 불러오기
import tensorflow as tf
import matplotlib.pyplot as plt
import cv2
# 스타일 이미지
style_path=r'/content/drive/MyDrive/pp.jpg'
# 스타일 이미지 경로를 이용해 읽은 이미지를 style_image에 저장
style_image = plt.imread(style_path)
# 사진의 사이즈를 알맞게 조정 및 정규화 과정
style_image = cv2.resize(style_image, dsize=(224, 224))
style_image = style_image / 255.0
plt.imshow(style_image)
# 8.43 타겟 텍스쳐 만들기
target_image = tf.random.uniform(style_image.shape)
print(target_image[0,0,:])
plt.imshow(target_image)
RGB차원이므로 shape는 3으로 출력된다.
출력된 첫번째 픽셀값을 살펴보면 0에서 1사이의 값으로 이루어진 것을 확인할 수 있다.
# 8.44 VGG-19 네트워크 불러오기
from tensorflow.keras.applications import VGG19
from tensorflow.keras.applications.vgg19 import preprocess_input
vgg = VGG19(include_top=False, weights='imagenet')
# 8.45 특징 추출 모델 만들기
style_layers = ['block1_conv1',
'block2_conv1',
'block3_conv1',
'block4_conv1',
'block5_conv1']
vgg.trainable = False
outputs = [vgg.get_layer(name).output for name in style_layers]
model = tf.keras.Model([vgg.input], outputs)
# 8.46 Gram matrix 계산 함수 정의
def gram_matrix(input_tensor):
channels = int(input_tensor.shape[-1]) # 맨 뒤 차원만 남기고
a = tf.reshape(input_tensor, [-1, channels]) # 1차원 벡터로 만든다
n = tf.shape(a)[0]
gram = tf.matmul(a, a, transpose_a=True)
return gram / tf.cast(n, tf.float32)
matmul행렬곱 함수를 이용한 결과를 통해 차원수가 (224,224,64)에서 (64,64)로 줄어들게 됐다.
# 8.47 원본 텍스쳐에서 gram matrix 계산
style_image = plt.imread(style_path)
style_image = cv2.resize(style_image, dsize=(224, 224))
style_image = style_image / 255.0
style_batch = style_image.astype('float32')
style_batch = tf.expand_dims(style_batch, axis=0)
style_output = model(preprocess_input(style_batch * 255.0))
# 8.48 원본 텍스쳐의 첫번째 특징 추출값 확인
print(style_output[0].shape)
plt.imshow(tf.squeeze(style_output[0][:,:,:,0], 0), cmap='gray')
내가 지정한 스타일이미지의 특징 추출값을 확인할 수 있다.
# 8.50 타겟 텍스쳐를 업데이트하기 위한 함수 정의
def get_outputs(image):
image_batch = tf.expand_dims(image, axis=0)
output = model(preprocess_input(image_batch * 255.0))
outputs = [gram_matrix(out) for out in output]
return outputs
def get_loss(outputs, style_outputs):
return tf.reduce_sum([tf.reduce_mean((o-s)**2) for o,s in zip(outputs, style_outputs)])
def clip_0_1(image):
return tf.clip_by_value(image, clip_value_min=0.0, clip_value_max=1.0)
# 8.51 tf.function과 GradientTape을 이용한 이미지 업데이트 함수 정의
opt = tf.optimizers.Adam(learning_rate=0.2, beta_1=0.99, epsilon=1e-1)
@tf.function()
def train_step(image):
with tf.GradientTape() as tape:
outputs = get_outputs(image)
loss = get_loss(outputs, style_outputs)
grad = tape.gradient(loss, image)
opt.apply_gradients([(grad, image)])
image.assign(clip_0_1(image))
# 8.52 텍스쳐 합성 알고리즘 실행
import IPython.display as display
import time
import imageio
start = time.time()
image = tf.Variable(target_image)
epochs = 50
steps_per_epoch = 100
step = 0
for n in range(epochs):
for m in range(steps_per_epoch):
step += 1
train_step(image)
if n % 5 == 0 or n == epochs - 1:
imageio.imwrite('style_epoch_{0}.png'.format(n), image.read_value().numpy())
display.clear_output(wait=True)
plt.imshow(image.read_value())
plt.title("Train step: {}".format(step))
plt.show()
end = time.time()
print("Total time: {:.1f}".format(end-start))
variation을 도입하면서 좀 더 나은 텍스처 합성결과를 얻을 수 있다 (보완)
# 8.53 varitation loss 함수 정의
def high_pass_x_y(image):
x_var = image[:,1:,:] - image[:,:-1,:]
y_var = image[1:,:,:] - image[:-1,:,:]
return x_var, y_var
def total_variation_loss(image):
x_deltas, y_deltas = high_pass_x_y(image)
return tf.reduce_mean(x_deltas**2) + tf.reduce_mean(y_deltas**2)
# 8.55 variation loss를 loss 계산식에 추가, 각 loss의 가중치 추가
total_variation_weight = 1e9
style_weight = 1e-1
@tf.function()
def train_step(image):
with tf.GradientTape() as tape:
outputs = get_outputs(image)
loss = style_weight * get_loss(outputs, style_outputs)
loss += total_variation_weight * total_variation_loss(image)
grad = tape.gradient(loss, image)
opt.apply_gradients([(grad, image)])
image.assign(clip_0_1(image))
# 8.56 variation loss를 추가한 텍스쳐 합성 알고리즘 실행
start = time.time()
target_image = tf.random.uniform(style_image.shape)
image = tf.Variable(target_image)
epochs = 50
steps_per_epoch = 100
step = 0
for n in range(epochs):
for m in range(steps_per_epoch):
step += 1
train_step(image)
if n % 5 == 0 or n == epochs - 1:
imageio.imwrite('style_variation_epoch_{0}.png'.format(n), image.read_value().numpy())
display.clear_output(wait=True)
plt.imshow(image.read_value())
plt.title("Train step: {}".format(step))
plt.show()
end = time.time()
print("Total time: {:.1f}".format(end-start))
original : tf.Tensor(0.055965573881594025)
target : tf.Tensor(0.11866248)
- > target : tf.Tensor(0.04533544)
보완한 텍스처의 loss값이 줄어든 것을 확인 (심지어 원본값보다 작음)
이제 내가 지정한 사진을 스타일 이미지를 통해 변형을 할 차례다
# 8.58 content 텍스쳐 불러오기
import matplotlib.pyplot as plt
import cv2
# content_path = tf.keras.utils.get_file('content.jpg', 'http://bit.ly/2mAfUX1')
content_path=r'/content/drive/MyDrive/soob.jpg'
content_image = plt.imread(content_path)
# content_image=cv2.rotate(content_image, cv2.ROTATE_90_CLOCKWISE) # 사진 회전되어 있으면
max_dim = 512
long_dim = max(content_image.shape[:-1])
scale = max_dim / long_dim
new_height = int(content_image.shape[0] * scale)
new_width = int(content_image.shape[1] * scale)
content_image = cv2.resize(content_image, dsize=(new_width, new_height))
content_image = content_image / 255.0
plt.figure(figsize=(8,8))
plt.imshow(content_image)
# 8.59 content 특징 추출 모델 만들기
content_batch = content_image.astype('float32')
content_batch = tf.expand_dims(content_batch, axis=0)
content_layers = ['block5_conv2']
vgg.trainable = False
outputs = [vgg.get_layer(name).output for name in content_layers]
model_content = tf.keras.Model([vgg.input], outputs)
content_output = model_content(preprocess_input(content_batch * 255.0))
# 8.60 content output, loss 함수 정의
def get_content_output(image):
image_batch = tf.expand_dims(image, axis=0)
output = model_content(preprocess_input(image_batch * 255.0))
return output
def get_content_loss(image, content_output):
return tf.reduce_sum(tf.reduce_mean(image-content_output)**2)
# 8.61 content loss를 loss 계산식에 추가
opt = tf.optimizers.Adam(learning_rate=0.001, beta_1=0.99, epsilon=1e-1)
total_variation_weight = 1e9
style_weight = 1e-2
content_weight = 1e4
@tf.function()
def train_step(image):
with tf.GradientTape() as tape:
outputs = get_outputs(image)
output2 = get_content_output(image)
loss = style_weight * get_loss(outputs, style_outputs)
loss += content_weight * get_content_loss(output2, content_output)
loss += total_variation_weight * total_variation_loss(image)
grad = tape.gradient(loss, image)
opt.apply_gradients([(grad, image)])
image.assign(clip_0_1(image))
# 8.62 Neural Style Transfer 실행
start = time.time()
# target_image = tf.random.uniform(content_image.shape)
image = tf.Variable(content_image.astype('float32'))
epochs = 20
steps_per_epoch = 100
step = 0
for n in range(epochs):
for m in range(steps_per_epoch):
step += 1
train_step(image)
print(".", end='')
if n % 5 == 0 or n == epochs - 1:
imageio.imwrite('style_{0}_content_{1}_transfer_epoch_{2}.png'
.format(style_weight, content_weight, n), image.read_value().numpy())
display.clear_output(wait=True)
plt.figure(figsize=(8,8))
plt.imshow(image.read_value())
plt.title("Train step: {}".format(step))
plt.show()
end = time.time()
print("Total time: {:.1f}".format(end-start))
출처: github.com/wikibook/tf2/blob/master/Chapter8.ipynb
'전공 과목 이수2👨💻 > 딥러닝' 카테고리의 다른 글
Pytorch입문 - 텐서 기본 문법 (0) | 2022.01.16 |
---|---|
ImageNet 신경망 불러와서 이미지 학습,분류 하기 (0) | 2022.01.16 |
CNN : 합성곱 신경망(컨볼루션 신경망) (0) | 2022.01.02 |
GAN 개구리 사진 (0) | 2021.02.05 |
ZYNQ 키트를 활용한 숫자 판별시스템 (0) | 2021.02.04 |
딥러닝에서의 회귀 (Regression) (0) | 2021.01.24 |