рд╕реНрдЯрд╛рдЗрд▓ рдЯреНрд░рд╛рдВрд╕рдлрд░ рд╕реНрд░реЛрдд рдХреА рд╢реИрд▓реА рдХреЛ рдЪрдпрдирд┐рдд рдЫрд╡рд┐ рдХреА рд╢реИрд▓реА рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИ рдФрд░ рдкрд╣рд▓реЗ рд╕реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рд╣реЛрдиреЗ рдХреЗ рджреМрд░рд╛рди рдХрдиреНрд╡реЗрдВрд╢рди рдкреНрд░рдХрд╛рд░ рдХреЗ рдиреЗрдЯрд╡рд░реНрдХ (CNN) рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдмрд╣реБрдд рдХреБрдЫ рдЗрд╕ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдиреЗрдЯрд╡рд░реНрдХ рдХреА рдкрд╕рдВрдж рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░реЗрдЧрд╛ред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдРрд╕реЗ рдиреЗрдЯрд╡рд░реНрдХ рд╣реИрдВ рдФрд░ рдЪреБрдирдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдХреБрдЫ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рд╡реАрдЬреАрдЬреА -16 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рдХрдиреЗрдХреНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛
рдкреБрд╕реНрддрдХрд╛рд▓рдп рдШреЛрд╖рдгрд╛ рдХреЛрдбimport time import torch from torch.autograd import Variable import torch.nn as nn import torch.nn.functional as F from torch import optim import torchvision from torchvision import transforms from io import BytesIO from PIL import Image from collections import OrderedDict from google.colab import files
рдлрд┐рд░ рдЖрдкрдХреЛ рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдиреЗрдЯрд╡рд░реНрдХ рд╡реАрдЬреАрдЬреА -16 рдХреЗ рд╡рд░реНрдЧ рдХреЛ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
рдХрдХреНрд╖рд╛ рдХреЛрдб VGG-16 class VGG16(nn.Module): def __init__(self, pool='max'): super(VGG, self).__init__() self.conv1_1 = nn.Conv2d(3, 64, kernel_size=3, padding=1) self.conv1_2 = nn.Conv2d(64, 64, kernel_size=3, padding=1) self.conv2_1 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.conv2_2 = nn.Conv2d(128, 128, kernel_size=3, padding=1) self.conv3_1 = nn.Conv2d(128, 256, kernel_size=3, padding=1) self.conv3_2 = nn.Conv2d(256, 256, kernel_size=3, padding=1) self.conv3_3 = nn.Conv2d(256, 256, kernel_size=3, padding=1) self.conv3_4 = nn.Conv2d(256, 256, kernel_size=3, padding=1) self.conv4_1 = nn.Conv2d(256, 512, kernel_size=3, padding=1) self.conv4_2 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.conv4_3 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.conv4_4 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.conv5_1 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.conv5_2 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.conv5_3 = nn.Conv2d(512, 512, kernel_size=3, padding=1) self.conv5_4 = nn.Conv2d(512, 512, kernel_size=3, padding=1) if pool == 'max': self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool5 = nn.MaxPool2d(kernel_size=2, stride=2) elif pool == 'avg': self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2) self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2) self.pool3 = nn.AvgPool2d(kernel_size=2, stride=2) self.pool4 = nn.AvgPool2d(kernel_size=2, stride=2) self.pool5 = nn.AvgPool2d(kernel_size=2, stride=2) def forward(self, x, layers): out = {} out['relu1_1'] = F.relu(self.conv1_1(x)) out['relu1_2'] = F.relu(self.conv1_2(out['relu1_1'])) out['pool1'] = self.pool1(out['relu1_2']) out['relu2_1'] = F.relu(self.conv2_1(out['pool1'])) out['relu2_2'] = F.relu(self.conv2_2(out['relu2_1'])) out['pool2'] = self.pool2(out['relu2_2']) out['relu3_1'] = F.relu(self.conv3_1(out['pool2'])) out['relu3_2'] = F.relu(self.conv3_2(out['relu3_1'])) out['relu3_3'] = F.relu(self.conv3_3(out['relu3_2'])) out['relu3_4'] = F.relu(self.conv3_4(out['relu3_3'])) out['pool3'] = self.pool3(out['relu3_4']) out['relu4_1'] = F.relu(self.conv4_1(out['pool3'])) out['relu4_2'] = F.relu(self.conv4_2(out['relu4_1'])) out['relu4_3'] = F.relu(self.conv4_3(out['relu4_2'])) out['relu4_4'] = F.relu(self.conv4_4(out['relu4_3'])) out['pool4'] = self.pool4(out['relu4_4']) out['relu5_1'] = F.relu(self.conv5_1(out['pool4'])) out['relu5_2'] = F.relu(self.conv5_2(out['relu5_1'])) out['relu5_3'] = F.relu(self.conv5_3(out['relu5_2'])) out['relu5_4'] = F.relu(self.conv5_4(out['relu5_3'])) out['pool5'] = self.pool5(out['relu5_4']) return [out[key] for key in layers]
рдЕрдЧрд▓рд╛, рдЖрдкрдХреЛ рд╡реАрдЬреАрдЬреА -16 рднрд╛рд░ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рд▓реЛрдб рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдпрджрд┐ рд╕рдВрднрд╡ рд╣реЛ рддреЛ рдкрд╣рд▓реЗ рдЗрд╕реЗ рд╡реАрдбрд┐рдпреЛ рдХрд╛рд░реНрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдП
vgg = VGG16() vgg.load_state_dict(torch.load('vgg_conv.pth')) for param in vgg.parameters(): param.requires_grad = False if torch.cuda.is_available(): vgg.cuda()
рдЬрд╣рд╛рдБ vgg_conv.pth рдиреЗрдЯрд╡рд░реНрдХ рд╡реЗрдЯ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдирд╛рдо рд╣реИред
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЛ рдЕрдХреНрд╖рдо рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЕрдиреНрдпрдерд╛ рдЖрдк рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рджрд┐рдиреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рднрд╛рд░ рднрд╛рд░ рдХреЛ рдЦрд░рд╛рдм рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЗрд╕рдХреЗ рдмрд╛рдж, рдЗрдирдкреБрдЯ рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдЙрди рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдиреЗ рдХреА рдШреЛрд╖рдгрд╛ рдХреА рдЬрд╛рддреА рд╣реИ, рдЬрд┐рди рдкрд░ VGG-16 рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛
рдЗрдирдкреБрдЯ рдЫрд╡рд┐ рд░реВрдкрд╛рдВрддрд░рдг рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЛрдб SIZE_IMAGE = 512 to_mean_tensor = transforms.Compose([transforms.Resize(SIZE_IMAGE), transforms.ToTensor(), transforms.Lambda(lambda x: x[torch.LongTensor([2,1,0])]), transforms.Normalize(mean=[0.40760392, 0.45795686, 0.48501961], std=[1,1,1]), transforms.Lambda(lambda x: x.mul_(255)), ]) to_unmean_tensor = transforms.Compose([transforms.Lambda(lambda x: x.div_(255)), transforms.Normalize(mean=[-0.40760392, -0.45795686, -0.48501961], std=[1,1,1]), transforms.Lambda(lambda x: x[torch.LongTensor([2,1,0])]), ]) to_image = transforms.Compose([transforms.ToPILImage()]) normalize_image = lambda t: to_image(torch.clamp(to_unmean_tensor(t), min=0, max=1))
to_mean_tensor - рдкреНрд░рддреНрдпрдХреНрд╖ рд░реВрдкрд╛рдВрддрд░рдг
normalize_image - рдЙрд▓рдЯрд╛ рд░реВрдкрд╛рдВрддрд░
рдЗрд╕рдХреЗ рдмрд╛рдж, рдЧреНрд░рд╛рдо рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЗ рд▓рд┐рдП рдЧреНрд░рд╛рдо рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХрдХреНрд╖рд╛рдПрдВ рдФрд░ рд╣рд╛рдирд┐ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХреА рдЬрд╛рддреА рд╣реИ
class GramMatrix(nn.Module): def forward(self, input): b,c,h,w = input.size() F = input.view(b, c, h*w) G = torch.bmm(F, F.transpose(1,2)) G.div_(h*w) return G class GramMSELoss(nn.Module): def forward(self, input, target): out = nn.MSELoss()(GramMatrix()(input), target) return out
рдЧреНрд░рд╛рдо рдореИрдЯреНрд░рд┐рдХреНрд╕ рд╢реИрд▓реА рд╡рд┐рд╡рд░рдг рдХреЗ рд╕реНрдерд╛рдирд┐рдХ рд╕рдВрджрд░реНрдн рдХреЛ рдЦрддреНрдо рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред
рдлрд┐рд░ рд╕реНрд░реЛрдд рдФрд░ рд╢реИрд▓реА рдХреА рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЖрддреА рд╣реИ
imgs = [style_img, content_img] imgs_torch = [to_mean_tensor(img) for img in imgs] if torch.cuda.is_available(): imgs_torch = [Variable(img.unsqueeze(0).cuda()) for img in imgs_torch] else: imgs_torch = [Variable(img.unsqueeze(0)) for img in imgs_torch] style_image, content_image = imgs_torch opt_img = Variable(content_image.data.clone(), requires_grad=True)
рдЬрд╣рд╛рдБ style_img рдФрд░ content_img рдРрд╕реА рдЗрдирдкреБрдЯ рдЫрд╡рд┐рдпрд╛рдВ рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЗрдВ рдЯреЗрдВрд╕рд░реЛрдВ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдпрджрд┐ рд╕рдВрднрд╡ рд╣реЛ рддреЛ рд╡реАрдбрд┐рдпреЛ рдХрд╛рд░реНрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ Opt_img рдореЗрдВ рд╢реИрд▓реА рд╣рд╕реНрддрд╛рдВрддрд░рдг рдХрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реЛрдЧрд╛, рдФрд░ рдореВрд▓ рдЫрд╡рд┐ рдХреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЕрдЧрд▓рд╛ рдкрд░рддреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ, рд╡рдЬрди рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдФрд░ рдиреБрдХрд╕рд╛рди рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИ
рд╡рдЬрди рдФрд░ рд╣рд╛рдирд┐ рдХреЛрдб style_layers = ['relu1_1','relu2_1','relu3_1','relu4_1', 'relu5_1'] content_layers = ['relu4_2'] loss_layers = style_layers + content_layers losses = [GramMSELoss()] * len(style_layers) + [nn.MSELoss()] * len(content_layers) if torch.cuda.is_available(): losses = [loss.cuda() for loss in losses] style_weights = [1e3/n**2 for n in [64,128,256,512,512]] content_weights = [1e0] weights = style_weights + content_weights style_targets = [GramMatrix()(A).detach() for A in vgg(style_image, style_layers)] content_targets = [A.detach() for A in vgg(content_image, content_layers)] targets = style_targets + content_targets
рдФрд░ рдЕрдВрддрд┐рдо рдЪрд░рдг рд╢реИрд▓реА рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИ
epochs = 300 opt = optim.LBFGS([opt_img]) def step_opt(): opt.zero_grad() out_layers = vgg(opt_img, loss_layers) layer_losses = [] for j, out in enumerate(out_layers): layer_losses.append(weights[j] * losses[j](out, targets[j])) loss = sum(layer_losses) loss.backward() return loss for i in range(0, epochs+1): loss = opt.step(step_opt)
рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ, рдЖрдк рдХреБрдЫ рдЙрджрд╛рд╣рд░рдг рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:














