Python/Deep Learning

전이 학습을 활용한 스타일 변환(Style Transfer)

임베디드 친구 2026. 1. 18. 19:18
728x90
반응형

전이 학습을 활용한 스타일 변환(Style Transfer)

1. 스타일 변환(Style Transfer)이란?

스타일 변환(Style Transfer)은 딥러닝을 활용하여 이미지의 스타일을 변경하는 기술입니다. 이는 콘텐츠 이미지의 구조를 유지하면서 스타일 이미지의 특징을 반영하여 새로운 이미지를 생성하는 방식으로 작동합니다. 예를 들어, 사진을 유명 화가의 화풍으로 변환하는 것이 가능합니다.

이 기술은 전이 학습(Transfer Learning)을 기반으로 하며, 사전 훈련된 신경망 모델을 활용하여 효율적으로 스타일 변환을 수행할 수 있습니다.


2. 스타일 변환의 원리

스타일 변환은 일반적으로 콘텐츠(Content) 손실스타일(Style) 손실을 최소화하는 방향으로 최적화됩니다.

  • 콘텐츠 손실(Content Loss): 콘텐츠 이미지의 고유한 구조(예: 윤곽선, 객체)를 유지하는 데 초점을 맞춘 손실 함수입니다.
  • 스타일 손실(Style Loss): 스타일 이미지의 텍스처 및 색상을 유지하는 데 초점을 맞춘 손실 함수입니다.

이러한 손실 함수를 결합하여 최적화하면, 주어진 콘텐츠 이미지에 스타일을 입힌 새로운 이미지를 생성할 수 있습니다.


3. 전이 학습을 활용한 스타일 변환 구현

스타일 변환을 구현하는 방법에는 여러 가지가 있지만, 대표적으로 VGG19 같은 사전 훈련된 CNN 모델을 활용하여 스타일 변환을 수행할 수 있습니다. 이 모델은 사전 학습된 가중치를 활용하여 빠르게 스타일 변환을 적용할 수 있습니다.

3.1 필요 라이브러리 설치

pip install tensorflow matplotlib numpy

3.2 코드 구현

아래는 TensorFlow와 VGG19 모델을 활용하여 스타일 변환을 수행하는 Python 코드입니다.

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

def load_and_process_image(image_path, target_size=(400, 400)):
    img = load_img(image_path, target_size=target_size)
    img = img_to_array(img)
    img = np.expand_dims(img, axis=0)
    img = vgg19.preprocess_input(img)
    return img

def deprocess_image(img):
    img = img.reshape((img.shape[1], img.shape[2], 3))
    img[:, :, 0] += 103.939
    img[:, :, 1] += 116.779
    img[:, :, 2] += 123.68
    img = np.clip(img, 0, 255).astype('uint8')
    return img

content_path = 'content.jpg'  # 콘텐츠 이미지 경로
style_path = 'style.jpg'  # 스타일 이미지 경로

content_image = load_and_process_image(content_path)
style_image = load_and_process_image(style_path)

plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('Content Image')
plt.imshow(deprocess_image(content_image.copy()))
plt.subplot(1, 2, 2)
plt.title('Style Image')
plt.imshow(deprocess_image(style_image.copy()))
plt.show()

위 코드는 콘텐츠 및 스타일 이미지를 로드하고, VGG19 모델이 요구하는 형식으로 전처리하는 역할을 합니다.


4. VGG19 모델을 활용한 스타일 변환

VGG19는 이미지 분류를 위한 CNN 모델이지만, 중간 계층의 특징 맵을 활용하면 스타일 변환에 사용할 수 있습니다.

4.1 VGG19 모델 로드 및 특정 계층 선택

vgg = vgg19.VGG19(weights='imagenet', include_top=False)
vgg.trainable = False

def get_model():
    content_layers = ['block5_conv2']  # 콘텐츠 정보를 추출할 계층
    style_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1', 'block5_conv1']

    outputs = {layer.name: layer.output for layer in vgg.layers if layer.name in (content_layers + style_layers)}
    model = Model(inputs=vgg.input, outputs=outputs)
    return model, content_layers, style_layers

model, content_layers, style_layers = get_model()

이제 모델을 활용하여 콘텐츠 손실과 스타일 손실을 계산할 수 있습니다.

4.2 손실 함수 정의 및 최적화

def compute_content_loss(content, generated):
    return tf.reduce_mean(tf.square(content - generated))

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 compute_style_loss(style, generated):
    return tf.reduce_mean(tf.square(gram_matrix(style) - gram_matrix(generated)))

이제 전체 손실 함수를 정의하고 최적화하면 스타일 변환을 수행할 수 있습니다.

optimizer = tf.keras.optimizers.Adam(learning_rate=5.0)

def compute_loss(model, content_image, style_image, generated_image):
    outputs = model(generated_image)

    content_loss = compute_content_loss(outputs['block5_conv2'], model(content_image)['block5_conv2'])
    style_loss = sum(compute_style_loss(outputs[layer], model(style_image)[layer]) for layer in style_layers)

    total_loss = content_loss + 1e-4 * style_loss
    return total_loss

def train_step(generated_image):
    with tf.GradientTape() as tape:
        loss = compute_loss(model, content_image, style_image, generated_image)
    grads = tape.gradient(loss, generated_image)
    optimizer.apply_gradients([(grads, generated_image)])
    return loss

5. 결론

이제 위에서 정의한 손실 함수를 기반으로 생성된 이미지를 업데이트하면서 스타일 변환을 진행할 수 있습니다.

generated_image = tf.Variable(content_image, dtype=tf.float32)
for i in range(1000):
    loss = train_step(generated_image)
    if i % 100 == 0:
        print(f'Step {i}, Loss: {loss.numpy()}')

위 코드를 실행하면, 콘텐츠 이미지를 스타일 이미지의 특징을 반영하여 변환하는 과정이 진행됩니다.

스타일 변환은 예술적 이미지 생성, 사진 편집, 콘텐츠 변형 등의 분야에서 폭넓게 활용될 수 있습니다. 전이 학습을 활용하면 더욱 효과적이고 빠르게 스타일 변환을 수행할 수 있습니다.

반응형