{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### The source code is from https://www.kaggle.com/code/estrelia/painter\n\n### The source code is also belong to me, but created 2 years ago. I might refer others' code at that time, and can't find now.","metadata":{}},{"cell_type":"code","source":"from __future__ import division\nfrom torchvision import models\nfrom torchvision import transforms\nfrom PIL import Image\nimport argparse\nimport torch\nimport torchvision\nimport torch.nn as nn\nimport numpy as np\nimport torchvision.utils as vutils\nimport matplotlib.pyplot as plt\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_image(image_path, transform=None, max_size=None, shape=None):\n    image = Image.open(image_path)    \n    if max_size:\n        scale = max_size / max(image.size)\n        size= np.array(image.size) * scale\n        image = image.resize(size.astype(int), Image.ANTIALIAS)   \n    \n    if shape:\n        image = image.resize(shape, Image.LANCZOS)    \n        \n    if transform:        \n        image = transform(image).unsqueeze(0)   \n        #print(image.shape)  \n    return image.to(device)\n\n\ntransform = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                        std=[0.229, 0.224, 0.225])      \n]) \n\ncontent = load_image(\"/kaggle/input/monet-for-test/0a497f768d.jpg\", transform, max_size=400)\nstyle = load_image(\"/kaggle/input/gan-getting-started/monet_jpg/000c1e3bff.jpg\", transform, shape=[content.size(2), content.size(3)])\n\nprint(content.shape, style.shape) \n\nunloader = transforms.ToPILImage()  # reconvert into PIL image\n\nplt.ion()\n\ndef imshow(tensor, title=None):\n    image = tensor.cpu().clone()  # we clone the tensor to not do changes on it\n    image = image.squeeze(0)      # remove the fake batch dimension\n    image = unloader(image)\n    plt.imshow(image)\n    if title is not None:\n        plt.title(title)\n    plt.pause(0.001) # pause a bit so that plots are updated\n\n\nplt.figure()\nimshow(style[0], title='Style')\nimshow(content[0], title='Image')\n\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class VGGNet(nn.Module):\n    def __init__(self):\n        super(VGGNet, self).__init__()\n        self.select = ['0', '5', '10', '19', '28']   \n        self.vgg = models.vgg19(pretrained=True).features   # 这个地方是拿出vgg19的前面部分， 后面的分类器舍弃掉\n        \n    def forward(self, x):\n        features = []\n        for name, layer in self.vgg._modules.items():\n            x = layer(x)\n            if name in self.select:\n                features.append(x)\n        print(features[0].size(), features[4].size())\n        return features\n\n\ntarget = content.clone().requires_grad_(True)\noptimizer = torch.optim.Adam([target], lr=0.003, betas=[0.5, 0.999])\nvgg = VGGNet().to(device).eval()    # 注意， 这个VGG已经是不训练状态了\n\nprint(vgg.modules)\n\n","metadata":{"execution":{"iopub.status.busy":"2023-04-10T04:31:20.634868Z","iopub.execute_input":"2023-04-10T04:31:20.635153Z","iopub.status.idle":"2023-04-10T04:31:21.045018Z","shell.execute_reply.started":"2023-04-10T04:31:20.635119Z","shell.execute_reply":"2023-04-10T04:31:21.044363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_step = 2000\nstyle_weight = 100.\nfor step in range(total_step):\n    target_features = vgg(target)\n    content_features = vgg(content)\n    style_features = vgg(style)\n    \n    style_loss = 0\n    content_loss = 0\n    for f1, f2, f3 in zip(target_features, content_features, style_features):  # 对于每一层特征， 下面开始计算损失\n        content_loss += torch.mean((f1-f2)**2)         # 内容损失\n        _, c, h, w = f1.size()  # [c, h, w]\n        f1 = f1.view(c, h*w)  #[c, h*w]\n        f3 = f3.view(c, h*w)  # [c, h*w]\n        \n        # 计算gram matrix\n        f1 = torch.mm(f1, f1.t())    # [c, c]\n        f3 = torch.mm(f3, f3.t())    # [c, c]\n        style_loss += torch.mean((f1-f3)**2)/(c*h*w)    # 风格损失\n        \n    loss = content_loss + style_weight * style_loss  # 总的损失\n    \n    # 更新target\n    optimizer.zero_grad()\n    loss.backward()\n    optimizer.step()\n    \n    if step % 100 == 0:\n        print(\"Step [{}/{}], Content Loss: {:.4f}, Style Loss: {:.4f}\"\n             .format(step, total_step, content_loss.item(), style_loss.item()))  ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"denorm = transforms.Normalize((-2.12, -2.04, -1.80), (4.37, 4.46, 4.44))  # 反归一化\nimg = target.clone().squeeze()\nimg = denorm(img).clamp_(0, 1)    # 控制到0-1\nplt.figure()\nimshow(img, title='Target Image')\nplt.savefig('/kaggle/working/0a49020ae5.png')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install torchsummaryX","metadata":{"execution":{"iopub.status.busy":"2023-04-10T05:33:30.248566Z","iopub.execute_input":"2023-04-10T05:33:30.249287Z","iopub.status.idle":"2023-04-10T05:33:38.481058Z","shell.execute_reply.started":"2023-04-10T05:33:30.249246Z","shell.execute_reply":"2023-04-10T05:33:38.480088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchsummaryX import summary\nimport torch\nimport torchvision.models as models\n\nmodel = VGGNet()\nsummary(model, torch.zeros((1, 3, 256, 256)))\n","metadata":{"execution":{"iopub.status.busy":"2023-04-10T05:56:36.994205Z","iopub.execute_input":"2023-04-10T05:56:36.994483Z","iopub.status.idle":"2023-04-10T05:56:39.329069Z","shell.execute_reply.started":"2023-04-10T05:56:36.994452Z","shell.execute_reply":"2023-04-10T05:56:39.328225Z"},"trusted":true},"execution_count":null,"outputs":[]}]}