본문 바로가기

AI/Deep Learning

3. Style Transfer 실습 | Image Style Transfer Using Convolutional Neural Networks (CVPR 2016)

728x90

들어가며


포스팅된 글은 아래에 첨부된 논문과 유튜브 영상을 바탕으로 공부를 한 내용입니다.

이외에도 구글링을 통해 다양한 글들을 참고하며 공부한 내용을 포스팅 한 것 입니다.

또한 본 프로젝트는 클론코딩을 기반으로 공부한 것 입니다.

더보기

논문 제목: Image Style Transfer Using Convolutional Neural Networks (CVPR 2016)

논문 링크: https://rn-unison.github.io/articulos/style_transfer.pdf

유튜브 링크: https://www.youtube.com/watch?v=va3e2c4uKJk 

 

 

 

이전 프로젝트 과정


2021.11.11 - [Output/Computer Vision] - 2. Style&Content Reconstruction 실습 | Image Style Transfer Using Convolutional Neural Networks (CVPR 2016)

 

2. Style&Content Reconstruction 실습 | Image Style Transfer Using Convolutional Neural Networks (CVPR 2016)

들어가며 포스팅된 글은 아래에 첨부된 논문과 유튜브 영상을 바탕으로 공부를 한 내용입니다. 이외에도 구글링을 통해 다양한 글들을 참고하며 공부한 내용을 포스팅 한 것 입니다. 또한 본 프

all-young.tistory.com

 

 

 

프로젝트 과정


Style Transfer 실습하기 1

In [21]:
content_layers = ['conv_4']
style_layers = ['conv_1', 'conv_3', 'conv_5', 'conv_7', 'conv_9']

# Style Transfer 손실(loss)을 계산하는 함수
def get_losses(cnn, content_img, style_img, noise_image):
    cnn = copy.deepcopy(cnn)
    normalization = Normalization(cnn_normalization_mean, cnn_normalization_std).to(device)
    content_losses = []
    style_losses = []
    
    # 가장 먼저 입력 이미지가 입력 정규화(input normalization)를 수행하도록
    model = nn.Sequential(normalization)

    # 현재 CNN 모델에 포함되어 있는 모든 레이어를 확인하며
    i = 0
    for layer in cnn.children():
        if isinstance(layer, nn.Conv2d):
            i += 1
            name = 'conv_{}'.format(i)
        elif isinstance(layer, nn.ReLU):
            name = 'relu_{}'.format(i)
            layer = nn.ReLU(inplace=False)
        elif isinstance(layer, nn.MaxPool2d):
            name = 'pool_{}'.format(i)
        elif isinstance(layer, nn.BatchNorm2d):
            name = 'bn_{}'.format(i)
        else:
            raise RuntimeError('Unrecognized layer: {}'.format(layer.__class__.__name__))

        model.add_module(name, layer)

        # 설정한 content layer까지의 결과를 이용해 content loss를 계산
        if name in content_layers:
            target_feature = model(content_img).detach()
            content_loss = ContentLoss(target_feature)
            model.add_module("content_loss_{}".format(i), content_loss)
            content_losses.append(content_loss)

        # 설정한 style layer까지의 결과를 이용해 style loss를 계산
        if name in style_layers:
            target_feature = model(style_img).detach()
            style_loss = StyleLoss(target_feature)
            model.add_module("style_loss_{}".format(i), style_loss)
            style_losses.append(style_loss)

    # 마지막 loss 이후의 레이어는 사용하지 않도록
    for i in range(len(model) - 1, -1, -1):
        if isinstance(model[i], ContentLoss) or isinstance(model[i], StyleLoss):
            break

    model = model[:(i + 1)]
    return model, content_losses, style_losses
In [22]:
def style_transfer(cnn, content_img, style_img, input_img, iters):
    model, content_losses, style_losses = get_losses(cnn, content_img, style_img, input_img)
    optimizer = optim.LBFGS([input_img.requires_grad_()])

    print("[ Start ]")
    imshow(input_img)

    # 하나의 값만 이용하기 위해 배열 형태로 사용
    run = [0]
    while run[0] <= iters:

        def closure():
            input_img.data.clamp_(0, 1)

            optimizer.zero_grad()
            model(input_img)
            content_score = 0
            style_score = 0

            for cl in content_losses:
                content_score += cl.loss
            for sl in style_losses:
                style_score += sl.loss

            style_score *= 1e5
            loss = content_score + style_score
            loss.backward()

            run[0] += 1
            if run[0] % 100 == 0:
                print(f"[ Step: {run[0]} / Content loss: {content_score.item()} / Style loss: {style_score.item()}]")
                imshow(input_img)
            
            return content_score + style_score
        
        optimizer.step(closure)

    # 결과적으로 이미지의 각 픽셀의 값이 [0, 1] 사이의 값이 되도록 자르기
    input_img.data.clamp_(0, 1)

    return input_img
