1. 프로젝트 제작 동기
프로젝트 주제를 정할 때 동아리 시간에 배웠던 딥러닝이 어디에 사용되는지 찾아보다가, 이미지 스타일 전이(Style Transfer) 기술을 활용하여 두 개의 이미지를 결합하여 새로운 이미지를 생성하는 것이 가장 흥미롭고 재미있을 것 같다고 생각했습니다. 이에 따라, 일반 이미지와 명화를 결합하여 특정 스타일로 변환하는 프로젝트를 진행하게 되었습니다.
2. 프로젝트 설명
이 프로젝트는 딥러닝을 활용한 스타일 전이(Style Transfer) 기술을 이용하여 하나의 이미지를 다른 이미지의 스타일로 변환하는 시스템을 구현하는 것을 목표로 합니다. 주요 기능은 다음과 같습니다.
- 콘텐츠 이미지와 스타일 이미지 입력
- VGG19 모델을 활용한 스타일 및 콘텐츠 정보 추출
- 스타일 및 콘텐츠 손실 함수 정의 및 최적화
- 스타일이 변환된 최종 이미지 출력
프로젝트는 Google Colab 환경에서 Python을 사용하여 개발되었으며, TensorFlow, NumPy, Matplotlib, PIL 등의 라이브러리를 활용하였습니다.
3. 코드 설명
3.1 이미지 로드 및 전처리
먼저, 이미지 파일을 불러와서 스타일 전이에 적합한 형태로 변환하는 과정을 수행합니다.
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.applications import VGG19
from tensorflow.keras.models import Model
from tensorflow.keras.preprocessing.image import load_img, img_to_array
from tensorflow.keras.applications.vgg19 import preprocess_input
def load_and_process_image(image_path):
img = load_img(image_path, target_size=(512, 512)) # 이미지 크기 조정
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = preprocess_input(img)
return img
# 콘텐츠 및 스타일 이미지 불러오기
content_image = load_and_process_image("content.jpg")
style_image = load_and_process_image("style.jpg")
3.2 VGG19 모델 로드 및 특징 추출
# VGG19 모델 로드 (최상위 분류 레이어 제외)
vgg = VGG19(include_top=False, weights='imagenet')
vgg.trainable = False
# 스타일 및 콘텐츠 레이어 정의
content_layers = ['block4_conv2']
style_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1', 'block5_conv1']
num_style_layers = len(style_layers)
def get_model():
outputs = {layer.name: layer.output for layer in vgg.layers if layer.name in style_layers + content_layers}
model = Model(inputs=vgg.input, outputs=outputs)
return model
model = get_model()
3.3 스타일 및 콘텐츠 손실 정의
def gram_matrix(tensor):
channels = int(tensor.shape[-1])
vectorized = tf.reshape(tensor, [-1, channels])
gram = tf.matmul(tf.transpose(vectorized), vectorized)
return gram / tf.cast(tf.shape(vectorized)[0], tf.float32)
def style_content_loss(outputs, style_targets, content_targets):
style_weight = 1e-2
content_weight = 1e4
style_loss = tf.add_n([tf.reduce_mean((gram_matrix(outputs[name]) - gram_matrix(style_targets[name]))**2)
for name in style_layers])
style_loss *= style_weight / num_style_layers
content_loss = tf.add_n([tf.reduce_mean((outputs[name] - content_targets[name])**2)
for name in content_layers])
content_loss *= content_weight / len(content_layers)
return style_loss + content_loss
3.4 학습 및 스타일 변환
@tf.function
def train_step(image, opt, model, style_targets, content_targets):
with tf.GradientTape() as tape:
outputs = model(image)
loss = style_content_loss(outputs, style_targets, content_targets)
grad = tape.gradient(loss, image)
opt.apply_gradients([(grad, image)])
image.assign(tf.clip_by_value(image, 0.0, 1.0))
# 학습 진행
opt = tf.optimizers.Adam(learning_rate=0.02)
image = tf.Variable(content_image, dtype=tf.float32)
style_targets = model(style_image)
content_targets = model(content_image)
for i in range(1000):
train_step(image, opt, model, style_targets, content_targets)
if i % 100 == 0:
print(f'Step {i} completed')
3.5 최종 결과 출력
def show_image(image):
img = image.numpy().squeeze()
img = np.clip(img, 0, 255).astype('uint8')
plt.imshow(img)
plt.axis('off')
plt.show()
show_image(image)
4. 시연
5. 개선방안 모색
- 스타일 전이 속도 향상을 위한 하이퍼파라미터 최적화
- 더 다양한 스타일을 적용할 수 있도록 데이터셋 확장
- 학습 시간을 줄이기 위한 경량화된 모델 사용