{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","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":30528,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The neural style transfer part","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\n\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\nimport torchvision.transforms as transforms\nimport torchvision.models as models\n\nimport copy\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ntorch.set_default_device(device)\n\n# desired size of the output image\nimsize = 512 if torch.cuda.is_available() else 128  # use small size if no GPU\n\nloader = transforms.Compose([\n    transforms.Resize(imsize),  # scale imported image\n    transforms.ToTensor()])  # transform it into a torch tensor\n\n\ndef image_loader(image_name):\n    image = Image.open(image_name)\n    # fake batch dimension required to fit network's input dimensions\n    image = loader(image).unsqueeze(0)\n    return image.to(device, torch.float)\n\n\n# style_img = image_loader(\"./data/images/neural-style/picasso.jpg\")\n# content_img = image_loader(\"./data/images/neural-style/dancing.jpg\")\n\n# assert style_img.size() == content_img.size(), \\\n#     \"we need to import style and content images of the same size\"\n\n\nunloader = transforms.ToPILImage()  # reconvert into PIL image\n\n\n# plt.figure()\n# imshow(style_img, title='Style Image')\n\n# plt.figure()\n# imshow(content_img, title='Content Image')\n\nclass ContentLoss(nn.Module):\n\n    def __init__(self, target,):\n        super(ContentLoss, self).__init__()\n        # we 'detach' the target content from the tree used\n        # to dynamically compute the gradient: this is a stated value,\n        # not a variable. Otherwise the forward method of the criterion\n        # will throw an error.\n        self.target = target.detach()\n\n    def forward(self, input):\n        self.loss = F.mse_loss(input, self.target)\n        return input\n    \n\ndef gram_matrix(input):\n    a, b, c, d = input.size()  # a=batch size(=1)\n    # b=number of feature maps\n    # (c,d)=dimensions of a f. map (N=c*d)\n\n    features = input.view(a * b, c * d)  # resize F_XL into \\hat F_XL\n\n    G = torch.mm(features, features.t())  # compute the gram product\n\n    # we 'normalize' the values of the gram matrix\n    # by dividing by the number of element in each feature maps.\n    return G.div(a * b * c * d)\n\nclass StyleLoss(nn.Module):\n\n    def __init__(self, target_feature):\n        super(StyleLoss, self).__init__()\n        self.target = gram_matrix(target_feature).detach()\n\n    def forward(self, input):\n        G = gram_matrix(input)\n        self.loss = F.mse_loss(G, self.target)\n        return input\n    \n\ncnn = models.vgg19(pretrained=True).features.eval()\n\n\n# cnn_normalization_mean = torch.tensor([0.485, 0.456, 0.406])\n# cnn_normalization_std = torch.tensor([0.229, 0.224, 0.225])\n\n# create a module to normalize input image so we can easily put it in a\n# ``nn.Sequential``\nclass Normalization(nn.Module):\n    def __init__(self, mean, std):\n        super(Normalization, self).__init__()\n        # .view the mean and std to make them [C x 1 x 1] so that they can\n        # directly work with image Tensor of shape [B x C x H x W].\n        # B is batch size. C is number of channels. H is height and W is width.\n        self.mean = torch.tensor(mean).view(-1, 1, 1)\n        self.std = torch.tensor(std).view(-1, 1, 1)\n\n    def forward(self, img):\n        # normalize ``img``\n        return (img - self.mean) / self.std\n    \n# desired depth layers to compute style/content losses :\ncontent_layers_default = ['conv_4']\nstyle_layers_default = ['conv_1', 'conv_2', 'conv_3', 'conv_4', 'conv_5']\n\ndef get_style_model_and_losses(cnn, normalization_mean, normalization_std,\n                               style_img, content_img,\n                               content_layers=content_layers_default,\n                               style_layers=style_layers_default):\n    # normalization module\n    normalization = Normalization(normalization_mean, normalization_std)\n\n    # just in order to have an iterable access to or list of content/style\n    # losses\n    content_losses = []\n    style_losses = []\n\n    # assuming that ``cnn`` is a ``nn.Sequential``, so we make a new ``nn.Sequential``\n    # to put in modules that are supposed to be activated sequentially\n    model = nn.Sequential(normalization)\n\n    i = 0  # increment every time we see a conv\n    for layer in cnn.children():\n        if isinstance(layer, nn.Conv2d):\n            i += 1\n            name = 'conv_{}'.format(i)\n        elif isinstance(layer, nn.ReLU):\n            name = 'relu_{}'.format(i)\n            # The in-place version doesn't play very nicely with the ``ContentLoss``\n            # and ``StyleLoss`` we insert below. So we replace with out-of-place\n            # ones here.\n            layer = nn.ReLU(inplace=False)\n        elif isinstance(layer, nn.MaxPool2d):\n            name = 'pool_{}'.format(i)\n        elif isinstance(layer, nn.BatchNorm2d):\n            name = 'bn_{}'.format(i)\n        else:\n            raise RuntimeError('Unrecognized layer: {}'.format(layer.__class__.__name__))\n\n        model.add_module(name, layer)\n\n        if name in content_layers:\n            # add content loss:\n            target = model(content_img).detach()\n            content_loss = ContentLoss(target)\n            model.add_module(\"content_loss_{}\".format(i), content_loss)\n            content_losses.append(content_loss)\n\n        if name in style_layers:\n            # add style loss:\n            target_feature = model(style_img).detach()\n            style_loss = StyleLoss(target_feature)\n            model.add_module(\"style_loss_{}\".format(i), style_loss)\n            style_losses.append(style_loss)\n\n    # now we trim off the layers after the last content and style losses\n    for i in range(len(model) - 1, -1, -1):\n        if isinstance(model[i], ContentLoss) or isinstance(model[i], StyleLoss):\n            break\n\n    model = model[:(i + 1)]\n\n    return model, style_losses, content_losses\n\n\n\ndef get_input_optimizer(input_img):\n    # this line to show that input is a parameter that requires a gradient\n    optimizer = optim.LBFGS([input_img])\n    return optimizer\n\n\ndef run_style_transfer(cnn, normalization_mean, normalization_std,\n                       content_img, style_img, input_img, num_steps=300,\n                       style_weight=1000000, content_weight=1):\n    \"\"\"Run the style transfer.\"\"\"\n    print('Building the style transfer model..')\n    model, style_losses, content_losses = get_style_model_and_losses(cnn,\n        normalization_mean, normalization_std, style_img, content_img)\n\n    # We want to optimize the input and not the model parameters so we\n    # update all the requires_grad fields accordingly\n    input_img.requires_grad_(True)\n    # We also put the model in evaluation mode, so that specific layers \n    # such as dropout or batch normalization layers behave correctly. \n    model.eval()\n    model.requires_grad_(False)\n\n    optimizer = get_input_optimizer(input_img)\n\n    print('Optimizing..')\n    run = [0]\n    while run[0] <= num_steps:\n\n        def closure():\n            # correct the values of updated input image\n            with torch.no_grad():\n                input_img.clamp_(0, 1)\n\n            optimizer.zero_grad()\n            model(input_img)\n            style_score = 0\n            content_score = 0\n\n            for sl in style_losses:\n                style_score += sl.loss\n            for cl in content_losses:\n                content_score += cl.loss\n\n            style_score *= style_weight\n            content_score *= content_weight\n\n            loss = style_score + content_score\n            loss.backward()\n\n            run[0] += 1\n#             if run[0] % 50 == 0:\n#                 print(\"run {}:\".format(run))\n#                 print('Style Loss : {:4f} Content Loss: {:4f}'.format(\n#                     style_score.item(), content_score.item()))\n#                 print()\n\n            return style_score + content_score\n\n        optimizer.step(closure)\n\n    # a last correction...\n    with torch.no_grad():\n        input_img.clamp_(0, 1)\n\n    return input_img","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unloader = transforms.ToPILImage()  # reconvert into PIL image\n\ndef save_img(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    h,w = 256,256\n    image = image.resize((w,h))\n    image = image.save(title)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"the eval generation part","metadata":{}},{"cell_type":"code","source":"cnn_normalization_mean = torch.tensor([0.485, 0.456, 0.406])\ncnn_normalization_std = torch.tensor([0.229, 0.224, 0.225])\ncontent_dir = \"/kaggle/input/gan-getting-started/photo_jpg\"\nstyle_dir = \"/kaggle/input/gan-getting-started/monet_jpg\"\n\nfiles_content = os.listdir(content_dir)\nfiles_style = os.listdir(style_dir)\nnum_imgs = 8000\n\npath_out = '/kaggle/working/images'\n\ntry:\n    os.mkdir(path_out)\nexcept OSError as er:\n    print(er)\nimport random \n\nwhile(num_imgs > 0):\n    idx_content = random.randint(0,int(len(files_content)-1))\n    idx_style = random.randint(0,int(len(files_style)-1))\n    content_img = image_loader(os.path.join(content_dir,files_content[idx_content]))\n    style_img = image_loader(os.path.join(style_dir,files_style[idx_style]))\n    input_img = content_img.clone()\n    output = run_style_transfer(cnn, cnn_normalization_mean, cnn_normalization_std,content_img, style_img, input_img,num_steps=400)\n    save_img(output,os.path.join(path_out,str(num_imgs)+\".jpg\"))\n    num_imgs -= 1\n    print(\"left :\" + str(num_imgs))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path_imgs = \"/kaggle/working/images\"\npath_to_zip = \"/kaggle/working\"\n\nfrom zipfile import ZipFile\n\nwith ZipFile('/kaggle/working/images.zip', 'w') as zip_object:\n    for _,f in enumerate(os.listdir(path_imgs)):\n         zip_object.write(os.path.join(path_imgs,f),f)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}