{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"from __future__ import print_function, division\nimport os, time, glob, argparse\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom scipy.stats import truncnorm\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nfrom torch.autograd import Variable\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, utils, models\nfrom torchvision.utils import save_image\nfrom tqdm import tqdm_notebook as tqdm\nfrom PIL import Image\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\nplt.ion()   # interactive mode\nplt.rcParams['image.interpolation'] = 'nearest'\nmultiGPU = False","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"rootpath = \"../input/dog-breed-identification/\"\nTRAIN_IMG_PATH = rootpath + \"train\"\nTEST_IMG_PATH = rootpath + \"test\"\nLABELS_CSV_PATH = rootpath + \"labels.csv\"\nSAMPLE_SUB_PATH = rootpath + \"sample_submission.csv\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 重要参数\nworkers = 4\nbatch_size = 32\nimage_size = 128   #  try 64 and 128\nnc = 3          # number of channels, RGB image is 3\nnz = 128\nngf = 64\nndf = 64\nnum_epochs = 300 # 循环次数\nlr = 0.001      # learning rate\nbeta1 = 0.5     # momentum\nngpu = 1        # nubmer of gpu\nnum_show = 6\nn_class = 120   # number of classes\n\n# Decide which device we want to run on\ndevice = torch.device(\"cuda:0\" if (torch.cuda.is_available() and ngpu > 0) else \"cpu\")\nprint(device)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dataset and Daloader"},{"metadata":{"trusted":true},"cell_type":"code","source":"class DogsDataset(Dataset):\n    \"\"\"Dog breed identification dataset.\"\"\"\n\n    def __init__(self, img_dir, dataframe, transform=None):\n        \"\"\"\n        Args:\n            img_dir (string): Directory with all the images.        \n            dataframe (pandas.core.frame.DataFrame): Pandas dataframe obtained\n                by read_csv().\n            transform (callable, optional): Optional transform to be applied\n                on a sample.\n        \"\"\"\n        self.labels_frame = dataframe\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.labels_frame)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.img_dir, self.labels_frame.id[idx]) + \".jpg\"\n        image = Image.open(img_name)\n        label = self.labels_frame.target[idx]\n\n        if self.transform:\n            image = self.transform(image)\n\n        return [image, label]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dframe = pd.read_csv(LABELS_CSV_PATH)\nlabelnames = pd.read_csv(SAMPLE_SUB_PATH).keys()[1:]\ncodes = range(len(labelnames))\nbreed_to_code = dict(zip(labelnames, codes))\ncode_to_breed = dict(zip(codes, labelnames))\ndframe['target'] =  [breed_to_code[x] for x in dframe.breed]\n\ncut = int(len(dframe)*0.8)\ntrain, test = np.split(dframe, [cut], axis=0)\ntest = test.reset_index(drop=True)\n\ntrain_ds = DogsDataset(TRAIN_IMG_PATH, train)\ntest_ds = DogsDataset(TRAIN_IMG_PATH, test)\nidx = 29\nplt.imshow(train_ds[idx][0])\nprint(code_to_breed[train_ds[idx][1]])\nprint(\"Shape of the image is: \", train_ds[idx][0].size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# change random crop to resize+center crop\ndata_transform = transforms.Compose([\n        transforms.Resize(image_size),\n        transforms.RandomHorizontalFlip(),\n        transforms.CenterCrop(image_size),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                             std=[0.229, 0.224, 0.225])\n    ])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = DogsDataset(TRAIN_IMG_PATH, train, data_transform)\ntest_ds = DogsDataset(TRAIN_IMG_PATH, test, data_transform)\ndatasets = {\"train\": train_ds, \"val\": test_ds}\n\nidx = 29\nprint(code_to_breed[train_ds[idx][1]])\nprint(\"Shape of the image is: \", train_ds[idx][0].shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainloader = DataLoader(train_ds, batch_size=batch_size,\n                        shuffle=True, num_workers=workers)\n\ntestloader = DataLoader(test_ds, batch_size=batch_size,\n                        shuffle=True, num_workers=workers)\n\n#dataloaders = {\"train\": trainloader, \"val\": testloader}\ndataloaders = [trainloader, testloader]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# 网络模型参数的初始化\ndef weights_init(m):\n    classname = m.__class__.__name__\n    if classname.find('Conv') != -1:\n        nn.init.normal_(m.weight.data, 0.0, 0.02)\n    elif classname.find('BatchNorm') != -1:\n        nn.init.normal_(m.weight.data, 1.0, 0.02)\n        nn.init.constant_(m.bias.data, 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 生成网络定义\nclass Generator(nn.Module):\n\n    def __init__(self, ngpu, nz=nz, ngf=ngf, nc=nc, n_class=n_class):\n\n        super(Generator, self).__init__()\n        self.ngpu = ngpu\n        self.ReLU = nn.ReLU(True)\n        self.Tanh = nn.Tanh()\n        self.conv1 = nn.ConvTranspose2d(nz+n_class, ngf * 16, 4, 1, 0, bias=False)\n        self.BatchNorm1 = nn.BatchNorm2d(ngf * 16)\n\n        self.conv2 = nn.ConvTranspose2d(ngf * 16, ngf * 8, 4, 2, 1, bias=False)\n        self.BatchNorm2 = nn.BatchNorm2d(ngf * 8)\n\n        self.conv3 = nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False)\n        self.BatchNorm3 = nn.BatchNorm2d(ngf * 4)\n\n        self.conv4 = nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False)\n        self.BatchNorm4 = nn.BatchNorm2d(ngf * 2)\n        \n        self.conv5 = nn.ConvTranspose2d(ngf * 2, ngf * 1, 4, 2, 1, bias=False)\n        self.BatchNorm5 = nn.BatchNorm2d(ngf * 1)\n\n        self.conv6 = nn.ConvTranspose2d(ngf * 1, nc, 4, 2, 1, bias=False)\n\n        self.apply(weights_init)\n\n\n    def forward(self, input):\n\n        x = self.conv1(input)\n        x = self.BatchNorm1(x)\n        x = self.ReLU(x)\n\n        x = self.conv2(x)\n        x = self.BatchNorm2(x)\n        x = self.ReLU(x)\n\n        x = self.conv3(x)\n        x = self.BatchNorm3(x)\n        x = self.ReLU(x)\n\n        x = self.conv4(x)\n        x = self.BatchNorm4(x)\n        x = self.ReLU(x)\n        \n        x = self.conv5(x)\n        x = self.BatchNorm5(x)\n        x = self.ReLU(x)\n\n        x = self.conv6(x)\n        output = self.Tanh(x)\n        return output\n    \nnetG = Generator(ngpu).to(device)\nnetG.apply(weights_init)\nprint(netG)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 鉴别网络定义\nclass Discriminator(nn.Module):\n\n    def __init__(self, ngpu, ndf=ndf, nc=nc, n_class=n_class):\n\n        super(Discriminator, self).__init__()\n        self.LeakyReLU = nn.LeakyReLU(0.2, inplace=True)\n        self.conv1 = nn.Conv2d(nc, ndf, 4, 2, 1, bias=False)\n        self.conv2 = nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False)\n        self.BatchNorm2 = nn.BatchNorm2d(ndf * 2)\n        self.conv3 = nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False)\n        self.BatchNorm3 = nn.BatchNorm2d(ndf * 4)\n        self.conv4 = nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False)\n        self.BatchNorm4 = nn.BatchNorm2d(ndf * 8)\n        self.conv5 = nn.Conv2d(ndf * 8, ndf * 16, 4, 2, 1, bias=False)\n        self.BatchNorm5 = nn.BatchNorm2d(ndf * 16)\n        self.conv6 = nn.Conv2d(ndf * 16, ndf * 1, 4, 1, 0, bias=False)\n        self.disc_linear = nn.Linear(ndf * 1, 1)\n        self.aux_linear = nn.Linear(ndf * 1, n_class)\n        self.softmax = nn.Softmax()\n        self.sigmoid = nn.Sigmoid()\n        self.ndf = ndf\n        self.apply(weights_init)\n\n    def forward(self, input):\n\n        x = self.conv1(input)\n        x = self.LeakyReLU(x)\n        #print(x.shape)\n\n        x = self.conv2(x)\n        x = self.BatchNorm2(x)\n        x = self.LeakyReLU(x)\n        #print(x.shape)\n\n        x = self.conv3(x)\n        x = self.BatchNorm3(x)\n        x = self.LeakyReLU(x)\n        #print(x.shape)\n\n        x = self.conv4(x)\n        x = self.BatchNorm4(x)\n        x = self.LeakyReLU(x)\n        #print(x.shape)\n        \n        x = self.conv5(x)\n        x = self.BatchNorm5(x)\n        x = self.LeakyReLU(x)\n        #print(x.shape)\n\n        x = self.conv6(x)\n        #print(x.shape)\n        \n        x = x.view(-1, self.ndf * 1)\n        c = self.aux_linear(x)\n        c = self.softmax(c)\n        s = self.disc_linear(x)\n        s = self.sigmoid(s)\n        return s,c\n\nnetD = Discriminator(ngpu).to(device)\nnetD.apply(weights_init)\nprint(netD)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setup Adam optimizers for both G and D  优化器\noptimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))\noptimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Loss functions 损失函数\ns_criterion = nn.BCELoss()\nc_criterion = nn.NLLLoss()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"# 展示生成图像\ndef show_generated_img(num_show):\n    gen_images = []\n    for _ in range(num_show):\n        noise = torch.randn(1, nz, 1, 1, device=device)\n        dog_label = torch.randint(0, n_class, (1, ), device=device)\n        gen_image = concat_noise_label(noise, dog_label, device)\n        gen_image = netG(gen_image).to(\"cpu\").clone().detach().squeeze(0)\n        # gen_image = gen_image.numpy().transpose(0, 2, 3, 1)\n        gen_image = gen_image.numpy().transpose(1, 2, 0)\n        gen_images.append(gen_image)\n        \n    fig = plt.figure(figsize=(10, 5))\n    for i, gen_image in enumerate(gen_images):\n        ax = fig.add_subplot(1, num_show, i + 1, xticks=[], yticks=[])\n        plt.imshow(gen_image + 1 / 2)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def onehot_encode(label, device, n_class=n_class):  \n    eye = torch.eye(n_class, device=device) \n    return eye[label].view(-1, n_class, 1, 1)   \n \ndef concat_image_label(image, label, device, n_class=n_class):\n    B, C, H, W = image.shape   \n    oh_label = onehot_encode(label, device=device)\n    oh_label = oh_label.expand(B, n_class, H, W)\n    return torch.cat((image, oh_label), dim=1)\n \ndef concat_noise_label(noise, label, device):\n    oh_label = onehot_encode(label, device=device)\n    return torch.cat((noise, oh_label), dim=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"r_label = 0.7\nf_label = 0\n\ninput = torch.tensor([batch_size, nc, image_size, image_size], device=device)\nnoise = torch.tensor([batch_size, nz, 1, 1], device=device)\n\nfixed_noise = torch.randn(1, nz, 1, 1, device=device)\nfixed_label = torch.randint(0, n_class, (1, ), device=device)\nfixed_noise_label = concat_noise_label(fixed_noise, fixed_label, device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Training Loop\n\n# Lists to Keep track pf progress\nG_losses, D_losses = [], []\niters = 0\n\nprint(\"Starting Training Loop...\")\nfor epoch in range(num_epochs):\n    # training train and test datasets \n    for dataloader in dataloaders:  \n        for i, data in enumerate(dataloader):\n            # prepare real image and label\n            real_label = data[1].cuda()\n            real_image = data[0].cuda()\n            b_size = real_label.size(0)      \n        \n            # prepare fake image and label\n            fake_label = torch.randint(n_class, (b_size,), dtype=torch.long, device=device)\n            noise = torch.randn(b_size, nz, 1, 1, device=device).squeeze(0)\n            noise = concat_noise_label(noise, real_label, device)  \n            fake_image = netG(noise)\n        \n            # target\n            real_target = torch.full((b_size,), r_label, device=device)\n            fake_target = torch.full((b_size,), f_label, device=device)\n            \n            #-----------------------\n            # Update Discriminator\n            #-----------------------\n            netD.zero_grad()\n        \n            # train with real\n            s_output, c_output = netD(real_image)\n            \n            print(s_output.shape, real_target.shape)\n            s_errD_real = s_criterion(s_output, real_target)  # realfake\n            c_errD_real = c_criterion(c_output, real_label)  # class\n            errD_real = s_errD_real + c_errD_real\n            errD_real.backward()\n            D_x = s_output.data.mean()\n\n            # train with fake\n            s_output,c_output = netD(fake_image.detach())\n            s_errD_fake = s_criterion(s_output, fake_target)  # realfake\n            c_errD_fake = c_criterion(c_output, real_label)  # class\n            errD_fake = s_errD_fake + c_errD_fake\n            errD_fake.backward()\n            D_G_z1 = s_output.data.mean()\n        \n            errD = s_errD_real + s_errD_fake\n            optimizerD.step()        \n\n            #-----------------------\n            # Update Generator\n            #-----------------------\n            netG.zero_grad()\n        \n            s_output,c_output = netD(fake_image)\n            s_output.shape\n            real_target.shape\n            s_errG = s_criterion(s_output, real_target)  # realfake\n            c_errG = c_criterion(c_output, real_label)  # class\n            errG = s_errG + c_errG\n            errG.backward()\n            D_G_z2 = s_output.data.mean()\n        \n            optimizerG.step()\n\n            # Save Losses for plotting later\n            G_losses.append(errG.item())\n            D_losses.append(errD.item())\n        \n            iters += 1\n    \n    print('[%d/%d][%d/%d]\\nLoss_D: %.4f\\tLoss_G: %.4f\\nD(x): %.4f\\tD(G(z)): %.4f / %.4f'\n          % (epoch+1, num_epochs, i+1, len(dataloader), errD.item(), errG.item(), D_x, D_G_z1, D_G_z2))      \n    \n    if epoch%5 ==0:\n        show_generated_img(num_show)\n\n#     # --------- save fake image  ----------\n#     fake_image = netG(fixed_noise_label)   \n#     vutils.save_image(fake_image.detach(), '{}/fake_samples_epoch_{:03d}.png'.format(outf, epoch + 1),\n#                     normalize=True, nrow=5)\n \n#     # ---------  save model  ----------\n#     if (epoch + 1) % 10 == 0:  \n#         torch.save(netG.state_dict(), '{}/netG_epoch_{}.pth'.format(outf, epoch + 1))\n#         torch.save(netD.state_dict(), '{}/netD_epoch_{}.pth'.format(outf, epoch + 1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## Testing"},{"metadata":{"trusted":true},"cell_type":"code","source":"def mse(imageA, imageB):\n    err = np.sum((imageA.astype(\"float\") - imageB.astype(\"float\")) ** 2)\n    err /= float(imageA.shape[0] * imageA.shape[1])\n    return err\n\ndef analyse_generated_by_class(n_images):\n    good_breeds = []\n    for l in range(n_class):\n        sample = []\n        for _ in range(n_images):\n            noise = torch.randn(1, nz, 1, 1, device=device)\n            dog_label = l\n            noise_label = concat_noise_label(noise, dog_label, device)\n            gen_image = netG(noise_label).to(\"cpu\").clone().detach().squeeze(0)\n            gen_image = gen_image.numpy().transpose(1, 2, 0)\n            sample.append(gen_image)\n\n        d = np.round(np.sum([mse(sample[k], sample[k + 1]) for k in range(len(sample) - 1)]) / n_images, 1,)\n        if d < 1.0:\n            continue  # had mode colapse(discard)\n            \n        print(f\"Generated breed({d}): \", code_to_breed[l])    \n        good_breeds.append(l)\n    return good_breeds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_generated_img_all():\n    dog_label = torch.randint(n_class, (64,), dtype=torch.long, device=device)\n    noise = torch.randn(64, nz, 1, 1, device=device)\n    gen_image = concat_noise_label(noise, dog_label, device)  \n    gen_image = netG(gen_image).to(\"cpu\").clone().detach().squeeze(0)\n    gen_image = gen_image.numpy().transpose(0, 2, 3, 1)\n    # gen_image = gen_image.numpy().transpose(1, 2, 0)\n    gen_image = (gen_image + 1.0) / 2.0\n    \n    fig = plt.figure(figsize=(25, 16))\n    for ii, img in enumerate(gen_image):\n        ax = fig.add_subplot(8, 8, ii + 1, xticks=[], yticks=[])\n        plt.imshow(img)\n        \ndef show_loss(ylim): \n    sns.set_style(\"white\")\n    fig = plt.figure(figsize=(10,5))\n    ax = fig.add_subplot(1,1,1)\n    ax.set_title(\"Generator and Discriminator Loss During Training\")\n    ax.plot(G_losses,label=\"G\",c=\"b\")\n    ax.plot(D_losses,label=\"D\",c=\"r\")\n    ax.set_xlabel(\"iterations\")\n    ax.set_ylabel(\"Loss\")\n    ax.legend()\n    if ylim == True:\n        ax.set_ylim(0,4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def truncated_normal(size, threshold=1):\n    values = truncnorm.rvs(-threshold, threshold, size=size)\n    return values\n\ndef create_submit(good_breeds):\n    print(\"Creating submit\")\n    os.makedirs(\"../output_images\", exist_ok=True)\n    im_batch_size = 100\n    n_images = 10000\n\n    for i_batch in range(0, n_images, im_batch_size):\n        z = truncated_normal((im_batch_size, nz, 1, 1), threshold=1)\n        noise = torch.from_numpy(z).float().to(device)\n        \n        dog_label = np.random.choice(good_breeds, size=im_batch_size, replace=True) \n        dog_label = torch.from_numpy(dog_label).to(device).clone().detach().squeeze(0)\n        noise_label = concat_noise_label(noise, dog_label, device)\n    \n        gen_images = (netG(noise_label) + 1) / 2\n        \n        for i_image in range(gen_images.size(0)):\n            save_image(gen_images[i_image, :, :, :], os.path.join('../output_images', f'image_{i_batch+i_image:05d}.png'))\n\n    import shutil\n    shutil.make_archive(\"images\", \"zip\", \"../output_images\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# loss curve\n\nshow_loss(ylim=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# loss curve\n\nshow_loss(ylim=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# analysis\ngood_breeds = analyse_generated_by_class(6)\n#create_submit(good_breeds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"show_generated_img_all()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualization generate image of all breeds \n\nfig = plt.figure(figsize=(20,40))\nfor i in range(n_class):\n    ax = fig.add_subplot(20,6,i+1)\n    noise = torch.randn(1, nz, 1, 1, device=device)\n    dog_label = i\n    noise_label = concat_noise_label(noise, dog_label, device)\n    gen_image = netG(noise_label).to(\"cpu\").clone().detach().squeeze(0)\n    # gen_image = gen_image.numpy().transpose(0, 2, 3, 1)\n    gen_image = gen_image.numpy().transpose(1, 2, 0)\n    gen_image = (gen_image + 1.0) / 2.0\n    ax.axis('off')\n    ax.set_title(code_to_breed[i])\n    ax.imshow(gen_image, cmap=\"gray\")\nplt.tight_layout()\nplt.show() ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}