{"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":"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","execution":{"iopub.status.busy":"2022-06-13T05:01:09.306489Z","iopub.execute_input":"2022-06-13T05:01:09.307033Z","iopub.status.idle":"2022-06-13T05:01:16.956984Z","shell.execute_reply.started":"2022-06-13T05:01:09.306965Z","shell.execute_reply":"2022-06-13T05:01:16.95567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\n\nimport numpy as np\nimport pickle as pkl\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.axes_grid1 import ImageGrid","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:01:16.960072Z","iopub.execute_input":"2022-06-13T05:01:16.961036Z","iopub.status.idle":"2022-06-13T05:01:19.02613Z","shell.execute_reply.started":"2022-06-13T05:01:16.960998Z","shell.execute_reply":"2022-06-13T05:01:19.025213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mean_ = 0.5\nstd_ = 0.5\nclass Dataset(torch.utils.data.Dataset):\n\n    def __init__(self, img_dir):\n        img_dir = BASE_DATASET_PATH + \"/\" + img_dir + \"/\"\n        \n        path_list = os.listdir(img_dir)\n        abspath = os.path.abspath(img_dir) \n        \n        self.img_dir = img_dir\n        self.img_list = [os.path.join(abspath, path) for path in path_list]\n\n        self.transform = transforms.Compose([\n            transforms.Resize(IMG_SIZE),\n            transforms.ToTensor(),\n            transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), # normalize image between -1 and 1\n        ])\n\n\n    def __len__(self):\n        return len(self.img_list)\n\n\n    def __getitem__(self, idx):\n        path = self.img_list[idx]\n        img = Image.open(path).convert('RGB')\n\n        img_tensor = self.transform(img)\n        return img_tensor\ndef reverse_normalize(image, mean_=mean_, std_=std_):\n    if torch.is_tensor(image):\n        image = image.detach().numpy()\n    un_normalized_img = image * std_ + mean_\n    un_normalized_img = un_normalized_img * 255\n    return np.uint8(un_normalized_img)\n","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:07:07.431674Z","iopub.execute_input":"2022-06-13T05:07:07.43226Z","iopub.status.idle":"2022-06-13T05:07:07.44234Z","shell.execute_reply.started":"2022-06-13T05:07:07.432224Z","shell.execute_reply":"2022-06-13T05:07:07.441557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Discriminator(nn.Module):\n\n    def __init__(self,conv_dim=32):\n        super(Discriminator, self).__init__()\n\n        self.main = nn.Sequential(\n            nn.Conv2d(3, conv_dim, 4, stride=2, padding=1),\n            nn.SELU(inplace=True),\n\n            nn.Conv2d(conv_dim, conv_dim*2, 4, stride=2, padding=1),\n            nn.InstanceNorm2d(conv_dim*2),\n            nn.SELU(inplace=True),\n\n            nn.Conv2d(conv_dim*2, conv_dim*4, 4, stride=2, padding=1),\n            nn.InstanceNorm2d(conv_dim*4),\n            nn.SELU(inplace=True),\n\n            nn.Conv2d(conv_dim*4, conv_dim*8, 4, padding=1),\n            nn.InstanceNorm2d(conv_dim*8),\n            nn.SELU(inplace=True),\n\n            nn.Conv2d(conv_dim*8, 1, 4, padding=1),\n        )\n\n    def forward(self, x):\n        x = self.main(x)\n        x = F.avg_pool2d(x, x.size()[2:])\n        x = torch.flatten(x, 1)\n        return x","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:02:47.379175Z","iopub.execute_input":"2022-06-13T05:02:47.379673Z","iopub.status.idle":"2022-06-13T05:02:47.389842Z","shell.execute_reply.started":"2022-06-13T05:02:47.379638Z","shell.execute_reply":"2022-06-13T05:02:47.388531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ResidualBlock(nn.Module):\n    def __init__(self, in_channels):\n        super(ResidualBlock, self).__init__()\n\n        self.main = nn.Sequential(\n            nn.ReflectionPad2d(1),\n            nn.Conv2d(in_channels, in_channels, 3),\n            nn.InstanceNorm2d(in_channels),\n            nn.SELU(inplace=True),\n            nn.ReflectionPad2d(1),\n            nn.Conv2d(in_channels, in_channels, 3),\n            nn.InstanceNorm2d(in_channels)\n        )\n\n    def forward(self, x):\n        return x + self.main(x)","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:02:47.789269Z","iopub.execute_input":"2022-06-13T05:02:47.789547Z","iopub.status.idle":"2022-06-13T05:02:47.795622Z","shell.execute_reply.started":"2022-06-13T05:02:47.789523Z","shell.execute_reply":"2022-06-13T05:02:47.794725Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Generator(nn.Module):\n    def __init__(self, conv_dim=64, n_res_block=9):\n        super(Generator, self).__init__()\n        self.main = nn.Sequential(\n            nn.ReflectionPad2d(3),\n            nn.Conv2d(3, conv_dim, 7),\n            nn.InstanceNorm2d(64),\n            nn.SELU(inplace=True),\n\n            nn.Conv2d(conv_dim, conv_dim*2, 3, stride=2, padding=1),\n            nn.InstanceNorm2d(conv_dim*2),\n            nn.SELU(inplace=True),\n            nn.Conv2d(conv_dim*2, conv_dim*4, 3, stride=2, padding=1),\n            nn.InstanceNorm2d(conv_dim*4),\n            nn.SELU(inplace=True),\n\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n            ResidualBlock(conv_dim*4),\n\n            nn.ConvTranspose2d(conv_dim*4, conv_dim*2, 3, stride=2, padding=1, output_padding=1),\n            nn.InstanceNorm2d(conv_dim*2),\n            nn.SELU(inplace=True),\n            nn.ConvTranspose2d(conv_dim*2, conv_dim, 3, stride=2, padding=1, output_padding=1),\n            nn.InstanceNorm2d(conv_dim),\n            nn.SELU(inplace=True),\n\n            nn.ReflectionPad2d(3),\n            nn.Conv2d(conv_dim, 3, 7),\n            nn.Tanh()\n        )\n\n    def forward(self, x):\n        return self.main(x)","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:02:47.979433Z","iopub.execute_input":"2022-06-13T05:02:47.979721Z","iopub.status.idle":"2022-06-13T05:02:47.991656Z","shell.execute_reply.started":"2022-06-13T05:02:47.979697Z","shell.execute_reply":"2022-06-13T05:02:47.990682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CycleGAN:\n\n    def __init__(self, g_conv_dim=64, d_conv_dim=64, n_res_block=6):\n        self.device = torch.device('cuda') if torch.cuda.is_available() else torch.device(\"cpu\")\n\n        self.G_XtoY = Generator(conv_dim=g_conv_dim, n_res_block=n_res_block).to(self.device)\n        self.G_YtoX = Generator(conv_dim=g_conv_dim, n_res_block=n_res_block).to(self.device)\n\n        self.D_X = Discriminator(conv_dim=d_conv_dim).to(self.device)\n        self.D_Y = Discriminator(conv_dim=d_conv_dim).to(self.device)\n\n        print(f\"Models running of {self.device}\")\n\n    def load_model(self, filename):\n        save_filename = os.path.splitext(os.path.basename(filename))[0] + '.pt'\n        return torch.load(save_filename)\n\n    def real_mse_loss(self, D_out):\n        return torch.mean((D_out-1)**2)\n\n\n    def fake_mse_loss(self, D_out):\n        return torch.mean(D_out**2)\n\n\n    def cycle_consistency_loss(self, real_img, reconstructed_img, lambda_weight):\n        reconstr_loss = torch.mean(torch.abs(real_img - reconstructed_img))\n        return lambda_weight*reconstr_loss    \n\n    \n    def train_generator(self, optimizers, images_x, images_y):\n        # Generator YtoX\n        optimizers[\"g_optim\"].zero_grad()\n\n        fake_images_x = self.G_YtoX(images_y)\n\n        d_real_x = self.D_X(fake_images_x)\n        g_YtoX_loss = self.real_mse_loss(d_real_x)\n\n        recon_y = self.G_XtoY(fake_images_x)\n        recon_y_loss = self.cycle_consistency_loss(images_y, recon_y, lambda_weight=10)\n\n\n        # Generator XtoY\n        fake_images_y = self.G_XtoY(images_x)\n\n        d_real_y = self.D_Y(fake_images_y)\n        g_XtoY_loss = self.real_mse_loss(d_real_y)\n\n        recon_x = self.G_YtoX(fake_images_y)\n        recon_x_loss = self.cycle_consistency_loss(images_x, recon_x, lambda_weight=10)\n\n        g_total_loss = g_YtoX_loss + g_XtoY_loss + recon_y_loss + recon_x_loss\n        g_total_loss.backward()\n        optimizers[\"g_optim\"].step()\n\n        return g_total_loss.item()\n\n    \n    def train_discriminator(self, optimizers, images_x, images_y):\n        # Discriminator x\n        optimizers[\"d_x_optim\"].zero_grad()\n\n        d_real_x = self.D_X(images_x)\n        d_real_loss_x = self.real_mse_loss(d_real_x)\n        \n        fake_images_x = self.G_YtoX(images_y)\n\n        d_fake_x = self.D_X(fake_images_x)\n        d_fake_loss_x = self.fake_mse_loss(d_fake_x)\n        \n        d_x_loss = d_real_loss_x + d_fake_loss_x\n        d_x_loss.backward()\n        optimizers[\"d_x_optim\"].step()\n\n\n        # Discriminator y\n        optimizers[\"d_y_optim\"].zero_grad()\n            \n        d_real_y = self.D_Y(images_y)\n        d_real_loss_x = self.real_mse_loss(d_real_y)\n    \n        fake_images_y = self.G_XtoY(images_x)\n\n        d_fake_y = self.D_Y(fake_images_y)\n        d_fake_loss_y = self.fake_mse_loss(d_fake_y)\n\n        d_y_loss = d_real_loss_x + d_fake_loss_y\n        d_y_loss.backward()\n        optimizers[\"d_y_optim\"].step()\n\n        return d_x_loss.item(), d_y_loss.item()\n\n\n    def train(self, optimizers, data_loader_x, data_loader_y, print_every=1, sample_every=100):\n        losses = []\n        g_total_loss_min = np.Inf\n    \n        fixed_x = next(iter(data_loader_x))[1].to(self.device)\n        fixed_y = next(iter(data_loader_y))[1].to(self.device)\n\n        print(f'Running on {self.device}')\n        for epoch in range(EPOCHS):\n            for (images_x, images_y) in zip(data_loader_x, data_loader_y):\n                images_x, images_y = images_x.to(self.device), images_y.to(self.device)\n                \n                g_total_loss = self.train_generator(optimizers, images_x, images_y)\n                d_x_loss, d_y_loss = self.train_discriminator(optimizers, images_x, images_y)\n                \n            \n            if epoch % print_every == 0:\n                losses.append((d_x_loss, d_y_loss, g_total_loss))\n                print('Epoch [{:5d}/{:5d}] | d_X_loss: {:6.4f} | d_Y_loss: {:6.4f} | g_total_loss: {:6.4f}'\n                .format(\n                    epoch, \n                    EPOCHS, \n                    d_x_loss, \n                    d_y_loss, \n                    g_total_loss\n                ))\n                \n            if g_total_loss < g_total_loss_min:\n                g_total_loss_min = g_total_loss\n                \n                torch.save(self.G_XtoY.state_dict(), \"G_X2Y\")\n                torch.save(self.G_YtoX.state_dict(), \"G_Y2X\")\n                \n                torch.save(self.D_X.state_dict(), \"D_X\")\n                torch.save(self.D_Y.state_dict(), \"D_Y\")\n                \n                print(\"Models Saved\")\n                \n                \n\n        return losses","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:02:48.145829Z","iopub.execute_input":"2022-06-13T05:02:48.146073Z","iopub.status.idle":"2022-06-13T05:02:48.169994Z","shell.execute_reply.started":"2022-06-13T05:02:48.146051Z","shell.execute_reply":"2022-06-13T05:02:48.169091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_DATASET_PATH = \"../input/gan-getting-started\"\nX_DATASET = \"photo_jpg\"\nY_DATASET = \"monet_jpg\"\n\nBATCH_SIZE = 32\nN_WORKERS = 0\n\nIMG_SIZE = 128\nLR = 0.0002\nBETA1 = 0.5\nBETA2 = 0.999\n\nEPOCHS = 3","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:02:48.342912Z","iopub.execute_input":"2022-06-13T05:02:48.343289Z","iopub.status.idle":"2022-06-13T05:02:48.349166Z","shell.execute_reply.started":"2022-06-13T05:02:48.343262Z","shell.execute_reply":"2022-06-13T05:02:48.348482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Dataset\nx_dataset = Dataset(X_DATASET)\ny_dataset = Dataset(Y_DATASET)\n\ndata_loader_x = DataLoader(x_dataset, BATCH_SIZE, shuffle=True, num_workers=N_WORKERS)\ndata_loader_y = DataLoader(y_dataset, BATCH_SIZE, shuffle=True, num_workers=N_WORKERS)\n\n# Model\ncycleGan = CycleGAN()\n\n# Oprimizer\ng_params = list(cycleGan.G_XtoY.parameters()) + list(cycleGan.G_YtoX.parameters())\n\noptimizers = {\n    \"g_optim\": optim.Adam(g_params, LR, [BETA1, BETA2]),\n    \"d_x_optim\": optim.Adam(cycleGan.D_X.parameters(), LR, [BETA1, BETA2]),\n    \"d_y_optim\": optim.Adam(cycleGan.D_Y.parameters(), LR, [BETA1, BETA2])\n}\n\n# Train\nlosses = cycleGan.train(optimizers, data_loader_x, data_loader_y)","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:02:48.484741Z","iopub.execute_input":"2022-06-13T05:02:48.485112Z","iopub.status.idle":"2022-06-13T05:04:20.435922Z","shell.execute_reply.started":"2022-06-13T05:02:48.485086Z","shell.execute_reply":"2022-06-13T05:04:20.434438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(data_loader_x)","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:04:20.437651Z","iopub.execute_input":"2022-06-13T05:04:20.438015Z","iopub.status.idle":"2022-06-13T05:04:20.445765Z","shell.execute_reply.started":"2022-06-13T05:04:20.437979Z","shell.execute_reply":"2022-06-13T05:04:20.444922Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"samples = []\n\nfor i in range(32):\n    fixed_x = next(iter(data_loader_x))[i].to(cycleGan.device)\n    fake_y = cycleGan.G_XtoY(torch.unsqueeze(fixed_x, dim=0))\n    samples.extend([fixed_x, torch.squeeze(fake_y, 0)])\n","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:04:20.447154Z","iopub.execute_input":"2022-06-13T05:04:20.447718Z","iopub.status.idle":"2022-06-13T05:04:28.959729Z","shell.execute_reply.started":"2022-06-13T05:04:20.447681Z","shell.execute_reply":"2022-06-13T05:04:28.95893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import PIL","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:04:28.961569Z","iopub.execute_input":"2022-06-13T05:04:28.96204Z","iopub.status.idle":"2022-06-13T05:04:28.966576Z","shell.execute_reply.started":"2022-06-13T05:04:28.962Z","shell.execute_reply":"2022-06-13T05:04:28.965714Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for i, im in enumerate(fake_y):\n#     _, w, h = im.size()\n#     im = im.detach().cpu().numpy()\n#     im = np.transpose(im, (1, 2, 0))\n    \n#     im = ((im +1)*255 / (2)).astype(np.uint8)\n#     im = PIL.Image.fromarray(im)\n#     im.save(\"./images/\" + str(i+1) + \".jpg\")\n    ","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:01:19.164617Z","iopub.status.idle":"2022-06-13T05:01:19.165106Z","shell.execute_reply.started":"2022-06-13T05:01:19.164843Z","shell.execute_reply":"2022-06-13T05:01:19.164864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import shutil\n# shutil.make_archive(\"/kaggle/working/images7\", 'zip', \"/kaggle/working/images\")","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:01:19.166472Z","iopub.status.idle":"2022-06-13T05:01:19.166941Z","shell.execute_reply.started":"2022-06-13T05:01:19.16671Z","shell.execute_reply":"2022-06-13T05:01:19.166733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir ./images\nos.listdir()","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:05:39.866452Z","iopub.execute_input":"2022-06-13T05:05:39.867249Z","iopub.status.idle":"2022-06-13T05:05:40.554538Z","shell.execute_reply.started":"2022-06-13T05:05:39.867214Z","shell.execute_reply":"2022-06-13T05:05:40.55352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for i, im in enumerate(samples):\n#     _, w, h = im.size()\n#     im = im.detach().cpu().numpy()\n#     im = np.transpose(im, (1, 2, 0))\n    \n#     im = ((im +1)*255 / (2)).astype(np.uint8)\n#     im = PIL.Image.fromarray(im)\n#     im.save(\"./images/\" + str(i+1) + \".jpg\")\n    ","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:01:19.169919Z","iopub.status.idle":"2022-06-13T05:01:19.170358Z","shell.execute_reply.started":"2022-06-13T05:01:19.170141Z","shell.execute_reply":"2022-06-13T05:01:19.170163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import shutil\n# shutil.make_archive(\"/kaggle/working/images7\", 'zip', \"/kaggle/working/images\")","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:01:19.17181Z","iopub.status.idle":"2022-06-13T05:01:19.172244Z","shell.execute_reply.started":"2022-06-13T05:01:19.172026Z","shell.execute_reply":"2022-06-13T05:01:19.172047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n#Set model to evaluation\ncycleGan.G_XtoY.eval()\n\n#Get data loader for final transformation / submission\nphoto_dataset = Dataset('../gan-getting-started/photo_jpg/')\nsubmit_dataloader = DataLoader(photo_dataset, batch_size=1, shuffle=False, pin_memory=True)\ndataiter = iter(submit_dataloader)\n\n#Previous normalization choosen\nmean_ = 0.5 \nstd_ = 0.5\n\n#Loop through each picture\nfor image_idx in range(0, len(submit_dataloader)):\n    with torch.no_grad():    \n    #Get base picture\n        fixed_X = dataiter.next()\n    \n    #Identify correct device\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    \n    #Create fake pictures (monet-esque)\n    fake_Y = cycleGan.G_XtoY(fixed_X.to(device))\n    fake_Y = fake_Y.detach().cpu().numpy()\n    fake_Y = reverse_normalize(fake_Y, mean_, std_)\n    fake_Y = fake_Y[0].transpose(1, 2, 0)\n    fake_Y = np.uint8(fake_Y)\n    fake_Y = Image.fromarray(fake_Y)\n    #print(fake_Y.shape)\n    \n    #Save picture\n    fake_Y.save(\"./images/\" + str(image_idx) + \".jpg\")\n\n#Back to it\ncycleGan.G_XtoY.train()","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:08:08.892796Z","iopub.execute_input":"2022-06-13T05:08:08.893134Z","iopub.status.idle":"2022-06-13T05:09:38.646156Z","shell.execute_reply.started":"2022-06-13T05:08:08.893107Z","shell.execute_reply":"2022-06-13T05:09:38.645424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images3\", 'zip', \"/kaggle/working/images\")","metadata":{"execution":{"iopub.status.busy":"2022-06-13T05:10:36.108916Z","iopub.execute_input":"2022-06-13T05:10:36.1093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}