{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"},{"sourceId":199828,"sourceType":"datasetVersion","datasetId":86746},{"sourceId":517453,"sourceType":"datasetVersion","datasetId":232742},{"sourceId":2684635,"sourceType":"datasetVersion","datasetId":1634071},{"sourceId":4202543,"sourceType":"datasetVersion","datasetId":2477766},{"sourceId":8975017,"sourceType":"datasetVersion","datasetId":5403736},{"sourceId":8975076,"sourceType":"datasetVersion","datasetId":5403788}],"dockerImageVersionId":30132,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"---------------------------------------\n# Introduction","metadata":{}},{"cell_type":"code","source":"# import resources\n%matplotlib inline\n\nfrom PIL import Image\nfrom io import BytesIO\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nimport torch\nimport torch.optim as optim\nimport requests\nfrom torchvision import transforms, models\nimport torch.nn as nn","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:02:55.920137Z","iopub.execute_input":"2024-08-05T16:02:55.920729Z","iopub.status.idle":"2024-08-05T16:03:00.774122Z","shell.execute_reply.started":"2024-08-05T16:02:55.920655Z","shell.execute_reply":"2024-08-05T16:03:00.773328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# chúng ta chỉ lấy vgg19 fearture mà không dùng classifier vì đây không phải bài toán classifi\nvgg = models.vgg19(pretrained=True).features\n\n# dùng hàm freeze để các trọng số của model sẽ không được cập nhật\nfor param in vgg.parameters():\n    param.requires_grad_(False)","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:03:00.775706Z","iopub.execute_input":"2024-08-05T16:03:00.775952Z","iopub.status.idle":"2024-08-05T16:03:05.157095Z","shell.execute_reply.started":"2024-08-05T16:03:00.775926Z","shell.execute_reply":"2024-08-05T16:03:05.156321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# chuyển model sang gpu\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nvgg.to(device)","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:03:05.158166Z","iopub.execute_input":"2024-08-05T16:03:05.158365Z","iopub.status.idle":"2024-08-05T16:03:10.77977Z","shell.execute_reply.started":"2024-08-05T16:03:05.158342Z","shell.execute_reply":"2024-08-05T16:03:10.779064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"-----------------------------------------------\n# 2. Load in Content and Style Images\n\nLoad the content image and style image to be used for style transfer. The load_image function transforms the image and loads it in the form of normalized Tensors.\n\n","metadata":{}},{"cell_type":"code","source":"import os\nimport random\nimport torch\nfrom PIL import Image\nfrom torchvision import transforms\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ndef load_image(img_path, max_size=128, shape=None):\n    ''' Load in and transform an image, making sure the image\n       is <= 400 pixels in the x-y dims.'''\n    if \"http\" in img_path:\n        response = requests.get(img_path)\n        image = Image.open(BytesIO(response.content)).convert('RGB')\n    else:\n        image = Image.open(img_path).convert('RGB')\n    \n    # large images will slow down processing\n    if max(image.size) > max_size:\n        size = max_size\n    else:\n        size = max(image.size)\n    \n    if shape is not None:\n        size = shape\n        \n    in_transform = transforms.Compose([\n                        transforms.Resize(size),\n                        transforms.ToTensor(),\n                        transforms.Normalize((0.485, 0.456, 0.406), \n                                             (0.229, 0.224, 0.225))])\n\n    # discard the transparent, alpha channel (that's the :3) and add the batch dimension\n    image = in_transform(image)[:3,:,:].unsqueeze(0)\n    \n    return image\n\n# Function to get all image files recursively from a directory\ndef get_all_image_files(directory):\n    image_files = []\n    for root, _, files in os.walk(directory):\n        for file in files:\n            if file.endswith('.jpg'):\n                image_files.append(os.path.join(root, file))\n    return image_files\n\n# Paths to the content and style image directories\ncontent_path = '/kaggle/input/images-for-style-transfer/Data/TestCases/'\nstyle_path = '/kaggle/input/wikiart/'\n\n# Get list of all image files in the directories\ncontent_files = get_all_image_files(content_path)\nstyle_files = get_all_image_files(style_path)\n\n# Select random content and style images\ncontent_image_path = random.choice(content_files)\nstyle_image_path = random.choice(style_files)\n\n# Load content and style images\ncontent = load_image(content_image_path).to(device)\nstyle = load_image(style_image_path).to(device)\n\nprint(f\"Content image path: {content_image_path}\")\nprint(f\"Style image path: {style_image_path}\")\n","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:03:10.7821Z","iopub.execute_input":"2024-08-05T16:03:10.782615Z","iopub.status.idle":"2024-08-05T16:05:36.671464Z","shell.execute_reply.started":"2024-08-05T16:03:10.782578Z","shell.execute_reply":"2024-08-05T16:05:36.670691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Load the content image and style image.","metadata":{}},{"cell_type":"code","source":"# helper function for un-normalizing an image \n# and converting it from a Tensor image to a NumPy image for display\ndef im_convert(tensor):\n    \"\"\" Display a tensor as an image. \"\"\"\n    \n    image = tensor.to(\"cpu\").clone().detach()\n    image = image.numpy().squeeze()\n    image = image.transpose(1,2,0)\n    image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))\n    image = image.clip(0, 1)\n\n    return image","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:36.67251Z","iopub.execute_input":"2024-08-05T16:05:36.672724Z","iopub.status.idle":"2024-08-05T16:05:36.679106Z","shell.execute_reply.started":"2024-08-05T16:05:36.672699Z","shell.execute_reply":"2024-08-05T16:05:36.678263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display the images\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\n# content and style ims side-by-side\nax1.imshow(im_convert(content))\nax2.imshow(im_convert(style))","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:36.680108Z","iopub.execute_input":"2024-08-05T16:05:36.680309Z","iopub.status.idle":"2024-08-05T16:05:37.241546Z","shell.execute_reply.started":"2024-08-05T16:05:36.680281Z","shell.execute_reply":"2024-08-05T16:05:37.240871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_features(image, model, layers=None):\n    \"\"\" Run an image forward through a model and get the features for \n        a set of layers. Default layers are for VGGNet matching Gatys et al (2016)\n    \"\"\"\n    \n    if layers is None:\n        layers = {'0': 'conv1_1',\n                  '5': 'conv2_1', \n                  '10': 'conv3_1', \n                  '19': 'conv4_1',\n                  '21': 'conv4_2',  ## content representation\n                  '28': 'conv5_1'}\n        \n    features = {}\n    x = image\n    # model._modules is a dictionary holding each module in the model\n    for name, layer in model._modules.items():\n        x = layer(x)\n        if name in layers:\n            features[layers[name]] = x\n            \n    return features","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:37.242567Z","iopub.execute_input":"2024-08-05T16:05:37.242798Z","iopub.status.idle":"2024-08-05T16:05:37.249113Z","shell.execute_reply.started":"2024-08-05T16:05:37.242759Z","shell.execute_reply":"2024-08-05T16:05:37.248349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------------------------------------------------\n# 3. Gram Matrix\n\n![](https://miro.medium.com/max/1400/1*VAQs1KSfbysnloPah_fHGQ.gif)\n\nPicture Credit: https://miro.medium.com\n\n\n\n\nhttps://en.wikipedia.org/wiki/Gram_matrix\n","metadata":{}},{"cell_type":"code","source":"def gram_matrix(tensor):\n    \"\"\" Calculate the Gram Matrix of a given tensor         \n    \"\"\"\n    \n    # get the batch_size, depth, height, and width of the Tensor\n    _, d, h, w = tensor.size()\n    \n    # reshape so we're multiplying the features for each channel\n    tensor = tensor.view(d, h * w)\n    \n    # calculate the gram matrix\n    gram = torch.mm(tensor, tensor.t())\n    \n    return gram ","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:37.250118Z","iopub.execute_input":"2024-08-05T16:05:37.25033Z","iopub.status.idle":"2024-08-05T16:05:37.262928Z","shell.execute_reply.started":"2024-08-05T16:05:37.2503Z","shell.execute_reply":"2024-08-05T16:05:37.262307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The function that extracts the features of a given convolutional layer and computes the Gram Matrix is made. Putting it all together, we extract the features from the image and compute the Gram Matrix for each layer from the style representation.","metadata":{}},{"cell_type":"code","source":"# get content and style features only once before training\ncontent_features = get_features(content, vgg)\nstyle_features = get_features(style, vgg)\n\n# calculate the gram matrices for each layer of our style representation\nstyle_grams = {layer: gram_matrix(style_features[layer]) for layer in style_features}\n\n# create a third \"target\" image and prep it for change\n# it is a good idea to start off with the target as a copy of our *content* image\n# then iteratively change its style\ntarget = content.clone().requires_grad_(True).to(device)","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:37.263696Z","iopub.execute_input":"2024-08-05T16:05:37.263886Z","iopub.status.idle":"2024-08-05T16:05:37.371833Z","shell.execute_reply.started":"2024-08-05T16:05:37.263865Z","shell.execute_reply":"2024-08-05T16:05:37.371214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"xác định trọng số và các lớp","metadata":{}},{"cell_type":"code","source":"# weights for each style layer \n# weighting earlier layers more will result in *larger* style artifacts\n# notice we are excluding `conv4_2` our content representation\nstyle_weights = {'conv1_1': 1,\n                 'conv2_1': 0.75,\n                 'conv3_1': 0.2,\n                 'conv4_1': 0.2,\n                 'conv5_1': 0.2}\n\ncontent_weight = 1  # alpha\nstyle_weight = 1e3  # beta","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:37.372753Z","iopub.execute_input":"2024-08-05T16:05:37.372997Z","iopub.status.idle":"2024-08-05T16:05:37.377575Z","shell.execute_reply.started":"2024-08-05T16:05:37.372972Z","shell.execute_reply":"2024-08-05T16:05:37.376864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"tính loss","metadata":{}},{"cell_type":"code","source":"# for displaying the target image, intermittently\nshow_every = 500\n\n# iteration hyperparameters\noptimizer = optim.Adam([target], lr=0.003)\nsteps = 5001  # decide how many iterations to update your image (5000)\n\nfor ii in range(1, steps+1):\n    \n    # get the features from your target image\n    target_features = get_features(target, vgg)\n    \n    # the content loss\n    content_loss = torch.mean((target_features['conv4_2'] - content_features['conv4_2'])**2)\n    \n    # the style loss\n    # initialize the style loss to 0\n    style_loss = 0\n    # then add to it for each layer's gram matrix loss\n    for layer in style_weights:\n        # get the \"target\" style representation for the layer\n        target_feature = target_features[layer]\n        target_gram = gram_matrix(target_feature)\n        _, d, h, w = target_feature.shape\n        # get the \"style\" style representation\n        style_gram = style_grams[layer]\n        # the style loss for one layer, weighted appropriately\n        layer_style_loss = style_weights[layer] * torch.mean((target_gram - style_gram)**2)\n        # add to the style loss\n        style_loss += layer_style_loss / (d * h * w)\n        \n    # calculate the *total* loss\n    total_loss = content_weight * content_loss + style_weight * style_loss\n    \n    # update your target image\n    optimizer.zero_grad()\n    total_loss.backward()\n    optimizer.step()\n    \n    # display intermediate images and print the loss\n    if  ii % show_every == 0:\n        print('Total loss: ', total_loss.item())\n        plt.imshow(im_convert(target))\n        plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-08-05T16:05:37.380857Z","iopub.execute_input":"2024-08-05T16:05:37.381066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"-----------------------------------------------------------------\n# 6. kết quả","metadata":{}},{"cell_type":"code","source":"# display content and final, target image\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\nax1.imshow(im_convert(content))\nax2.imshow(im_convert(target))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display style and final, target image\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\nax1.imshow(im_convert(style))\nax2.imshow(im_convert(target))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.optim as optim\nimport torch.nn.functional as F\nimport matplotlib.pyplot as plt\n\n# Tính MSE giữa hình ảnh kết quả và hình ảnh gốc\ndef mse(image1, image2):\n    return F.mse_loss(image1, image2)\n\nmse_loss = mse(target, content)\nprint('MSE between target and content image:', mse_loss.item())\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**RESNET50**","metadata":{}},{"cell_type":"markdown","source":"Load model","metadata":{}},{"cell_type":"code","source":"\n# get the \"features\" portion of ResNet50 (we will not need the \"classifier\" portion)\nresnet = models.resnet50(pretrained=True)\nresnet_features = nn.Sequential(*list(resnet.children())[:-2])\n\n# freeze all ResNet parameters since we're only optimizing the target image\nfor param in resnet_features.parameters():\n    param.requires_grad_(False)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# move the model to GPU, if available\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nresnet.to(device)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Get feature","metadata":{}},{"cell_type":"code","source":"content_layers = ['conv1'] \n# Style layers we are interested in\nstyle_layers = [\n    'layer1.1.bn2',  # bn2 layer from the second Bottleneck in layer1\n    'layer2.1.bn3',  # bn3 layer from the second Bottleneck in layer2\n    'layer3.1.conv3', # conv3 layer from the second Bottleneck in layer3\n    'layer4.1.bn2'   # bn2 layer from the second Bottleneck in layer4\n]\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Gram Matrix","metadata":{}},{"cell_type":"code","source":"def gram_matrix(tensor):\n    _, d, h, w = tensor.size()\n    tensor = tensor.view(d, h * w)\n    gram = torch.mm(tensor, tensor.t())\n    return gram\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# get content and style features only once before training\ncontent_features = get_features(content, resnet_features)\nstyle_features = get_features(style, resnet_features)\n\n# calculate the gram matrices for each layer of our style representation\nstyle_grams = {layer: gram_matrix(style_features[layer]) for layer in style_features}\n\n# create a third \"target\" image and prep it for change\ntarget = content.clone().requires_grad_(True).to(device)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Define loss and weight","metadata":{}},{"cell_type":"code","source":"# Define the layers to be used for style and content extraction\nstyle_weights = {\n    'layer1.1.bn2': 0.75,  # bn2 layer from the second Bottleneck in layer1\n    'layer2.1.bn3': 0.2,   # bn3 layer from the second Bottleneck in layer2\n    'layer3.1.conv3': 0.2, # conv3 layer from the second Bottleneck in layer3\n    'layer4.1.bn2': 0.2    # bn2 layer from the second Bottleneck in layer4\n}\n\ncontent_layer = 'conv1'  # Using the initial convolutional layer\ncontent_weight = 1  # alpha\nstyle_weight = 1e3  # beta\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. Update Target and Calculate Losses\n\n**Content Loss**\n\nThe content loss is calculated as the MSE between the target and the content feature in the 'conv4_2' layer.\n\n**Style Loss**\n\nThe style loss is the loss between the target image and the style image. That is, it refers to the difference between the gram matrix of the style image and the gram matrix of the target image. Loss is calculated using MSE\n\n**Total Loss**\n\nFinally, the total loss is calculated by summing the style and content losses and weighting them with the specified alpha and beta.","metadata":{}},{"cell_type":"code","source":"import torch.optim as optim\n\n\nshow_every = 500\n\noptimizer = optim.Adam([target], lr=0.003)\nsteps = 5001\n\nfor ii in range(1, steps+1):\n\n    # get the features from your target image\n    target_features = get_features(target, resnet_features)\n\n    # the content loss\n    content_loss = torch.mean((target_features[content_layer] - content_features[content_layer])**2)\n\n    # the style loss\n    style_loss = 0\n    for layer in style_weights:\n        target_feature = target_features[layer]\n        target_gram = gram_matrix(target_feature)\n        _, d, h, w = target_feature.shape\n        style_gram = style_grams[layer]\n        layer_style_loss = style_weights[layer] * torch.mean((target_gram - style_gram)**2)\n        style_loss += layer_style_loss / (d * h * w)\n\n    total_loss = content_weight * content_loss + style_weight * style_loss\n\n    optimizer.zero_grad()\n    total_loss.backward()\n    optimizer.step()\n\n    if ii % show_every == 0:\n        print('Total loss: ', total_loss.item())\n        plt.imshow(im_convert(target))\n        plt.show()\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display content and final, target image\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\nax1.imshow(im_convert(content))\nax2.imshow(im_convert(target))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display style and final, target image\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\nax1.imshow(im_convert(style))\nax2.imshow(im_convert(target))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Tính MSE giữa hình ảnh kết quả và hình ảnh gốc\ndef mse(image1, image2):\n    return F.mse_loss(image1, image2)\n\nmse_loss = mse(target, content)\nprint('MSE between target and content image:', mse_loss.item())\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"test cho chính bản thân","metadata":{}},{"cell_type":"code","source":"# Load content and style images\ncontent = load_image('/kaggle/input/test2minhnhat/IMG_0021.jpg').to(device)\nstyle = load_image('/kaggle/input/wikiart/Art_Nouveau_Modern/a.y.-jackson_first-snow-algoma-country-1920.jpg').to(device)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# helper function for un-normalizing an image \n# and converting it from a Tensor image to a NumPy image for display\ndef im_convert(tensor):\n    \"\"\" Display a tensor as an image. \"\"\"\n    \n    image = tensor.to(\"cpu\").clone().detach()\n    image = image.numpy().squeeze()\n    image = image.transpose(1,2,0)\n    image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))\n    image = image.clip(0, 1)\n\n    return image","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display the images\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\n# content and style ims side-by-side\nax1.imshow(im_convert(content))\nax2.imshow(im_convert(style))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_features(image, model, layers=None):\n    \"\"\" Run an image forward through a model and get the features for \n        a set of layers. Default layers are for VGGNet matching Gatys et al (2016)\n    \"\"\"\n    \n    if layers is None:\n        layers = {'0': 'conv1_1',\n                  '5': 'conv2_1', \n                  '10': 'conv3_1', \n                  '19': 'conv4_1',\n                  '21': 'conv4_2',  ## content representation\n                  '28': 'conv5_1'}\n        \n    features = {}\n    x = image\n    # model._modules is a dictionary holding each module in the model\n    for name, layer in model._modules.items():\n        x = layer(x)\n        if name in layers:\n            features[layers[name]] = x\n            \n    return features","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def gram_matrix(tensor):\n    \"\"\" Calculate the Gram Matrix of a given tensor         \n    \"\"\"\n    \n    # get the batch_size, depth, height, and width of the Tensor\n    _, d, h, w = tensor.size()\n    \n    # reshape so we're multiplying the features for each channel\n    tensor = tensor.view(d, h * w)\n    \n    # calculate the gram matrix\n    gram = torch.mm(tensor, tensor.t())\n    \n    return gram ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# get content and style features only once before training\ncontent_features = get_features(content, vgg)\nstyle_features = get_features(style, vgg)\n\n# calculate the gram matrices for each layer of our style representation\nstyle_grams = {layer: gram_matrix(style_features[layer]) for layer in style_features}\n\n# create a third \"target\" image and prep it for change\n# it is a good idea to start off with the target as a copy of our *content* image\n# then iteratively change its style\ntarget = content.clone().requires_grad_(True).to(device)\n# weights for each style layer \n# weighting earlier layers more will result in *larger* style artifacts\n# notice we are excluding `conv4_2` our content representation\nstyle_weights = {'conv1_1': 1,\n                 'conv2_1': 0.75,\n                 'conv3_1': 0.2,\n                 'conv4_1': 0.2,\n                 'conv5_1': 0.2}\n\ncontent_weight = 1  # alpha\nstyle_weight = 1e3  # beta","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for displaying the target image, intermittently\nshow_every = 500\n\n# iteration hyperparameters\noptimizer = optim.Adam([target], lr=0.003)\nsteps = 5001  # decide how many iterations to update your image (5000)\n\nfor ii in range(1, steps+1):\n    \n    # get the features from your target image\n    target_features = get_features(target, vgg)\n    \n    # the content loss\n    content_loss = torch.mean((target_features['conv4_2'] - content_features['conv4_2'])**2)\n    \n    # the style loss\n    # initialize the style loss to 0\n    style_loss = 0\n    # then add to it for each layer's gram matrix loss\n    for layer in style_weights:\n        # get the \"target\" style representation for the layer\n        target_feature = target_features[layer]\n        target_gram = gram_matrix(target_feature)\n        _, d, h, w = target_feature.shape\n        # get the \"style\" style representation\n        style_gram = style_grams[layer]\n        # the style loss for one layer, weighted appropriately\n        layer_style_loss = style_weights[layer] * torch.mean((target_gram - style_gram)**2)\n        # add to the style loss\n        style_loss += layer_style_loss / (d * h * w)\n        \n    # calculate the *total* loss\n    total_loss = content_weight * content_loss + style_weight * style_loss\n    \n    # update your target image\n    optimizer.zero_grad()\n    total_loss.backward()\n    optimizer.step()\n    \n    # display intermediate images and print the loss\n    if  ii % show_every == 0:\n        print('Total loss: ', total_loss.item())\n        plt.imshow(im_convert(target))\n        plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display content and final, target image\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\nax1.imshow(im_convert(content))\nax2.imshow(im_convert(target))","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}