728x90
들어가며
포스팅된 글은 아래에 첨부된 논문과 유튜브 영상을 바탕으로 공부를 한 내용입니다.
이외에도 구글링을 통해 다양한 글들을 참고하며 공부한 내용을 포스팅 한 것 입니다.
또한 본 프로젝트는 클론코딩을 기반으로 공부한 것 입니다.
더보기
논문 제목: Image Style Transfer Using Convolutional Neural Networks (CVPR 2016)
논문 링크: https://rn-unison.github.io/articulos/style_transfer.pdf
이전 프로젝트 과정
프로젝트 과정
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