2024.02.26
Style
- 스타일은 모든 레이어마다 가각 비교하며 오차를 수정한다. 이 때문에 오래 걸리는 한계가 있다.
- CNN을 기반으로 VGG19를 사용해서 Feature Map 사이의 유사성을 비교하여 Loss Funcition을 새롭게 정의한다. grammitrix를 통해 측정한다.
- FeatureMap 3D → Matrix 2D (style)→ Transpose (Noise)
실습
큰 이미지는 연산이 엄청 오래 걸리므로 줄여서 진행
import tensorflow as tf
import cv2
import tensorflow_hub as hub
import matplotlib.pyplot as plt
# Style에 대한 이미지
style_path = tf.keras.utils.get_file("style.jpg", 'http://bit.ly/2mGfZIq')
style_image = plt.imread(style_path)
style_image = cv2.resize(style_image, dsize= (224,224))
style_image = style_image/ 255.
plt.imshow(style_image)
# 타겟이 되는 텍스쳐 : 노이즈로 랜덤하게 생성
# 일단 시작을 Random Noise에서
target_image = tf.random.uniform( style_image.shape)
plt.imshow(target_image)
VGG를 사용하여 이미지의 Feature Map 추출 + 나의 데이터에 맞게 모양 수정
from tensorflow.keras.applications import VGG19
from tensorflow.keras.applications.vgg19 import preprocess_input
vgg = VGG19(include_top= False, weights="imagenet")
# 레이어 구조 확인
for layer in vgg.layers:
print(layer.name)
# 각 블럭에서 특징 결과 Feature Map을 활용할 것들 정의
# & 기존 VGG19의 Conv들은 학습을 하지 않고 그냥 기존 값 사용
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)
gram matrix 정의
def gram_matrix(input_tensor):
ch = int(input_tensor.shape[-1] )
x = tf.reshape(input_tensor, [-1, ch] )
n = tf.shape(x)[0] # 전체 평탄화한 크기
gram = tf.matmul( x, x, transpose_a=True) # 행렬끼리 곱을 전치행렬로
return gram / tf.cast( n, tf.float32) # 레이어별로 크기가 다르기에, 정규화 작업
# 입력 데이터에 적용
style_batch = style_image.astype("float32") # 3차원
style_batch = tf.expand_dims(style_batch, axis =0 ) # 4차원
style_out = model( preprocess_input(style_batch * 255.0 ))
# style에 대한 gram_matrix 결과
style_outputs = [gram_matrix(out) for out in style_out]
# Target에 대한 부분 수정
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
# Style과 Target의 Bloack별로 나오는 Grammatrix
# Loss을 계산 : 두 쪽의 GM의 제곱의 합으로 논문상 정의
def get_loss( outputs, style_outputs):
return tf.reduce_sum([tf.reduce_mean((o-s)**2) for o,s in zip(outputs, style_outputs)])
# 값들이 일정 범위 내에서 존재할 수 있도록 처리하기 위해서
# 0~1사이의 값으로 제한
def clip_0_1( image ):
return tf.clip_by_value(image, clip_value_min=0.0, clip_value_max=1.0
# Loss 최적화
opt = tf.optimizers.Adam(learning_rate=0.2,
beta_1=0.99,
epsilon=1e-1)
미분 수행 과정을 기존의 있는 것을 튜닝하여 진행
TF.미분연산자 tf.GradientTape연산자를 활용해서 수정
@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))
# 스타일 이전 시키기
import IPython.display as display
import time
import imageio
from PIL import Image
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:
#img_2 = Image.fromarray(image.read_value().numpy())
#img_2.save('style_epoch_{0}.png'.format(n),'PNG')
tf.keras.utils.save_img('style_epoch_{0}.png'.format(n),image.read_value().numpy())
#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))
만약 노이즈가 아닌 Content를 추가해서 Style 전이를 하고자 한다면
content_path = tf.keras.utils.get_file('content.jpg', 'http://bit.ly/2mAfUX1')
content_image = plt.imread(content_path)
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)
# Style 이미지
plt.imshow(style_image)
# content 이미지
plt.imshow(content_image)
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))
# 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)
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)
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))
#----------------------------------------------------------#
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:
tf.keras.utils.save_img('style_{0}_content_{1}_transfer_epoch_{2}.png'.format(style_weight, content_weight, n), image.read_value().numpy())
#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))
'ASAC 빅데이터전문가과정 > DL' 카테고리의 다른 글
ASAC 63일차_딥러닝 14일차 (1) | 2024.09.06 |
---|---|
ASAC 60일차_딥러닝 13일차 (1) | 2024.09.06 |
ASAC 57일차_딥러닝 11일차 (0) | 2024.09.05 |
ASAC 56일차_딥러닝 10일차 (5) | 2024.09.05 |
ASAC 55일차_딥러닝 9일차 (0) | 2024.09.04 |