{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# NST is one of the most well-known approaches based on convolutional neural networks (CNNs),\n# originally proposed by Gatis et al. The model attempts to match the content structure of one\n# image with the style of another. NST uses pre-trained CNNs such as VGG19.\n# It uses network layers to extract texture and color features of style as well as content structure\n# and combines them.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-11-14T08:56:35.542137Z","iopub.execute_input":"2024-11-14T08:56:35.542465Z","iopub.status.idle":"2024-11-14T08:56:35.547606Z","shell.execute_reply.started":"2024-11-14T08:56:35.542424Z","shell.execute_reply":"2024-11-14T08:56:35.546564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision import models\n\n\n# For VGG19 \"classifier\" we won't need\n# We are only optimizing the target image, so other VGG parameters will remain constant\nvgg = models.vgg19(pretrained=True).features\n\nfor param in vgg.parameters():\n    param.requires_grad_(False)","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:35.549196Z","iopub.execute_input":"2024-11-14T08:56:35.549912Z","iopub.status.idle":"2024-11-14T08:56:48.395974Z","shell.execute_reply.started":"2024-11-14T08:56:35.549869Z","shell.execute_reply":"2024-11-14T08:56:48.394919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\nimport torch\n\n\n# To run a convolutional network, you will need a GPU.\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nvgg.to(device)","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:48.397604Z","iopub.execute_input":"2024-11-14T08:56:48.398013Z","iopub.status.idle":"2024-11-14T08:56:48.721063Z","shell.execute_reply.started":"2024-11-14T08:56:48.397981Z","shell.execute_reply":"2024-11-14T08:56:48.720169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\nfrom torchvision import transforms\n\n\n# Loaded Image Normalization Function\ndef load_image(img_path, max_size=128, shape=None):\n    image = Image.open(img_path).convert(\"RGB\")\n    \n    # Limiting the maximum image size\n    if max(image.size) > max_size:\n        size = max_size\n    else:\n        size = max(image.size)\n    \n    # Resize image if specific shape is specified\n    if shape is not None:\n        size = shape\n\n    in_transform = transforms.Compose([\n        transforms.Resize((size, size)),         \n        transforms.ToTensor(),                   \n        transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))  # VGG normalization\n    ])\n\n    image = in_transform(image)[:3, :, :].unsqueeze(0)\n    \n    return image","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:48.722399Z","iopub.execute_input":"2024-11-14T08:56:48.722784Z","iopub.status.idle":"2024-11-14T08:56:48.730027Z","shell.execute_reply.started":"2024-11-14T08:56:48.722748Z","shell.execute_reply":"2024-11-14T08:56:48.729190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo = load_image('/kaggle/input/gan-getting-started/photo_jpg/00068bc07f.jpg').to(device)\nstyle = load_image('/kaggle/input/gan-getting-started/monet_jpg/000c1e3bff.jpg').to(device)","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:48.732261Z","iopub.execute_input":"2024-11-14T08:56:48.732589Z","iopub.status.idle":"2024-11-14T08:56:48.887354Z","shell.execute_reply.started":"2024-11-14T08:56:48.732557Z","shell.execute_reply":"2024-11-14T08:56:48.886355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image display function\ndef imshow(tensor, title=None):\n    # Do inverse transformations\n    image = tensor.clone().detach()  \n    image = image.squeeze(0) \n    image = image.permute(1, 2, 0)  \n    image = image.cpu().numpy()  \n    \n    mean = np.array([0.485, 0.456, 0.406])\n    std = np.array([0.229, 0.224, 0.225])\n    image = std * image + mean \n    image = np.clip(image, 0, 1) \n    \n    return image","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:48.888963Z","iopub.execute_input":"2024-11-14T08:56:48.889367Z","iopub.status.idle":"2024-11-14T08:56:48.895376Z","shell.execute_reply.started":"2024-11-14T08:56:48.889293Z","shell.execute_reply":"2024-11-14T08:56:48.894487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 10))\n\nax1.imshow(imshow(photo))\nax2.imshow(imshow(style))","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:48.896833Z","iopub.execute_input":"2024-11-14T08:56:48.897135Z","iopub.status.idle":"2024-11-14T08:56:49.599209Z","shell.execute_reply.started":"2024-11-14T08:56:48.897104Z","shell.execute_reply":"2024-11-14T08:56:49.598276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extracts image features from specified model layers\ndef get_features(image, model, layers=None):\n    #If layers are not specified, use standard VGG19 layers\n    if layers is None:\n        layers = {\n            '0': 'conv1_1',   \n            '5': 'conv2_1',   \n            '10': 'conv3_1', \n            '19': 'conv4_1',  # Fourth convolutional layer (for style)\n            '21': 'conv4_2',  # Fourth convolutional layer (for content)\n            '28': 'conv5_1'   \n        }\n\n    features = {}\n    x = image\n\n    # We go through the layers of the model and save the activations for the specified layers\n    for name, layer in model._modules.items():\n        x = layer(x)\n        if name in layers:\n            features[layers[name]] = x  # Save activations from specified layers\n\n    return features","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:49.600497Z","iopub.execute_input":"2024-11-14T08:56:49.600822Z","iopub.status.idle":"2024-11-14T08:56:49.607402Z","shell.execute_reply.started":"2024-11-14T08:56:49.600789Z","shell.execute_reply":"2024-11-14T08:56:49.606563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The gram_matrix function is used to calculate the Gram matrix,\n# which helps to determine the style of an image. This matrix represents pairwise\n# correlations between activation filters and is used to calculate the style loss:\n# the closer the Gram matrix of the generated image is to the reference (style image),\n# the better the style is conveyed.\n\ndef gram_matrix(tensor):\n    _, c, h, w = tensor.size()\n    features = tensor.view(c, h * w)\n    gram = torch.mm(features, features.t())\n    \n    # Normalization by number of elements\n    return gram / (c * h * w)","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:49.608888Z","iopub.execute_input":"2024-11-14T08:56:49.609557Z","iopub.status.idle":"2024-11-14T08:56:49.619511Z","shell.execute_reply.started":"2024-11-14T08:56:49.609510Z","shell.execute_reply":"2024-11-14T08:56:49.618687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Getting content and style features from content and style images\ncontent_features = get_features(photo, vgg)\nstyle_features = get_features(style, vgg)\n\n# Calculate the Gram matrix for each layer\nstyle_grams = {}\nfor layer in style_features:\n    style_grams[layer] = gram_matrix(style_features[layer])\n    \n","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:49.620788Z","iopub.execute_input":"2024-11-14T08:56:49.621103Z","iopub.status.idle":"2024-11-14T08:56:50.710161Z","shell.execute_reply.started":"2024-11-14T08:56:49.621071Z","shell.execute_reply":"2024-11-14T08:56:50.709217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.optim as optim\n\n\n# Setting parameters for style and content\nstyle_weight = 1e6  \ncontent_weight = 1e0 \nstyle_layers = ['conv1_1', 'conv2_1', 'conv3_1', 'conv4_1', 'conv5_1']\n\n# Create a copy of the content image that will be optimized\ntarget = photo.clone().requires_grad_(True).to(device)\n\n# Optimizer for image pixel update\noptimizer = optim.Adam([target], lr=0.003)\n\nnum_steps = 5000\n\nfor step in range(1, num_steps+1):\n    target_features = get_features(target, vgg)\n    content_loss = torch.mean((target_features['conv4_2'] - content_features['conv4_2']) ** 2)\n    \n    style_loss = 0\n    for layer in style_layers:\n        target_gram = gram_matrix(target_features[layer])\n        style_gram = style_grams[layer]\n        layer_style_loss = torch.mean((target_gram - style_gram) ** 2)\n        style_loss += layer_style_loss / len(style_layers)\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 step % 100 == 0:\n        print(f\"Step {step}, Total Loss: {total_loss.item()}\")\n\nplt.figure(figsize=(10, 10))\nplt.imshow(imshow(target))\nplt.axis(\"off\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:56:50.713436Z","iopub.execute_input":"2024-11-14T08:56:50.714087Z","iopub.status.idle":"2024-11-14T08:57:28.715236Z","shell.execute_reply.started":"2024-11-14T08:56:50.714038Z","shell.execute_reply":"2024-11-14T08:57:28.714177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 10))\nax1.imshow(imshow(photo))\nax2.imshow(imshow(target))","metadata":{"execution":{"iopub.status.busy":"2024-11-14T08:57:28.716647Z","iopub.execute_input":"2024-11-14T08:57:28.717074Z","iopub.status.idle":"2024-11-14T08:57:29.320710Z","shell.execute_reply.started":"2024-11-14T08:57:28.717016Z","shell.execute_reply":"2024-11-14T08:57:29.319839Z"},"trusted":true},"execution_count":null,"outputs":[]}]}