In [23]:
# 콘텐츠(Content) 이미지와 스타일(Style) 이미지를 모두 준비합니다.
content_img = image_loader('./code_practices/images/content_img_1.jpg', (512, 640))
style_img = image_loader('./code_practices/images/style_img_1.jpg', (512, 640))

print("[ Content Image ]")
imshow(content_img)
print("[ Style Image ]")
imshow(style_img)
 
[ Content Image ]
 
 
[ Style Image ]
 
In [24]:
# 콘텐츠 이미지와 동일한 크기의 노이즈 이미지 준비하기
input_img = torch.empty_like(content_img).uniform_(0, 1).to(device)
imshow(input_img)
 
In [25]:
# style transfer 수행
output = style_transfer(cnn, content_img=content_img, style_img=style_img, input_img=input_img, iters=900)
 
[ Start ]
 
 
[ Step: 100 / Content loss: 44.52748489379883 / Style loss: 27.010915756225586]
 
 
[ Step: 200 / Content loss: 36.79779815673828 / Style loss: 9.159881591796875]
 
 
[ Step: 300 / Content loss: 31.1829891204834 / Style loss: 5.865222454071045]
 
 
[ Step: 400 / Content loss: 27.817337036132812 / Style loss: 4.730966091156006]
 
 
[ Step: 500 / Content loss: 25.578956604003906 / Style loss: 4.089476585388184]
 
 
[ Step: 600 / Content loss: 23.94287109375 / Style loss: 3.9665560722351074]
 
 
[ Step: 700 / Content loss: 22.87112808227539 / Style loss: 3.2565221786499023]
 
 
[ Step: 800 / Content loss: 21.85686683654785 / Style loss: 3.198655366897583]
 
 
[ Step: 900 / Content loss: 21.207813262939453 / Style loss: 3.0289390087127686]
 
In [26]:
from torchvision.utils import save_image

save_image(output.cpu().detach()[0], 'output_1.png')
print('이미지 파일 저장을 완료했습니다.')
 
이미지 파일 저장을 완료했습니다.
In [41]:
from IPython.display import Image

Image('output_1.png')
Out[41]:
 

Style Transfer 실습하기 2

In [67]:
# 콘텐츠(Content) 이미지와 스타일(Style) 이미지를 모두 준비합니다.
content_img = image_loader('./code_practices/images/content_img_2.jpg', (512, 512))
style_img = image_loader('./code_practices/images/style_img_2.jpg', (512, 512))

print("[ Content Image ]")
imshow(content_img)
print("[ Style Image ]")
imshow(style_img)
 
[ Content Image ]
 
 
[ Style Image ]
 
In [68]:
# 콘텐츠 이미지와 동일한 크기의 노이즈 이미지 준비하기
input_img = torch.empty_like(content_img).uniform_(0, 1).to(device)
imshow(input_img)
 
In [69]:
# style transfer 수행
output = style_transfer(cnn, content_img=content_img, style_img=style_img, input_img=input_img, iters=800)
 
[ Start ]
 
 
[ Step: 100 / Content loss: 12.399771690368652 / Style loss: 8.86927318572998]
 
 
[ Step: 200 / Content loss: 8.73117446899414 / Style loss: 3.412388563156128]
 
 
[ Step: 300 / Content loss: 6.892287731170654 / Style loss: 2.2129619121551514]
 
 
[ Step: 400 / Content loss: 5.795084476470947 / Style loss: 1.7047309875488281]
 
 
[ Step: 500 / Content loss: 5.115100860595703 / Style loss: 1.4167126417160034]
 
 
[ Step: 600 / Content loss: 4.678493499755859 / Style loss: 1.214884638786316]
 
 
[ Step: 700 / Content loss: 4.369482517242432 / Style loss: 1.0739508867263794]
 
 
[ Step: 800 / Content loss: 4.165056228637695 / Style loss: 0.9731464385986328]
 
In [70]:
from torchvision.utils import save_image

save_image(output.cpu().detach()[0], 'output_2.png')
print('이미지 파일 저장을 완료했습니다.')
 
이미지 파일 저장을 완료했습니다.
In [72]:
from IPython.display import Image

Image('output_2.png')
Out[72]:

 

 

 

총 프로젝트 공부 및 결과물 과정


2021.09.20 - [History/2021] - [프로젝트] tf.keras를 사용한 Neural Style Transfer

 

[프로젝트] tf.keras를 사용한 Neural Style Transfer

프로젝트 기간 2021.09.20 ~ 2021.11.11 프로젝트 개요 1_프로젝트 소개 프로젝트 명은 tf.keras를 사용한 Neural Style Transfer 인데, 간단히 말하면 케라스를 이용해서 신경 스타일 전이를 하는 것이다. 첫번.

all-young.tistory.com