{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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\n#for 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 5GB 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","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"DATA_DIR = '../input/gan-getting-started/'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.nn.functional as F","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\n\nprint(os.listdir(DATA_DIR))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(os.listdir(DATA_DIR)[:10])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.utils.data import DataLoader\nfrom torchvision.datasets import ImageFolder\nimport torchvision.transforms as T","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_size = 64\nbatch_size = 128\nstats = (0.5, 0.5, 0.5), (0.5, 0.5, 0.5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = ImageFolder(DATA_DIR, transform=T.Compose([\n    T.Resize(image_size),\n    T.CenterCrop(image_size),\n    T.ToTensor(),\n    T.Normalize(*stats)]))\n\ntrain_dl = DataLoader(train_ds, batch_size, shuffle=True, num_workers=3, pin_memory=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nfrom torchvision.utils import make_grid\nimport matplotlib.pyplot as plt\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def denorm(img_tensors):\n    return img_tensors * stats[1][0] + stats[0][0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_images(images, nmax=64):\n    fig, ax = plt.subplots(figsize=(8, 8))\n    ax.set_xticks([]); ax.set_yticks([])\n    ax.imshow(make_grid(denorm(images.detach()[:nmax]), nrow=8).permute(1, 2, 0))\n\ndef show_batch(dl, nmax=64):\n    for images, _ in dl:\n        show_images(images, nmax)\n        break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_default_device():\n    \"\"\"Pick GPU if available, else CPU\"\"\"\n    if torch.cuda.is_available():\n        return torch.device('cuda')\n    else:\n        return torch.device('cpu')\n    \ndef to_device(data, device):\n    \"\"\"Move tensor(s) to chosen device\"\"\"\n    if isinstance(data, (list,tuple)):\n        return [to_device(x, device) for x in data]\n    return data.to(device, non_blocking=True)\n\nclass DeviceDataLoader():\n    \"\"\"Wrap a dataloader to move data to a device\"\"\"\n    def __init__(self, dl, device):\n        self.dl = dl\n        self.device = device\n        \n    def __iter__(self):\n        \"\"\"Yield a batch of data after moving it to device\"\"\"\n        for b in self.dl: \n            yield to_device(b, self.device)\n\n    def __len__(self):\n        \"\"\"Number of batches\"\"\"\n        return len(self.dl)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = get_default_device()\ndevice\ntrain_dl = DeviceDataLoader(train_dl, device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.nn as nn\ndiscriminator = nn.Sequential(\n    # in: 3 x 64 x 64\n\n    nn.Conv2d(3, 64, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(64),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out: 64 x 32 x 32\n\n    nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(128),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out: 128 x 16 x 16\n\n    nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(256),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out: 256 x 8 x 8\n\n    nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(512),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out: 512 x 4 x 4\n\n    nn.Conv2d(512, 1, kernel_size=4, stride=1, padding=0, bias=False),\n    # out: 1 x 1 x 1\n\n    nn.Flatten(),\n    nn.Sigmoid())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"discriminator = to_device(discriminator, device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"latent_size = 128\ngenerator = nn.Sequential(\n    # in: latent_size x 1 x 1\n\n    nn.ConvTranspose2d(latent_size, 512, kernel_size=4, stride=1, padding=0, bias=False),\n    nn.BatchNorm2d(512),\n    nn.ReLU(True),\n    # out: 512 x 4 x 4\n\n    nn.ConvTranspose2d(512, 256, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(256),\n    nn.ReLU(True),\n    # out: 256 x 8 x 8\n\n    nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(128),\n    nn.ReLU(True),\n    # out: 128 x 16 x 16\n\n    nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(64),\n    nn.ReLU(True),\n    # out: 64 x 32 x 32\n\n    nn.ConvTranspose2d(64, 3, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.Tanh()\n    # out: 3 x 64 x 64\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"generator = to_device(generator, device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_discriminator(real_images, opt_d):\n    # Clear discriminator gradients\n    opt_d.zero_grad()\n\n    # Pass real images through discriminator\n    real_preds = discriminator(real_images)\n    real_targets = torch.ones(real_images.size(0), 1, device=device)\n    real_loss = F.binary_cross_entropy(real_preds, real_targets)\n    real_score = torch.mean(real_preds).item()\n    \n    # Generate fake images\n    latent = torch.randn(batch_size, latent_size, 1, 1, device=device)\n    fake_images = generator(latent)\n\n    # Pass fake images through discriminator\n    fake_targets = torch.zeros(fake_images.size(0), 1, device=device)\n    fake_preds = discriminator(fake_images)\n    fake_loss = F.binary_cross_entropy(fake_preds, fake_targets)\n    fake_score = torch.mean(fake_preds).item()\n\n    # Update discriminator weights\n    loss = real_loss + fake_loss\n    loss.backward()\n    opt_d.step()\n    return loss.item(), real_score, fake_score","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_generator(opt_g):\n    # Clear generator gradients\n    opt_g.zero_grad()\n    \n    # Generate fake images\n    latent = torch.randn(batch_size, latent_size, 1, 1, device=device)\n    fake_images = generator(latent)\n    \n    # Try to fool the discriminator\n    preds = discriminator(fake_images)\n    targets = torch.ones(batch_size, 1, device=device)\n    loss = F.binary_cross_entropy(preds, targets)\n    \n    # Update generator weights\n    loss.backward()\n    opt_g.step()\n    \n    return loss.item()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torchvision.utils import save_image\nsample_dir = 'generated'\nos.makedirs(sample_dir, exist_ok=True)\ndef save_samples(index, latent_tensors, show=True):\n    fake_images = generator(latent_tensors)\n    fake_fname = 'generated-images-{0:0=4d}.png'.format(index)\n    save_image(denorm(fake_images), os.path.join(sample_dir, fake_fname), nrow=8)\n    print('Saving', fake_fname)\n    if show:\n        fig, ax = plt.subplots(figsize=(8, 8))\n        ax.set_xticks([]); ax.set_yticks([])\n        ax.imshow(make_grid(fake_images.cpu().detach(), nrow=8).permute(1, 2, 0))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fixed_latent = torch.randn(64, latent_size, 1, 1, device=device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm.notebook import tqdm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def fit(epochs, lr, start_idx=1):\n    torch.cuda.empty_cache()\n    \n    # Losses & scores\n    losses_g = []\n    losses_d = []\n    real_scores = []\n    fake_scores = []\n    \n    # Create optimizers\n    opt_d = torch.optim.Adam(discriminator.parameters(), lr=lr, betas=(0.5, 0.999))\n    opt_g = torch.optim.Adam(generator.parameters(), lr=lr, betas=(0.5, 0.999))\n    \n    for epoch in range(epochs):\n        for real_images, _ in tqdm(train_dl):\n            # Train discriminator\n            loss_d, real_score, fake_score = train_discriminator(real_images, opt_d)\n            # Train generator\n            loss_g = train_generator(opt_g)\n            \n        # Record losses & scores\n        losses_g.append(loss_g)\n        losses_d.append(loss_d)\n        real_scores.append(real_score)\n        fake_scores.append(fake_score)\n        \n        # Log losses & scores (last batch)\n        print(\"Epoch [{}/{}], loss_g: {:.4f}, loss_d: {:.4f}, real_score: {:.4f}, fake_score: {:.4f}\".format(\n            epoch+1, epochs, loss_g, loss_d, real_score, fake_score))\n    \n        # Save generated images\n        save_samples(epoch+start_idx, fixed_latent, show=False)\n    \n    return losses_g, losses_d, real_scores, fake_scores","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lr = 0.0002\nepochs = 25","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = fit(epochs, lr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"losses_g, losses_d, real_scores, fake_scores = history","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Save the model checkpoints \ntorch.save(generator.state_dict(), 'images.zip')\ntorch.save(discriminator.state_dict(), 'submission.csv')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(losses_d, '-')\nplt.plot(losses_g, '-')\nplt.xlabel('epoch')\nplt.ylabel('loss')\nplt.legend(['Discriminator', 'Generator'])\nplt.title('Losses');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(real_scores, '-')\nplt.plot(fake_scores, '-')\nplt.xlabel('epoch')\nplt.ylabel('score')\nplt.legend(['Real', 'Fake'])\nplt.title('Scores');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom subprocess import check_output\nprint(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import PIL\ndef predict_and_save(input_ds, generator_model, output_path):\n    i = 1\n    for img in input_ds:\n        prediction = generator_model(img, training=False)[0].numpy() # make predition\n        prediction = (prediction * 127.5 + 127.5).astype(np.uint8)   # re-scale\n        im = PIL.Image.fromarray(prediction)\n        im.save(f'{output_path}{str(i)}.jpg')\n        i += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import PIL\n! mkdir ../images","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}