{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as Fn\nimport torch.optim as optim\nfrom torch.autograd import Variable\nfrom torch.utils.data import DataLoader, TensorDataset\n\nimport os\nimport numpy as np\nfrom PIL import Image\n\nimport matplotlib.pyplot as plt\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"\n#storing the names of your images and paintings in a list\n\ndir = '../input/gan-getting-started'\ntrain_paintings_dir = dir + '/monet_jpg/'\ntrain_photos_dir = dir + '/photo_jpg/'\n\npaintings_addr = [train_paintings_dir+i for i in os.listdir(train_paintings_dir)]\nphotos_addr = [train_photos_dir+i for i in os.listdir(train_photos_dir)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(photos_addr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Preprocessing data so that every value in the image array is between -1 and 1. \n\ndef create_train_sets(paintings_addr, photos_addr):\n    \n    X_train, Y_train = np.zeros((300, 3, 256, 256), dtype=np.float32), np.zeros((7038, 3, 256, 256), dtype=np.float32)\n    \n    for i in range(len(paintings_addr)):\n        temp_np = np.asarray(Image.open(paintings_addr[i]).resize((256, 256), Image.ANTIALIAS))  #resizing the image to 128x128\n        X_train[i] = temp_np.transpose(2, 0, 1)\n        X_train[i] /= 255\n        X_train[i] = X_train[i] * 2 -  1\n        \n    for i in range(len(photos_addr)):\n        temp_np = np.asarray(Image.open(photos_addr[i]).resize((256, 256), Image.ANTIALIAS))\n        Y_train[i] = temp_np.transpose(2, 0, 1)\n        Y_train[i] /= 255\n        Y_train[i] = Y_train[i] * 2 -  1\n    \n    return X_train, Y_train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nX_train, Y_train = create_train_sets(paintings_addr, photos_addr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_tensor = torch.from_numpy(X_train)                #Creating Tensors which will later be wrapped into variables\nY_tensor = torch.from_numpy(Y_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class discriminator_nonpatch(nn.Module):\n    def __init__(self):\n        super(discriminator_nonpatch, self).__init__()\n        \n        self.conv1 = nn.Conv2d(3, 64, kernel_size=4, stride=2)\n        \n        self.conv2 = nn.Conv2d(64, 128, kernel_size=4, stride=2)\n        self.bn2 = nn.BatchNorm2d(128)\n        \n        self.conv3 = nn.Conv2d(128, 256, kernel_size=4, stride=2)\n        self.bn3 = nn.BatchNorm2d(256)\n        \n        self.conv4 = nn.Conv2d(256, 512, kernel_size=4, stride=2)\n        self.bn4 = nn.BatchNorm2d(512)\n        \n        self.conv5 = nn.Conv2d(512, 512, kernel_size=4, stride=2)\n        self.bn5 = nn.BatchNorm2d(512)\n        \n        self.conv6 = nn.Conv2d(512, 512, kernel_size=4, stride=2)\n        self.bn6 = nn.BatchNorm2d(512)\n        \n        self.conv7 = nn.Conv2d(512, 512, kernel_size=2, stride=2)\n        \n        \n        self.head = nn.Linear(512, 1)\n        \n    def forward(self, input):\n        x = Fn.leaky_relu(self.conv1(input), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn2(self.conv2(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn3(self.conv3(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn4(self.conv4(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn5(self.conv5(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn6(self.conv6(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.conv7(x), negative_slope=0.2)\n        \n        x = x.view(x.size(0), -1)\n        x = self.head(x)\n        \n        return torch.sigmoid(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nclass discriminator(nn.Module):\n    def __init__(self):\n        super(discriminator, self).__init__()\n        \n        self.conv1 = nn.Conv2d(3, 64, kernel_size=4, stride=2)\n        \n        self.conv2 = nn.Conv2d(64, 128, kernel_size=4, stride=2)\n        self.bn2 = nn.BatchNorm2d(128)\n        \n        self.conv3 = nn.Conv2d(128, 256, kernel_size=4, stride=2)\n        self.bn3 = nn.BatchNorm2d(256)\n        \n        self.conv4 = nn.Conv2d(256, 512, kernel_size=4, stride=2)\n        self.bn4 = nn.BatchNorm2d(512)\n        \n        self.conv5 = nn.Conv2d(512, 512, kernel_size=2, stride=1)\n        \n\n        self.head = nn.Linear(512, 1)\n        \n    def forward(self, input):\n        x = Fn.leaky_relu(self.conv1(input), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn2(self.conv2(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn3(self.conv3(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.bn4(self.conv4(x)), negative_slope=0.2)\n        x = Fn.leaky_relu(self.conv5(x), negative_slope=0.2)\n\n        x = x.view(x.size(0), -1)\n        x = self.head(x)\n        \n        return torch.sigmoid(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nclass generator(nn.Module):         #padding concerns: reflection? What exactly is the concept behind convTranspose?\n    \n    def __init__(self):\n        super(generator, self).__init__()\n        \n        #c7s1-32\n        self.r1 = nn.ReflectionPad2d(3)\n        self.conv1 = nn.Conv2d(3, 32, kernel_size=7, stride=1)\n        self.bn1 = nn.BatchNorm2d(32)\n        \n        #d64\n        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1)\n        self.bn2 = nn.BatchNorm2d(64)\n        \n        #d128\n        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1)\n        self.bn3 = nn.BatchNorm2d(128)\n        \n        #R128\n        self.r4 = nn.ReflectionPad2d(1)\n        self.conv4 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn4 = nn.BatchNorm2d(128)\n        \n        self.r5 = nn.ReflectionPad2d(1)\n        self.conv5 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn5 = nn.BatchNorm2d(128)\n        \n        #R128\n        self.r6 = nn.ReflectionPad2d(1)\n        self.conv6 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn6 = nn.BatchNorm2d(128)\n        \n        self.r7 = nn.ReflectionPad2d(1)\n        self.conv7 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn7 = nn.BatchNorm2d(128)\n        \n        #R128\n        self.r8 = nn.ReflectionPad2d(1)\n        self.conv8 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn8 = nn.BatchNorm2d(128)\n        \n        self.r9 = nn.ReflectionPad2d(1)\n        self.conv9 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn9 = nn.BatchNorm2d(128)\n        \n        #R128\n        self.r10 = nn.ReflectionPad2d(1)\n        self.conv10 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn10 = nn.BatchNorm2d(128)\n        \n        self.r11 = nn.ReflectionPad2d(1)\n        self.conv11 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn11 = nn.BatchNorm2d(128)\n        \n        #R128\n        self.r12 = nn.ReflectionPad2d(1)\n        self.conv12 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn12 = nn.BatchNorm2d(128)\n        \n        self.r13 = nn.ReflectionPad2d(1)\n        self.conv13 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn13 = nn.BatchNorm2d(128)\n        \n        #R128\n        self.r14 = nn.ReflectionPad2d(1)\n        self.conv14 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn14 = nn.BatchNorm2d(128)\n        \n        self.r15 = nn.ReflectionPad2d(1)\n        self.conv15 = nn.Conv2d(128, 128, kernel_size=3)\n        self.bn15 = nn.BatchNorm2d(128)\n        \n        #u64\n        self.uconv16 = nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, output_padding=1)\n        self.bn16 = nn.BatchNorm2d(64)\n        \n        #u32\n        self.uconv17 = nn.ConvTranspose2d(64, 32, kernel_size=3, stride=2, padding=1, output_padding=1)\n        self.bn17 = nn.BatchNorm2d(32)\n        \n        #c7s1-3\n        self.r18 = nn.ReflectionPad2d(3)\n        self.conv18 = nn.Conv2d(32, 3, kernel_size=7, stride=1)\n        self.bn18 = nn.BatchNorm2d(3)\n        \n    def forward(self, input):\n        \n        #c7s1-32\n        x = Fn.leaky_relu(self.bn1(self.conv1(self.r1(input))), negative_slope=0.2)\n        \n        #d64\n        x = Fn.leaky_relu(self.bn2(self.conv2(x)), negative_slope=0.2)\n        \n        #d128\n        x = Fn.leaky_relu(self.bn3(self.conv3(x)), negative_slope=0.2)\n        \n        #R128\n        x1 = Fn.leaky_relu(self.bn4(self.conv4(self.r4(x))), negative_slope=0.2)\n        x1 = Fn.leaky_relu(self.bn5(self.conv5(self.r5(x1))), negative_slope=0.2)\n        \n        x = x + x1\n        \n        #R128\n        x1 = Fn.leaky_relu(self.bn6(self.conv6(self.r6(x))), negative_slope=0.2)\n        x1 = Fn.leaky_relu(self.bn7(self.conv7(self.r7(x1))), negative_slope=0.2)\n        \n        x = x + x1\n        \n        #R128\n        x1 = Fn.leaky_relu(self.bn8(self.conv8(self.r8(x))), negative_slope=0.2)\n        x1 = Fn.leaky_relu(self.bn9(self.conv9(self.r9(x1))), negative_slope=0.2)\n        \n        x = x + x1\n        \n        #R128\n        x1 = Fn.leaky_relu(self.bn10(self.conv10(self.r10(x))), negative_slope=0.2)\n        x1 = Fn.leaky_relu(self.bn11(self.conv11(self.r11(x1))), negative_slope=0.2)\n        \n        x = x + x1\n       \n        #R128\n        x1 = Fn.leaky_relu(self.bn12(self.conv12(self.r12(x))), negative_slope=0.2)\n        x1 = Fn.leaky_relu(self.bn13(self.conv13(self.r13(x1))), negative_slope=0.2)\n        \n        x = x + x1\n        \n        #R128\n        x1 = Fn.leaky_relu(self.bn14(self.conv14(self.r14(x))), negative_slope=0.2)\n        x1 = Fn.leaky_relu(self.bn15(self.conv15(self.r15(x1))), negative_slope=0.2)\n        \n        x = x + x1\n        \n        #u64\n        x = Fn.leaky_relu(self.bn16(self.uconv16(x)), negative_slope=0.2)\n        \n        #u32\n        x = Fn.leaky_relu(self.bn17(self.uconv17(x)), negative_slope=0.2)\n        \n        #c7s1-3\n        x = Fn.leaky_relu(self.bn18(self.conv18(self.r18(x))), negative_slope=0.2)\n        \n        return torch.tanh(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef weights_init(m):\n    classname = m.__class__.__name__\n    if classname.find('Conv') != -1:\n        m.weight.data.normal_(0.0, 0.02)\n    elif classname.find('BatchNorm') != -1:\n        m.weight.data.normal_(1.0, 0.02)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef pass_through_discriminator(discriminator, image):\n    score, k = 0, Variable(torch.zeros(1)).type(dtype)\n    xp, yp = 0, 0\n    x, y = 70, 70\n    offset = 25\n    \n    while x < 256:\n        while y < 256:\n            k += 1\n            score += discriminator(image[:, :, xp:x, yp:y])\n            yp += offset\n            y += offset\n            \n        xp += offset\n        x += offset\n        \n    return score / k","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndtype = torch.FloatTensor\n\nif torch.cuda.is_available():\n    dtype = torch.cuda.FloatTensor\n    \nG = generator().type(dtype)\nF = generator().type(dtype)\n\nDg = discriminator().type(dtype)\nDf = discriminator().type(dtype)\nDgnp = discriminator_nonpatch().type(dtype)\nDfnp = discriminator_nonpatch().type(dtype)\n\nG.apply(weights_init)\nF.apply(weights_init)\nDg.apply(weights_init)\nDf.apply(weights_init)\n\nG_optim = optim.Adam(G.parameters(), lr=0.0002)    #Learning rates directly borrowed from the paper\nF_optim = optim.Adam(F.parameters(), lr=0.0002)\n\nDg_optim = optim.Adam(Dg.parameters(), lr=0.0001)\nDf_optim = optim.Adam(Df.parameters(), lr=0.0001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(Dgnp)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nepochs = 30\nbatch_size = 32\n\nG.train()\nF.train()\nDg.train()\nDf.train()\n\nk = 0\n\nfor epoch in range(epochs):\n    print('Epoch number: {0}'.format(epoch))\n    \n    for batch in range(X_tensor.size(0) // batch_size):\n        if batch % 100 == 0:\n            print('**Batch number: {0}**'.format(batch))\n        \n        painting_real = X_tensor[batch * batch_size: (batch + 1) * batch_size]\n        if k!= 7038:\n            photo_real = Y_tensor[k % 7038: (k + 1) % 7038]       \n        else:\n            photo_real = Y_tensor[7038]\n            photo_real = photo_real[np.newaxis, ...]\n        k += 1\n        \n        painting_real = Variable(painting_real).type(dtype)\n        photo_real = Variable(photo_real).type(dtype)\n        \n        #Train GAN G\n        \n        #Train Dg\n        photo_fake = G(painting_real)\n        \n        scores_real = pass_through_discriminator(Dg, photo_real)\n        scores_real_np = Dgnp(photo_real)\n        scores_fake = pass_through_discriminator(Dg, photo_fake)\n        scores_fake_np = Dgnp(photo_fake)\n        \n        label_fake = Variable(torch.zeros(batch_size)).type(dtype)\n        label_real = Variable(torch.ones(batch_size)).type(dtype)\n        \n        scores_real = (0.8 * scores_real + 0.2 * scores_real_np) \n        scores_fake = (0.8 * scores_fake + 0.2 * scores_fake_np) \n        \n        loss1 = torch.mean((scores_real - label_real)**2)\n        loss2 = torch.mean((scores_fake - label_fake)**2)\n        \n        Dg_optim.zero_grad()\n        \n        loss_dg = (loss1 + loss2)\n        if batch % 100 == 0:\n            print('Discriminator G loss: {0}'.format(loss_dg.data))\n        loss_dg.backward()\n        \n        Dg_optim.step()\n\n        #Train G\n        photo_fake = G(painting_real)\n        \n        scores_fake = pass_through_discriminator(Dg, photo_fake)\n        loss_g = torch.mean((scores_fake - label_real)**2) + 10 * torch.mean(torch.abs(G(F(photo_real)) - photo_real))\n        if batch % 100 == 0:\n            print('Generator G loss: {0}'.format(loss_g.data))\n        \n        G_optim.zero_grad()\n        loss_g.backward()\n        G_optim.step()\n        \n        #Train GAN F\n        \n        painting_fake = F(photo_real)\n        \n        scores_real = pass_through_discriminator(Df, painting_real)\n        scores_real_np = Dfnp(painting_real)\n        scores_fake = pass_through_discriminator(Df, painting_fake)\n        scores_fake_np = Dfnp(painting_fake)\n        \n        scores_real = (0.8 * scores_real + 0.2 * scores_real_np)\n        scores_fake = (0.8 * scores_fake + 0.2 * scores_fake_np)\n        \n        loss1 = torch.mean((scores_real - label_real)**2)\n        loss2 = torch.mean((scores_fake - label_fake)**2)\n        \n        Df_optim.zero_grad()\n        \n        loss_df = (loss1 + loss2)\n        if batch % 100 == 0:\n            print('Discriminator F loss: {0}'.format(loss_df.data))\n        loss_df.backward()\n        \n        Df_optim.step()\n        \n        #Train F\n        \n        painting_fake = F(photo_real)\n        \n        scores_fake = pass_through_discriminator(Df, painting_fake)\n        loss_f = torch.mean((scores_fake - label_real)**2) + 10 * torch.mean(torch.abs(F(G(painting_real)) - painting_real))\n        if batch % 100 == 0:\n            print('Generator F loss: {0}'.format(loss_f.data))\n        \n        F_optim.zero_grad()\n        loss_f.backward()\n        F_optim.step()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Simple function for unpreprocessing and displaying results\n\ndef test_image(img_addr):\n    img = Image.open(img_addr)\n    img_np = np.zeros((1, 3, 256, 256), dtype=np.float32)\n    temp_np = np.asarray(img.resize((256, 256), Image.ANTIALIAS))\n    plt.imshow(temp_np)\n    \n    img_np[0] = temp_np.transpose(2, 0, 1)\n    \n    img_np /= 255\n    img_np = img_np * 2 - 1\n    img_tensor = torch.from_numpy(img_np)\n    img_var = Variable(img_tensor).type(dtype)\n    \n    photo_var = G(img_var)\n    photo = photo_var.data.cpu().numpy()\n    photo = photo[0].transpose(1, 2, 0)\n    photo = (photo + 1)/2\n    plt.figure()\n    plt.imshow(photo)\n    \n    paint_var = F(photo_var)\n    paint = paint_var.data.cpu().numpy()\n    paint = paint[0].transpose(1, 2, 0)\n    paint = (paint + 1)/2\n    plt.figure()\n    plt.imshow(paint)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_image(paintings_addr[22])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def photo2monet(photo_addr):\n    img = Image.open(photo_addr)\n    img_np = np.zeros((1, 3, 256, 256), dtype=np.float32)\n    temp_np = np.asarray(img.resize((256, 256), Image.ANTIALIAS))\n    plt.imshow(temp_np)\n    \n    img_np[0] = temp_np.transpose(2, 0, 1)\n    \n    img_np /= 255\n    img_np = img_np * 2 - 1\n    img_tensor = torch.from_numpy(img_np)\n    img_var = Variable(img_tensor).type(dtype)\n    \n    paint_var = F(img_var)\n    paint = paint_var.data.cpu().numpy()\n    paint = paint[0].transpose(1, 2, 0)\n    paint = (paint + 1)/2\n    plt.figure()\n    plt.imshow(paint)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## submission","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import PIL\n! mkdir ../images","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"photos_addr[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"i = 1\nfor photo_addr in photos_addr:\n    img = Image.open(photo_addr)\n    img_np = np.zeros((1, 3, 128, 128), dtype=np.float32)\n    temp_np = np.asarray(img.resize((128, 128), Image.ANTIALIAS))\n    \n    img_np[0] = temp_np.transpose(2, 0, 1)\n    \n    img_np /= 255\n    img_np = img_np * 2 - 1\n    img_tensor = torch.from_numpy(img_np)\n    img_var = Variable(img_tensor).type(dtype)\n    \n    paint_var = F(img_var)\n    paint = paint_var.data.cpu().numpy()\n    paint = paint[0].transpose(1, 2, 0)\n    paint = (paint + 1)/2\n    #plt.savefig()\n    im = PIL.Image.fromarray(np.uint8(paint*255))\n    im.save(\"../images/\" + str(i) + \".jpg\")\n    i +=1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}