├── .gitignore ├── CARS └── DCGAN.ipynb ├── CelebA ├── BEGAN.ipynb └── R1GAN.ipynb ├── MNIST ├── Conditional-DCGAN.ipynb ├── Conditional-GAN.ipynb ├── DCGAN.ipynb ├── VanillaGAN.ipynb ├── W-GAN.ipynb ├── WGAN-GP.ipynb └── infoGAN.ipynb ├── README.md └── images ├── BEGAN.jpg ├── CGAN.jpg ├── Conditional-DCGAN.gif ├── Conditional-GAN.gif ├── DCGAN.jpg ├── R1GAN-interp.jpg ├── R1GAN-sample1.jpg ├── R1GAN.jpg ├── Vanilla-GAN.gif ├── VanillaGAN.jpg ├── WGAN-gp.gif ├── WGAN-gp.jpg ├── colab-usage.JPG ├── infoGAN_type1.jpg ├── infoGAN_type2.jpg └── interpolation.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | */.ipynb_checkpoints 2 | */__pycache__ 3 | */ckpt 4 | */samples 5 | */*bak 6 | data 7 | .ipynb_checkpoints -------------------------------------------------------------------------------- /CARS/DCGAN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Implementation of Deep Convolutional GANs\n", 8 | "Reference: https://arxiv.org/pdf/1511.06434.pdf" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": { 15 | "collapsed": true 16 | }, 17 | "outputs": [], 18 | "source": [ 19 | "# Run the comment below only when using Google Colab\n", 20 | "# !pip install torch torchvision" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": { 27 | "collapsed": true 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "import torch\n", 32 | "import torchvision\n", 33 | "import torch.nn as nn\n", 34 | "import torch.nn.functional as F" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 2, 40 | "metadata": { 41 | "collapsed": true 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "from torch.utils.data import DataLoader\n", 46 | "from torch.utils.data.dataset import Dataset\n", 47 | "from torchvision import datasets\n", 48 | "from torchvision import transforms\n", 49 | "from torchvision.utils import save_image" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "metadata": { 56 | "collapsed": true 57 | }, 58 | "outputs": [], 59 | "source": [ 60 | "import numpy as np\n", 61 | "import datetime\n", 62 | "import os, sys" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 4, 68 | "metadata": { 69 | "collapsed": true 70 | }, 71 | "outputs": [], 72 | "source": [ 73 | "import glob" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 5, 79 | "metadata": { 80 | "collapsed": true 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "from PIL import Image" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 6, 90 | "metadata": { 91 | "collapsed": true 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "from matplotlib.pyplot import imshow, imsave\n", 96 | "%matplotlib inline" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 7, 102 | "metadata": { 103 | "collapsed": true 104 | }, 105 | "outputs": [], 106 | "source": [ 107 | "MODEL_NAME = 'DCGAN'\n", 108 | "DEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": true 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "IMAGE_DIM = (32, 32, 3)" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 8, 125 | "metadata": { 126 | "collapsed": true 127 | }, 128 | "outputs": [], 129 | "source": [ 130 | "def get_sample_image(G, n_noise):\n", 131 | " \"\"\"\n", 132 | " save sample 100 images\n", 133 | " \"\"\"\n", 134 | " z = torch.randn(10, n_noise).to(DEVICE)\n", 135 | " y_hat = G(z).view(10, 3, 28, 28).permute(0, 2, 3, 1) # (100, 28, 28)\n", 136 | " result = (y_hat.detach().cpu().numpy()+1)/2.\n", 137 | " return result" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 9, 143 | "metadata": { 144 | "collapsed": true 145 | }, 146 | "outputs": [], 147 | "source": [ 148 | "class Discriminator(nn.Module):\n", 149 | " \"\"\"\n", 150 | " Convolutional Discriminator for MNIST\n", 151 | " \"\"\"\n", 152 | " def __init__(self, in_channel=1, num_classes=1):\n", 153 | " super(Discriminator, self).__init__()\n", 154 | " self.conv = nn.Sequential(\n", 155 | " # 28 -> 14\n", 156 | " nn.Conv2d(in_channel, 512, 3, stride=2, padding=1, bias=False),\n", 157 | " nn.BatchNorm2d(512),\n", 158 | " nn.LeakyReLU(0.2),\n", 159 | " # 14 -> 7\n", 160 | " nn.Conv2d(512, 256, 3, stride=2, padding=1, bias=False),\n", 161 | " nn.BatchNorm2d(256),\n", 162 | " nn.LeakyReLU(0.2),\n", 163 | " # 7 -> 4\n", 164 | " nn.Conv2d(256, 128, 3, stride=2, padding=1, bias=False),\n", 165 | " nn.BatchNorm2d(128),\n", 166 | " nn.LeakyReLU(0.2),\n", 167 | " # \n", 168 | " nn.Conv2d(128, 128, 3, stride=2, padding=1, bias=False),\n", 169 | " nn.BatchNorm2d(128),\n", 170 | " nn.LeakyReLU(0.2),\n", 171 | " nn.AdaptiveAvgPool2d(1),\n", 172 | " ) \n", 173 | " self.fc = nn.Sequential(\n", 174 | " # reshape input, 128 -> 1\n", 175 | " nn.Linear(128, 1),\n", 176 | " nn.Sigmoid(),\n", 177 | " )\n", 178 | " \n", 179 | " def forward(self, x, y=None):\n", 180 | " y_ = self.conv(x)\n", 181 | " y_ = y_.view(y_.size(0), -1)\n", 182 | " y_ = self.fc(y_)\n", 183 | " return y_" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 10, 189 | "metadata": { 190 | "collapsed": true 191 | }, 192 | "outputs": [], 193 | "source": [ 194 | "class Generator(nn.Module):\n", 195 | " \"\"\"\n", 196 | " Convolutional Generator for MNIST\n", 197 | " \"\"\"\n", 198 | " def __init__(self, out_channel=1, input_size=100, num_classes=784):\n", 199 | " super(Generator, self).__init__()\n", 200 | " assert IMAGE_DIM[0] % 2**4 == 0, 'Should be divided 16'\n", 201 | " self.init_dim = (IMAGE_DIM[0] // 2**4, IMAGE_DIM[1] // 2**4)\n", 202 | " self.fc = nn.Sequential(\n", 203 | " nn.Linear(input_size, self.init_dim[0]*self.init_dim[1]*512),\n", 204 | " nn.ReLU(),\n", 205 | " )\n", 206 | " self.conv = nn.Sequential(\n", 207 | " nn.Conv2d(512, 512, 3, padding=1, bias=False),\n", 208 | " nn.BatchNorm2d(512),\n", 209 | " nn.ReLU(),\n", 210 | " # x2\n", 211 | " nn.ConvTranspose2d(512, 256, 4, stride=2, padding=1, bias=False),\n", 212 | " nn.BatchNorm2d(256),\n", 213 | " nn.ReLU(),\n", 214 | " # x2\n", 215 | " nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1, bias=False),\n", 216 | " nn.BatchNorm2d(128),\n", 217 | " nn.ReLU(),\n", 218 | " # x2\n", 219 | " nn.ConvTranspose2d(128, 128, 4, stride=2, padding=1, bias=False),\n", 220 | " nn.BatchNorm2d(128),\n", 221 | " nn.ReLU(),\n", 222 | " # x2\n", 223 | " nn.ConvTranspose2d(128, out_channel, 4, stride=2, padding=1, bias=False),\n", 224 | " nn.Tanh(),\n", 225 | " )\n", 226 | " \n", 227 | " def forward(self, x, y=None):\n", 228 | " x = x.view(x.size(0), -1)\n", 229 | " y_ = self.fc(x)\n", 230 | " y_ = y_.view(y_.size(0), 512, self.init_dim[0], self.init_dim[1])\n", 231 | " y_ = self.conv(y_)\n", 232 | " return y_" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 11, 238 | "metadata": { 239 | "collapsed": true 240 | }, 241 | "outputs": [], 242 | "source": [ 243 | "class CARS(Dataset):\n", 244 | " '''\n", 245 | " CARS Dataset\n", 246 | " You should download this dataset from below url.\n", 247 | " url: https://ai.stanford.edu/~jkrause/cars/car_dataset.html\n", 248 | " '''\n", 249 | " def __init__(self, data_path, transform=None):\n", 250 | " '''\n", 251 | " Args:\n", 252 | " data_path (str): path to dataset\n", 253 | " '''\n", 254 | " self.data_path = data_path\n", 255 | " self.transform = transform\n", 256 | " self.fpaths = sorted(glob.glob(os.path.join(data_path, '*.jpg')))\n", 257 | " gray_lst = [266, 1085, 2176, 3048, 3439, 3469, 3539, 4577, 4848, 5177, 5502, 5713, 6947, 7383, 7693, 7774, 8137, 8144]\n", 258 | " for num in gray_lst:\n", 259 | " self.fpaths.remove(os.path.join(data_path, '{:05d}.jpg'.format(num)))\n", 260 | " \n", 261 | " def __getitem__(self, idx):\n", 262 | " img = self.transform(Image.open(self.fpaths[idx]))\n", 263 | " return img\n", 264 | "\n", 265 | " def __len__(self):\n", 266 | " return len(self.fpaths)" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": 12, 272 | "metadata": { 273 | "collapsed": true 274 | }, 275 | "outputs": [], 276 | "source": [ 277 | "D = Discriminator(in_channel=IMAGE_DIM[-1]).to(DEVICE)\n", 278 | "G = Generator(out_channel=IMAGE_DIM[-1]).to(DEVICE)\n", 279 | "# D.load_state_dict('D_dc.pkl')\n", 280 | "# G.load_state_dict('G_dc.pkl')" 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": 13, 286 | "metadata": { 287 | "collapsed": true 288 | }, 289 | "outputs": [], 290 | "source": [ 291 | "transform = transforms.Compose([transforms.Resize((IMAGE_DIM[0],IMAGE_DIM[1])),\n", 292 | " transforms.ToTensor(),\n", 293 | " transforms.Normalize(mean=(0.5, 0.5, 0.5),\n", 294 | " std=(0.5, 0.5, 0.5))\n", 295 | " ]\n", 296 | ")" 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": 14, 302 | "metadata": { 303 | "collapsed": true 304 | }, 305 | "outputs": [], 306 | "source": [ 307 | "dataset = CARS(data_path='/home/yangyangii/git/cars_train', transform=transform)" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 15, 313 | "metadata": { 314 | "collapsed": true 315 | }, 316 | "outputs": [], 317 | "source": [ 318 | "batch_size = 64" 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": 16, 324 | "metadata": { 325 | "collapsed": true 326 | }, 327 | "outputs": [], 328 | "source": [ 329 | "data_loader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True, drop_last=True, num_workers=8)" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 17, 335 | "metadata": { 336 | "collapsed": true 337 | }, 338 | "outputs": [], 339 | "source": [ 340 | "criterion = nn.BCELoss()\n", 341 | "D_opt = torch.optim.Adam(D.parameters(), lr=0.001, betas=(0.5, 0.999))\n", 342 | "G_opt = torch.optim.Adam(G.parameters(), lr=0.001, betas=(0.5, 0.999))" 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": 18, 348 | "metadata": { 349 | "collapsed": true 350 | }, 351 | "outputs": [], 352 | "source": [ 353 | "max_epoch = 100\n", 354 | "step = 0\n", 355 | "n_critic = 1 # for training more k steps about Discriminator\n", 356 | "n_noise = 100" 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": 19, 362 | "metadata": { 363 | "collapsed": true 364 | }, 365 | "outputs": [], 366 | "source": [ 367 | "D_labels = torch.ones([batch_size, 1]).to(DEVICE) # Discriminator Label to real\n", 368 | "D_fakes = torch.zeros([batch_size, 1]).to(DEVICE) # Discriminator Label to fake" 369 | ] 370 | }, 371 | { 372 | "cell_type": "code", 373 | "execution_count": 20, 374 | "metadata": { 375 | "scrolled": true 376 | }, 377 | "outputs": [ 378 | { 379 | "name": "stdout", 380 | "output_type": "stream", 381 | "text": [ 382 | "Epoch: 0/100, Step: 0, D Loss: 1.3999, G Loss: 0.6180, Time:16:46:45\n", 383 | "Epoch: 3/100, Step: 500, D Loss: 1.1598, G Loss: 1.0826, Time:16:47:35\n", 384 | "Epoch: 7/100, Step: 1000, D Loss: 0.9844, G Loss: 0.9956, Time:16:48:25\n", 385 | "Epoch: 11/100, Step: 1500, D Loss: 0.9111, G Loss: 1.1050, Time:16:49:16\n", 386 | "Epoch: 15/100, Step: 2000, D Loss: 0.8433, G Loss: 1.1394, Time:16:50:06\n", 387 | "Epoch: 19/100, Step: 2500, D Loss: 1.0972, G Loss: 1.2265, Time:16:50:56\n", 388 | "Epoch: 23/100, Step: 3000, D Loss: 0.9124, G Loss: 1.1806, Time:16:51:47\n", 389 | "Epoch: 27/100, Step: 3500, D Loss: 0.7294, G Loss: 1.5435, Time:16:52:38\n", 390 | "Epoch: 31/100, Step: 4000, D Loss: 0.8479, G Loss: 1.4291, Time:16:53:29\n", 391 | "Epoch: 35/100, Step: 4500, D Loss: 0.7055, G Loss: 1.6143, Time:16:54:21\n", 392 | "Epoch: 39/100, Step: 5000, D Loss: 0.5880, G Loss: 1.8291, Time:16:55:12\n", 393 | "Epoch: 43/100, Step: 5500, D Loss: 0.7331, G Loss: 2.0989, Time:16:56:03\n", 394 | "Epoch: 47/100, Step: 6000, D Loss: 1.1191, G Loss: 0.4572, Time:16:56:54\n", 395 | "Epoch: 51/100, Step: 6500, D Loss: 0.5204, G Loss: 2.0754, Time:16:57:45\n", 396 | "Epoch: 55/100, Step: 7000, D Loss: 0.7635, G Loss: 1.3319, Time:16:58:38\n", 397 | "Epoch: 59/100, Step: 7500, D Loss: 0.7345, G Loss: 1.4658, Time:16:59:36\n", 398 | "Epoch: 63/100, Step: 8000, D Loss: 0.5926, G Loss: 2.2090, Time:17:00:32\n", 399 | "Epoch: 67/100, Step: 8500, D Loss: 0.4818, G Loss: 2.0671, Time:17:01:30\n", 400 | "Epoch: 71/100, Step: 9000, D Loss: 0.5194, G Loss: 2.1079, Time:17:02:28\n", 401 | "Epoch: 75/100, Step: 9500, D Loss: 0.4987, G Loss: 1.7474, Time:17:03:25\n", 402 | "Epoch: 79/100, Step: 10000, D Loss: 0.4036, G Loss: 2.1554, Time:17:04:23\n", 403 | "Epoch: 83/100, Step: 10500, D Loss: 1.2285, G Loss: 3.0286, Time:17:05:22\n", 404 | "Epoch: 87/100, Step: 11000, D Loss: 0.3730, G Loss: 2.3211, Time:17:06:19\n", 405 | "Epoch: 91/100, Step: 11500, D Loss: 0.3307, G Loss: 2.4072, Time:17:07:14\n", 406 | "Epoch: 95/100, Step: 12000, D Loss: 0.4987, G Loss: 3.4012, Time:17:08:12\n", 407 | "Epoch: 99/100, Step: 12500, D Loss: 0.4947, G Loss: 3.2567, Time:17:09:09\n" 408 | ] 409 | } 410 | ], 411 | "source": [ 412 | "for epoch in range(max_epoch):\n", 413 | " for idx, images in enumerate(data_loader):\n", 414 | " # Training Discriminator\n", 415 | " x = images.to(DEVICE)\n", 416 | " x_outputs = D(x)\n", 417 | " D_x_loss = criterion(x_outputs, D_labels)\n", 418 | "\n", 419 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 420 | " z_outputs = D(G(z))\n", 421 | " D_z_loss = criterion(z_outputs, D_fakes)\n", 422 | " D_loss = D_x_loss + D_z_loss\n", 423 | " \n", 424 | " D.zero_grad()\n", 425 | " D_loss.backward()\n", 426 | " D_opt.step()\n", 427 | "\n", 428 | " if step % n_critic == 0:\n", 429 | " # Training Generator\n", 430 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 431 | " z_outputs = D(G(z))\n", 432 | " G_loss = criterion(z_outputs, D_labels)\n", 433 | "\n", 434 | " D.zero_grad()\n", 435 | " G.zero_grad()\n", 436 | " G_loss.backward()\n", 437 | " G_opt.step()\n", 438 | " \n", 439 | " if step % 500 == 0:\n", 440 | " dt = datetime.datetime.now().strftime('%H:%M:%S')\n", 441 | " print('Epoch: {}/{}, Step: {}, D Loss: {:.4f}, G Loss: {:.4f}, Time:{}'.format(epoch, max_epoch, step, D_loss.item(), G_loss.item(), dt))\n", 442 | " G.eval()\n", 443 | " img = get_sample_image(G, n_noise)\n", 444 | " imsave('samples/{}_step{:05d}.jpg'.format(MODEL_NAME, step), img[0])\n", 445 | " G.train()\n", 446 | " step += 1" 447 | ] 448 | }, 449 | { 450 | "cell_type": "code", 451 | "execution_count": null, 452 | "metadata": { 453 | "collapsed": true 454 | }, 455 | "outputs": [], 456 | "source": [] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "metadata": {}, 461 | "source": [ 462 | "## Sample" 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "execution_count": 36, 468 | "metadata": {}, 469 | "outputs": [ 470 | { 471 | "data": { 472 | "text/plain": [ 473 | "" 474 | ] 475 | }, 476 | "execution_count": 36, 477 | "metadata": {}, 478 | "output_type": "execute_result" 479 | }, 480 | { 481 | "data": { 482 | "image/png": "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\n", 483 | "text/plain": [ 484 | "" 485 | ] 486 | }, 487 | "metadata": {}, 488 | "output_type": "display_data" 489 | } 490 | ], 491 | "source": [ 492 | "# generation to image\n", 493 | "G.eval()\n", 494 | "imshow(get_sample_image(G, n_noise)[0])" 495 | ] 496 | }, 497 | { 498 | "cell_type": "code", 499 | "execution_count": 38, 500 | "metadata": {}, 501 | "outputs": [ 502 | { 503 | "data": { 504 | "text/plain": [ 505 | "" 506 | ] 507 | }, 508 | "execution_count": 38, 509 | "metadata": {}, 510 | "output_type": "execute_result" 511 | }, 512 | { 513 | "data": { 514 | "image/png": "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\nAAAAAElFTkSuQmCC\n", 515 | "text/plain": [ 516 | "" 517 | ] 518 | }, 519 | "metadata": {}, 520 | "output_type": "display_data" 521 | } 522 | ], 523 | "source": [ 524 | "# Real Image\n", 525 | "t = Image.open(dataset.fpaths[999])\n", 526 | "t = (transform(t).permute(1, 2, 0)+1)/2.\n", 527 | "imshow(t)" 528 | ] 529 | }, 530 | { 531 | "cell_type": "code", 532 | "execution_count": null, 533 | "metadata": { 534 | "collapsed": true 535 | }, 536 | "outputs": [], 537 | "source": [] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "execution_count": 15, 542 | "metadata": { 543 | "collapsed": true 544 | }, 545 | "outputs": [], 546 | "source": [ 547 | "def save_checkpoint(state, file_name='checkpoint.pth.tar'):\n", 548 | " torch.save(state, file_name)" 549 | ] 550 | }, 551 | { 552 | "cell_type": "code", 553 | "execution_count": 16, 554 | "metadata": { 555 | "collapsed": true 556 | }, 557 | "outputs": [], 558 | "source": [ 559 | "# Saving params.\n", 560 | "# torch.save(D.state_dict(), 'D_c.pkl')\n", 561 | "# torch.save(G.state_dict(), 'G_c.pkl')\n", 562 | "save_checkpoint({'epoch': epoch + 1,\n", 563 | " 'D':D.state_dict(),\n", 564 | " 'G':G.state_dict(),\n", 565 | " 'd_optim': D_opt.state_dict(),\n", 566 | " 'g_optim' : G_opt.state_dict()},\n", 567 | " 'dcgan.pth.tar')" 568 | ] 569 | }, 570 | { 571 | "cell_type": "code", 572 | "execution_count": null, 573 | "metadata": { 574 | "collapsed": true 575 | }, 576 | "outputs": [], 577 | "source": [] 578 | } 579 | ], 580 | "metadata": { 581 | "kernelspec": { 582 | "display_name": "Python 3", 583 | "language": "python", 584 | "name": "python3" 585 | }, 586 | "language_info": { 587 | "codemirror_mode": { 588 | "name": "ipython", 589 | "version": 3 590 | }, 591 | "file_extension": ".py", 592 | "mimetype": "text/x-python", 593 | "name": "python", 594 | "nbconvert_exporter": "python", 595 | "pygments_lexer": "ipython3", 596 | "version": "3.6.3" 597 | } 598 | }, 599 | "nbformat": 4, 600 | "nbformat_minor": 2 601 | } 602 | -------------------------------------------------------------------------------- /MNIST/Conditional-DCGAN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Implementation of Deep Convolutional GANs\n", 8 | "Reference: https://arxiv.org/pdf/1511.06434.pdf" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": { 15 | "collapsed": true 16 | }, 17 | "outputs": [], 18 | "source": [ 19 | "# Run the comment below only when using Google Colab\n", 20 | "# !pip install torch torchvision" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": { 27 | "collapsed": true 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "import torch\n", 32 | "import torchvision\n", 33 | "import torch.nn as nn\n", 34 | "import torch.nn.functional as F" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 2, 40 | "metadata": { 41 | "collapsed": true 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "from torch.utils.data import DataLoader\n", 46 | "from torchvision import datasets\n", 47 | "from torchvision import transforms\n", 48 | "from torchvision.utils import save_image" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": { 55 | "collapsed": true 56 | }, 57 | "outputs": [], 58 | "source": [ 59 | "import numpy as np\n", 60 | "import datetime\n", 61 | "import os, sys" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 4, 67 | "metadata": { 68 | "collapsed": true 69 | }, 70 | "outputs": [], 71 | "source": [ 72 | "from matplotlib.pyplot import imshow, imsave\n", 73 | "%matplotlib inline" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 5, 79 | "metadata": { 80 | "collapsed": true 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "MODEL_NAME = 'Conditional-DCGAN'\n", 85 | "DEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 6, 91 | "metadata": { 92 | "collapsed": true 93 | }, 94 | "outputs": [], 95 | "source": [ 96 | "def to_onehot(x, num_classes=10):\n", 97 | " assert isinstance(x, int) or isinstance(x, (torch.LongTensor, torch.cuda.LongTensor))\n", 98 | " if isinstance(x, int):\n", 99 | " c = torch.zeros(1, num_classes).long()\n", 100 | " c[0][x] = 1\n", 101 | " else:\n", 102 | " x = x.cpu()\n", 103 | " c = torch.LongTensor(x.size(0), num_classes)\n", 104 | " c.zero_()\n", 105 | " c.scatter_(1, x, 1) # dim, index, src value\n", 106 | " return c" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 7, 112 | "metadata": { 113 | "collapsed": true 114 | }, 115 | "outputs": [], 116 | "source": [ 117 | "def get_sample_image(G, n_noise=100):\n", 118 | " \"\"\"\n", 119 | " save sample 100 images\n", 120 | " \"\"\"\n", 121 | " img = np.zeros([280, 280])\n", 122 | " for j in range(10):\n", 123 | " c = torch.zeros([10, 10]).to(DEVICE)\n", 124 | " c[:, j] = 1\n", 125 | " z = torch.randn(10, n_noise).to(DEVICE)\n", 126 | " y_hat = G(z,c).view(10, 28, 28)\n", 127 | " result = y_hat.cpu().data.numpy()\n", 128 | " img[j*28:(j+1)*28] = np.concatenate([x for x in result], axis=-1)\n", 129 | " return img" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 8, 135 | "metadata": { 136 | "collapsed": true 137 | }, 138 | "outputs": [], 139 | "source": [ 140 | "class Discriminator(nn.Module):\n", 141 | " \"\"\"\n", 142 | " Convolutional Discriminator for MNIST\n", 143 | " \"\"\"\n", 144 | " def __init__(self, in_channel=1, input_size=784, condition_size=10, num_classes=1):\n", 145 | " super(Discriminator, self).__init__()\n", 146 | " self.transform = nn.Sequential(\n", 147 | " nn.Linear(input_size+condition_size, 784),\n", 148 | " nn.LeakyReLU(0.2),\n", 149 | " )\n", 150 | " self.conv = nn.Sequential(\n", 151 | " # 28 -> 14\n", 152 | " nn.Conv2d(in_channel, 512, 3, stride=2, padding=1, bias=False),\n", 153 | " nn.BatchNorm2d(512),\n", 154 | " nn.LeakyReLU(0.2),\n", 155 | " # 14 -> 7\n", 156 | " nn.Conv2d(512, 256, 3, stride=2, padding=1, bias=False),\n", 157 | " nn.BatchNorm2d(256),\n", 158 | " nn.LeakyReLU(0.2),\n", 159 | " # 7 -> 4\n", 160 | " nn.Conv2d(256, 128, 3, stride=2, padding=1, bias=False),\n", 161 | " nn.BatchNorm2d(128),\n", 162 | " nn.LeakyReLU(0.2),\n", 163 | " nn.AvgPool2d(4),\n", 164 | " )\n", 165 | " self.fc = nn.Sequential(\n", 166 | " # reshape input, 128 -> 1\n", 167 | " nn.Linear(128, 1),\n", 168 | " nn.Sigmoid(),\n", 169 | " )\n", 170 | " \n", 171 | " def forward(self, x, c=None):\n", 172 | " # x: (N, 1, 28, 28), c: (N, 10)\n", 173 | " x, c = x.view(x.size(0), -1), c.float() # may not need\n", 174 | " v = torch.cat((x, c), 1) # v: (N, 794)\n", 175 | " y_ = self.transform(v) # (N, 784)\n", 176 | " y_ = y_.view(y_.shape[0], 1, 28, 28) # (N, 1, 28, 28)\n", 177 | " y_ = self.conv(y_)\n", 178 | " y_ = y_.view(y_.size(0), -1)\n", 179 | " y_ = self.fc(y_)\n", 180 | " return y_" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 9, 186 | "metadata": { 187 | "collapsed": true 188 | }, 189 | "outputs": [], 190 | "source": [ 191 | "class Generator(nn.Module):\n", 192 | " \"\"\"\n", 193 | " Convolutional Generator for MNIST\n", 194 | " \"\"\"\n", 195 | " def __init__(self, input_size=100, condition_size=10):\n", 196 | " super(Generator, self).__init__()\n", 197 | " self.fc = nn.Sequential(\n", 198 | " nn.Linear(input_size+condition_size, 4*4*512),\n", 199 | " nn.ReLU(),\n", 200 | " )\n", 201 | " self.conv = nn.Sequential(\n", 202 | " # input: 4 by 4, output: 7 by 7\n", 203 | " nn.ConvTranspose2d(512, 256, 3, stride=2, padding=1, bias=False),\n", 204 | " nn.BatchNorm2d(256),\n", 205 | " nn.ReLU(),\n", 206 | " # input: 7 by 7, output: 14 by 14\n", 207 | " nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1, bias=False),\n", 208 | " nn.BatchNorm2d(128),\n", 209 | " nn.ReLU(),\n", 210 | " # input: 14 by 14, output: 28 by 28\n", 211 | " nn.ConvTranspose2d(128, 1, 4, stride=2, padding=1, bias=False),\n", 212 | " nn.Tanh(),\n", 213 | " )\n", 214 | " \n", 215 | " def forward(self, x, c):\n", 216 | " # x: (N, 100), c: (N, 10)\n", 217 | " x, c = x.view(x.size(0), -1), c.float() # may not need\n", 218 | " v = torch.cat((x, c), 1) # v: (N, 110)\n", 219 | " y_ = self.fc(v)\n", 220 | " y_ = y_.view(y_.size(0), 512, 4, 4)\n", 221 | " y_ = self.conv(y_) # (N, 28, 28)\n", 222 | " return y_" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 10, 228 | "metadata": { 229 | "collapsed": true 230 | }, 231 | "outputs": [], 232 | "source": [ 233 | "D = Discriminator().to(DEVICE)\n", 234 | "G = Generator().to(DEVICE)\n", 235 | "# D.load_state_dict('D_dc.pkl')\n", 236 | "# G.load_state_dict('G_dc.pkl')" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 11, 242 | "metadata": { 243 | "collapsed": true 244 | }, 245 | "outputs": [], 246 | "source": [ 247 | "transform = transforms.Compose([transforms.ToTensor(),\n", 248 | " transforms.Normalize(mean=[0.5],\n", 249 | " std=[0.5])]\n", 250 | ")" 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": 12, 256 | "metadata": { 257 | "collapsed": true 258 | }, 259 | "outputs": [], 260 | "source": [ 261 | "mnist = datasets.MNIST(root='../data/', train=True, transform=transform, download=True)" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 13, 267 | "metadata": { 268 | "collapsed": true 269 | }, 270 | "outputs": [], 271 | "source": [ 272 | "batch_size = 64" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 14, 278 | "metadata": { 279 | "collapsed": true 280 | }, 281 | "outputs": [], 282 | "source": [ 283 | "data_loader = DataLoader(dataset=mnist, batch_size=batch_size, shuffle=True, drop_last=True, pin_memory=True)" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": 15, 289 | "metadata": { 290 | "collapsed": true 291 | }, 292 | "outputs": [], 293 | "source": [ 294 | "criterion = nn.BCELoss()\n", 295 | "D_opt = torch.optim.Adam(D.parameters(), lr=0.0005, betas=(0.5, 0.999))\n", 296 | "G_opt = torch.optim.Adam(G.parameters(), lr=0.0005, betas=(0.5, 0.999))" 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": 16, 302 | "metadata": { 303 | "collapsed": true 304 | }, 305 | "outputs": [], 306 | "source": [ 307 | "max_epoch = 30 # need more than 20 epochs for training generator\n", 308 | "step = 0\n", 309 | "n_critic = 1 # for training more k steps about Discriminator\n", 310 | "n_noise = 100" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 17, 316 | "metadata": { 317 | "collapsed": true 318 | }, 319 | "outputs": [], 320 | "source": [ 321 | "D_labels = torch.ones([batch_size, 1]).to(DEVICE) # Discriminator Label to real\n", 322 | "D_fakes = torch.zeros([batch_size, 1]).to(DEVICE) # Discriminator Label to fake" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": 18, 328 | "metadata": { 329 | "scrolled": true 330 | }, 331 | "outputs": [ 332 | { 333 | "name": "stdout", 334 | "output_type": "stream", 335 | "text": [ 336 | "Epoch: 0/30, Step: 0, D Loss: 1.38820219039917, G Loss: 0.6656067967414856\n", 337 | "Epoch: 0/30, Step: 500, D Loss: 0.12251123040914536, G Loss: 2.9214797019958496\n", 338 | "Epoch: 1/30, Step: 1000, D Loss: 1.193413257598877, G Loss: 1.0453091859817505\n", 339 | "Epoch: 1/30, Step: 1500, D Loss: 0.9341679811477661, G Loss: 0.9606684446334839\n", 340 | "Epoch: 2/30, Step: 2000, D Loss: 1.1234525442123413, G Loss: 1.1498955488204956\n", 341 | "Epoch: 2/30, Step: 2500, D Loss: 0.6930141448974609, G Loss: 1.1742724180221558\n", 342 | "Epoch: 3/30, Step: 3000, D Loss: 1.3757328987121582, G Loss: 0.812011182308197\n", 343 | "Epoch: 3/30, Step: 3500, D Loss: 1.0801360607147217, G Loss: 0.9421672821044922\n", 344 | "Epoch: 4/30, Step: 4000, D Loss: 0.9499390125274658, G Loss: 0.9240808486938477\n", 345 | "Epoch: 4/30, Step: 4500, D Loss: 1.3822717666625977, G Loss: 1.1036415100097656\n", 346 | "Epoch: 5/30, Step: 5000, D Loss: 1.0304744243621826, G Loss: 1.405872106552124\n", 347 | "Epoch: 5/30, Step: 5500, D Loss: 0.9890630841255188, G Loss: 1.632412314414978\n", 348 | "Epoch: 6/30, Step: 6000, D Loss: 1.521059274673462, G Loss: 0.7919453382492065\n", 349 | "Epoch: 6/30, Step: 6500, D Loss: 1.140388011932373, G Loss: 0.607524037361145\n", 350 | "Epoch: 7/30, Step: 7000, D Loss: 1.1539878845214844, G Loss: 0.8947302103042603\n", 351 | "Epoch: 8/30, Step: 7500, D Loss: 1.2763843536376953, G Loss: 1.1148791313171387\n", 352 | "Epoch: 8/30, Step: 8000, D Loss: 1.1152751445770264, G Loss: 0.7313449382781982\n", 353 | "Epoch: 9/30, Step: 8500, D Loss: 1.2663581371307373, G Loss: 0.6541774272918701\n", 354 | "Epoch: 9/30, Step: 9000, D Loss: 1.3565425872802734, G Loss: 0.7318902611732483\n", 355 | "Epoch: 10/30, Step: 9500, D Loss: 1.2353792190551758, G Loss: 0.7434751987457275\n", 356 | "Epoch: 10/30, Step: 10000, D Loss: 1.3849306106567383, G Loss: 0.7219750285148621\n", 357 | "Epoch: 11/30, Step: 10500, D Loss: 1.3713154792785645, G Loss: 0.7351651191711426\n", 358 | "Epoch: 11/30, Step: 11000, D Loss: 1.4120464324951172, G Loss: 0.6873267889022827\n", 359 | "Epoch: 12/30, Step: 11500, D Loss: 1.3668935298919678, G Loss: 0.7004505395889282\n", 360 | "Epoch: 12/30, Step: 12000, D Loss: 1.3948414325714111, G Loss: 0.6682448387145996\n", 361 | "Epoch: 13/30, Step: 12500, D Loss: 1.3520605564117432, G Loss: 0.7200150489807129\n", 362 | "Epoch: 13/30, Step: 13000, D Loss: 1.38283371925354, G Loss: 0.6875632405281067\n", 363 | "Epoch: 14/30, Step: 13500, D Loss: 1.3800649642944336, G Loss: 0.6897081136703491\n", 364 | "Epoch: 14/30, Step: 14000, D Loss: 1.3227455615997314, G Loss: 0.7387114763259888\n", 365 | "Epoch: 15/30, Step: 14500, D Loss: 1.3912972211837769, G Loss: 0.7016972303390503\n", 366 | "Epoch: 16/30, Step: 15000, D Loss: 1.3620877265930176, G Loss: 0.7103703022003174\n", 367 | "Epoch: 16/30, Step: 15500, D Loss: 1.383725881576538, G Loss: 0.6901295781135559\n", 368 | "Epoch: 17/30, Step: 16000, D Loss: 1.3718159198760986, G Loss: 0.7076488733291626\n", 369 | "Epoch: 17/30, Step: 16500, D Loss: 1.3845096826553345, G Loss: 0.6948199272155762\n", 370 | "Epoch: 18/30, Step: 17000, D Loss: 1.3773895502090454, G Loss: 0.697970986366272\n", 371 | "Epoch: 18/30, Step: 17500, D Loss: 1.3563889265060425, G Loss: 0.7274670004844666\n", 372 | "Epoch: 19/30, Step: 18000, D Loss: 1.42695152759552, G Loss: 0.6805920600891113\n", 373 | "Epoch: 19/30, Step: 18500, D Loss: 1.389258623123169, G Loss: 0.7034153938293457\n", 374 | "Epoch: 20/30, Step: 19000, D Loss: 1.3753050565719604, G Loss: 0.7082930207252502\n", 375 | "Epoch: 20/30, Step: 19500, D Loss: 1.370561122894287, G Loss: 0.7599979639053345\n", 376 | "Epoch: 21/30, Step: 20000, D Loss: 1.391028642654419, G Loss: 0.6823822855949402\n", 377 | "Epoch: 21/30, Step: 20500, D Loss: 1.365208387374878, G Loss: 0.7175812721252441\n", 378 | "Epoch: 22/30, Step: 21000, D Loss: 1.3695178031921387, G Loss: 0.7152674198150635\n", 379 | "Epoch: 22/30, Step: 21500, D Loss: 1.3963592052459717, G Loss: 0.683794379234314\n", 380 | "Epoch: 23/30, Step: 22000, D Loss: 1.3914263248443604, G Loss: 0.7091646790504456\n", 381 | "Epoch: 24/30, Step: 22500, D Loss: 1.3689409494400024, G Loss: 0.6955894231796265\n", 382 | "Epoch: 24/30, Step: 23000, D Loss: 1.4021984338760376, G Loss: 0.6963061094284058\n", 383 | "Epoch: 25/30, Step: 23500, D Loss: 1.3541772365570068, G Loss: 0.7195296287536621\n", 384 | "Epoch: 25/30, Step: 24000, D Loss: 1.3771123886108398, G Loss: 0.7081385850906372\n", 385 | "Epoch: 26/30, Step: 24500, D Loss: 1.3679018020629883, G Loss: 0.7069792747497559\n", 386 | "Epoch: 26/30, Step: 25000, D Loss: 1.3764290809631348, G Loss: 0.6909903287887573\n", 387 | "Epoch: 27/30, Step: 25500, D Loss: 1.3768750429153442, G Loss: 0.699029266834259\n", 388 | "Epoch: 27/30, Step: 26000, D Loss: 1.3821161985397339, G Loss: 0.6960726976394653\n", 389 | "Epoch: 28/30, Step: 26500, D Loss: 1.3820538520812988, G Loss: 0.6842552423477173\n", 390 | "Epoch: 28/30, Step: 27000, D Loss: 1.3942863941192627, G Loss: 0.7066346406936646\n", 391 | "Epoch: 29/30, Step: 27500, D Loss: 1.3738797903060913, G Loss: 0.7084473967552185\n", 392 | "Epoch: 29/30, Step: 28000, D Loss: 1.4056565761566162, G Loss: 0.6934462785720825\n" 393 | ] 394 | } 395 | ], 396 | "source": [ 397 | "for epoch in range(max_epoch):\n", 398 | " for idx, (images, labels) in enumerate(data_loader):\n", 399 | " # Training Discriminator\n", 400 | " x = images.to(DEVICE)\n", 401 | " y = labels.view(batch_size, 1)\n", 402 | " y = to_onehot(y).to(DEVICE)\n", 403 | " x_outputs = D(x, y)\n", 404 | " D_x_loss = criterion(x_outputs, D_labels)\n", 405 | "\n", 406 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 407 | " z_outputs = D(G(z, y), y)\n", 408 | " D_z_loss = criterion(z_outputs, D_fakes)\n", 409 | " D_loss = D_x_loss + D_z_loss\n", 410 | " \n", 411 | " D.zero_grad()\n", 412 | " D_loss.backward()\n", 413 | " D_opt.step()\n", 414 | "\n", 415 | " if step % n_critic == 0:\n", 416 | " # Training Generator\n", 417 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 418 | " z_outputs = D(G(z, y), y)\n", 419 | " G_loss = criterion(z_outputs, D_labels)\n", 420 | "\n", 421 | " D.zero_grad()\n", 422 | " G.zero_grad()\n", 423 | " G_loss.backward()\n", 424 | " G_opt.step()\n", 425 | " \n", 426 | " if step % 500 == 0:\n", 427 | " print('Epoch: {}/{}, Step: {}, D Loss: {}, G Loss: {}'.format(epoch, max_epoch, step, D_loss.item(), G_loss.item()))\n", 428 | " \n", 429 | " if step % 1000 == 0:\n", 430 | " G.eval()\n", 431 | " img = get_sample_image(G, n_noise)\n", 432 | " imsave('samples/{}_step{}.jpg'.format(MODEL_NAME, str(step).zfill(3)), img, cmap='gray')\n", 433 | " G.train()\n", 434 | " step += 1" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": null, 440 | "metadata": { 441 | "collapsed": true 442 | }, 443 | "outputs": [], 444 | "source": [] 445 | }, 446 | { 447 | "cell_type": "markdown", 448 | "metadata": {}, 449 | "source": [ 450 | "## Sample" 451 | ] 452 | }, 453 | { 454 | "cell_type": "code", 455 | "execution_count": null, 456 | "metadata": { 457 | "collapsed": true 458 | }, 459 | "outputs": [], 460 | "source": [ 461 | "# generation to image\n", 462 | "G.eval()\n", 463 | "imshow(get_sample_image(G, n_noise), cmap='gray')" 464 | ] 465 | }, 466 | { 467 | "cell_type": "code", 468 | "execution_count": null, 469 | "metadata": { 470 | "collapsed": true 471 | }, 472 | "outputs": [], 473 | "source": [] 474 | }, 475 | { 476 | "cell_type": "code", 477 | "execution_count": 15, 478 | "metadata": { 479 | "collapsed": true 480 | }, 481 | "outputs": [], 482 | "source": [ 483 | "def save_checkpoint(state, file_name='checkpoint.pth.tar'):\n", 484 | " torch.save(state, file_name)" 485 | ] 486 | }, 487 | { 488 | "cell_type": "code", 489 | "execution_count": 16, 490 | "metadata": { 491 | "collapsed": true 492 | }, 493 | "outputs": [], 494 | "source": [ 495 | "# Saving params.\n", 496 | "# torch.save(D.state_dict(), 'D_c.pkl')\n", 497 | "# torch.save(G.state_dict(), 'G_c.pkl')\n", 498 | "save_checkpoint({'epoch': epoch + 1, 'state_dict':D.state_dict(), 'optimizer' : D_opt.state_dict()}, 'D_dc.pth.tar')\n", 499 | "save_checkpoint({'epoch': epoch + 1, 'state_dict':G.state_dict(), 'optimizer' : G_opt.state_dict()}, 'G_dc.pth.tar')" 500 | ] 501 | }, 502 | { 503 | "cell_type": "code", 504 | "execution_count": null, 505 | "metadata": { 506 | "collapsed": true 507 | }, 508 | "outputs": [], 509 | "source": [] 510 | } 511 | ], 512 | "metadata": { 513 | "kernelspec": { 514 | "display_name": "Python 3", 515 | "language": "python", 516 | "name": "python3" 517 | }, 518 | "language_info": { 519 | "codemirror_mode": { 520 | "name": "ipython", 521 | "version": 3 522 | }, 523 | "file_extension": ".py", 524 | "mimetype": "text/x-python", 525 | "name": "python", 526 | "nbconvert_exporter": "python", 527 | "pygments_lexer": "ipython3", 528 | "version": "3.6.3" 529 | } 530 | }, 531 | "nbformat": 4, 532 | "nbformat_minor": 2 533 | } 534 | -------------------------------------------------------------------------------- /MNIST/Conditional-GAN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Implementation of Conditional GANs\n", 8 | "Reference: https://arxiv.org/pdf/1411.1784.pdf" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": { 15 | "collapsed": true 16 | }, 17 | "outputs": [], 18 | "source": [ 19 | "# Run the comment below only when using Google Colab\n", 20 | "# !pip install torch torchvision" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": { 27 | "collapsed": true 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "import torch\n", 32 | "import torchvision\n", 33 | "import torch.nn as nn\n", 34 | "import torch.nn.functional as F" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 2, 40 | "metadata": { 41 | "collapsed": true 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "from torch.utils.data import DataLoader\n", 46 | "from torchvision import datasets\n", 47 | "from torchvision import transforms\n", 48 | "from torchvision.utils import save_image" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": { 55 | "collapsed": true 56 | }, 57 | "outputs": [], 58 | "source": [ 59 | "import numpy as np\n", 60 | "import datetime\n", 61 | "import os, sys" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 4, 67 | "metadata": { 68 | "collapsed": true 69 | }, 70 | "outputs": [], 71 | "source": [ 72 | "from matplotlib.pyplot import imshow, imsave\n", 73 | "%matplotlib inline" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 5, 79 | "metadata": { 80 | "collapsed": true 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "MODEL_NAME = 'ConditionalGAN'\n", 85 | "DEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 6, 91 | "metadata": { 92 | "collapsed": true 93 | }, 94 | "outputs": [], 95 | "source": [ 96 | "def to_onehot(x, num_classes=10):\n", 97 | " assert isinstance(x, int) or isinstance(x, (torch.LongTensor, torch.cuda.LongTensor))\n", 98 | " if isinstance(x, int):\n", 99 | " c = torch.zeros(1, num_classes).long()\n", 100 | " c[0][x] = 1\n", 101 | " else:\n", 102 | " x = x.cpu()\n", 103 | " c = torch.LongTensor(x.size(0), num_classes)\n", 104 | " c.zero_()\n", 105 | " c.scatter_(1, x, 1) # dim, index, src value\n", 106 | " return c" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 7, 112 | "metadata": { 113 | "collapsed": true 114 | }, 115 | "outputs": [], 116 | "source": [ 117 | "def get_sample_image(G, n_noise=100):\n", 118 | " \"\"\"\n", 119 | " save sample 100 images\n", 120 | " \"\"\"\n", 121 | " img = np.zeros([280, 280])\n", 122 | " for j in range(10):\n", 123 | " c = torch.zeros([10, 10]).to(DEVICE)\n", 124 | " c[:, j] = 1\n", 125 | " z = torch.randn(10, n_noise).to(DEVICE)\n", 126 | " y_hat = G(z,c).view(10, 28, 28)\n", 127 | " result = y_hat.cpu().data.numpy()\n", 128 | " img[j*28:(j+1)*28] = np.concatenate([x for x in result], axis=-1)\n", 129 | " return img" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 8, 135 | "metadata": { 136 | "collapsed": true 137 | }, 138 | "outputs": [], 139 | "source": [ 140 | "class Discriminator(nn.Module):\n", 141 | " \"\"\"\n", 142 | " Simple Discriminator w/ MLP\n", 143 | " \"\"\"\n", 144 | " def __init__(self, input_size=784, condition_size=10, num_classes=1):\n", 145 | " super(Discriminator, self).__init__()\n", 146 | " self.layer = nn.Sequential(\n", 147 | " nn.Linear(input_size+condition_size, 512),\n", 148 | " nn.LeakyReLU(0.2),\n", 149 | " nn.Linear(512, 256),\n", 150 | " nn.LeakyReLU(0.2),\n", 151 | " nn.Linear(256, num_classes),\n", 152 | " nn.Sigmoid(),\n", 153 | " )\n", 154 | " \n", 155 | " def forward(self, x, c): \n", 156 | " x, c = x.view(x.size(0), -1), c.view(c.size(0), -1).float()\n", 157 | " v = torch.cat((x, c), 1) # v: [input, label] concatenated vector\n", 158 | " y_ = self.layer(v)\n", 159 | " return y_" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 9, 165 | "metadata": { 166 | "collapsed": true 167 | }, 168 | "outputs": [], 169 | "source": [ 170 | "class Generator(nn.Module):\n", 171 | " \"\"\"\n", 172 | " Simple Generator w/ MLP\n", 173 | " \"\"\"\n", 174 | " def __init__(self, input_size=100, condition_size=10, num_classes=784):\n", 175 | " super(Generator, self).__init__()\n", 176 | " self.layer = nn.Sequential(\n", 177 | " nn.Linear(input_size+condition_size, 128),\n", 178 | " nn.LeakyReLU(0.2),\n", 179 | " nn.Linear(128, 256),\n", 180 | " nn.BatchNorm1d(256),\n", 181 | " nn.LeakyReLU(0.2),\n", 182 | " nn.Linear(256, 512),\n", 183 | " nn.BatchNorm1d(512),\n", 184 | " nn.LeakyReLU(0.2),\n", 185 | " nn.Linear(512, 1024),\n", 186 | " nn.BatchNorm1d(1024),\n", 187 | " nn.LeakyReLU(0.2),\n", 188 | " nn.Linear(1024, num_classes),\n", 189 | " nn.Tanh()\n", 190 | " )\n", 191 | " \n", 192 | " def forward(self, x, c):\n", 193 | " x, c = x.view(x.size(0), -1), c.view(c.size(0), -1).float()\n", 194 | " v = torch.cat((x, c), 1) # v: [input, label] concatenated vector\n", 195 | " y_ = self.layer(v)\n", 196 | " y_ = y_.view(x.size(0), 1, 28, 28)\n", 197 | " return y_" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": 10, 203 | "metadata": { 204 | "collapsed": true 205 | }, 206 | "outputs": [], 207 | "source": [ 208 | "D = Discriminator().to(DEVICE)\n", 209 | "G = Generator().to(DEVICE)" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 11, 215 | "metadata": { 216 | "collapsed": true 217 | }, 218 | "outputs": [], 219 | "source": [ 220 | "transform = transforms.Compose([transforms.ToTensor(),\n", 221 | " transforms.Normalize(mean=[0.5],\n", 222 | " std=[0.5])]\n", 223 | ")" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": 12, 229 | "metadata": { 230 | "collapsed": true 231 | }, 232 | "outputs": [], 233 | "source": [ 234 | "mnist = datasets.MNIST(root='../data/', train=True, transform=transform, download=True)" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 13, 240 | "metadata": { 241 | "collapsed": true 242 | }, 243 | "outputs": [], 244 | "source": [ 245 | "batch_size = 64\n", 246 | "condition_size = 10" 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": 14, 252 | "metadata": { 253 | "collapsed": true 254 | }, 255 | "outputs": [], 256 | "source": [ 257 | "data_loader = DataLoader(dataset=mnist, batch_size=batch_size, shuffle=True, drop_last=True)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 15, 263 | "metadata": { 264 | "collapsed": true 265 | }, 266 | "outputs": [], 267 | "source": [ 268 | "criterion = nn.BCELoss()\n", 269 | "D_opt = torch.optim.Adam(D.parameters(), lr=0.0002, betas=(0.5, 0.999))\n", 270 | "G_opt = torch.optim.Adam(G.parameters(), lr=0.0002, betas=(0.5, 0.999))" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": 16, 276 | "metadata": { 277 | "collapsed": true 278 | }, 279 | "outputs": [], 280 | "source": [ 281 | "max_epoch = 30 # need more than 100 epochs for training generator\n", 282 | "step = 0\n", 283 | "n_critic = 1 # for training more k steps about Discriminator\n", 284 | "n_noise = 100" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 17, 290 | "metadata": { 291 | "collapsed": true 292 | }, 293 | "outputs": [], 294 | "source": [ 295 | "D_labels = torch.ones([batch_size, 1]).to(DEVICE) # Discriminator Label to real\n", 296 | "D_fakes = torch.zeros([batch_size, 1]).to(DEVICE) # Discriminator Label to fake" 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": 18, 302 | "metadata": { 303 | "collapsed": true 304 | }, 305 | "outputs": [], 306 | "source": [ 307 | "if not os.path.exists('samples'):\n", 308 | " os.makedirs('samples')" 309 | ] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": 19, 314 | "metadata": { 315 | "scrolled": true 316 | }, 317 | "outputs": [ 318 | { 319 | "name": "stdout", 320 | "output_type": "stream", 321 | "text": [ 322 | "Epoch: 0/30, Step: 500, D Loss: 1.036657691001892, G Loss: 0.9185525178909302\n", 323 | "Epoch: 1/30, Step: 1000, D Loss: 1.1014388799667358, G Loss: 1.0158565044403076\n", 324 | "Epoch: 1/30, Step: 1500, D Loss: 1.017891764640808, G Loss: 0.5917305946350098\n", 325 | "Epoch: 2/30, Step: 2000, D Loss: 1.0990983247756958, G Loss: 1.2299494743347168\n", 326 | "Epoch: 2/30, Step: 2500, D Loss: 0.9987165331840515, G Loss: 1.0967953205108643\n", 327 | "Epoch: 3/30, Step: 3000, D Loss: 1.0531857013702393, G Loss: 0.805138885974884\n", 328 | "Epoch: 3/30, Step: 3500, D Loss: 1.0865103006362915, G Loss: 1.1308486461639404\n", 329 | "Epoch: 4/30, Step: 4000, D Loss: 1.316153883934021, G Loss: 1.4331691265106201\n", 330 | "Epoch: 4/30, Step: 4500, D Loss: 1.2097547054290771, G Loss: 0.9566960334777832\n", 331 | "Epoch: 5/30, Step: 5000, D Loss: 1.3060839176177979, G Loss: 1.0760974884033203\n", 332 | "Epoch: 5/30, Step: 5500, D Loss: 1.1368037462234497, G Loss: 1.1087679862976074\n", 333 | "Epoch: 6/30, Step: 6000, D Loss: 1.2275606393814087, G Loss: 0.7947745323181152\n", 334 | "Epoch: 6/30, Step: 6500, D Loss: 1.2633943557739258, G Loss: 0.6697460412979126\n", 335 | "Epoch: 7/30, Step: 7000, D Loss: 1.1676291227340698, G Loss: 0.876056969165802\n", 336 | "Epoch: 8/30, Step: 7500, D Loss: 1.2297134399414062, G Loss: 1.0675418376922607\n", 337 | "Epoch: 8/30, Step: 8000, D Loss: 1.2598073482513428, G Loss: 1.0166195631027222\n", 338 | "Epoch: 9/30, Step: 8500, D Loss: 1.3194297552108765, G Loss: 1.5806450843811035\n", 339 | "Epoch: 9/30, Step: 9000, D Loss: 1.493754267692566, G Loss: 0.5422479510307312\n", 340 | "Epoch: 10/30, Step: 9500, D Loss: 1.393540620803833, G Loss: 1.2079241275787354\n", 341 | "Epoch: 10/30, Step: 10000, D Loss: 1.2525854110717773, G Loss: 0.844454824924469\n", 342 | "Epoch: 11/30, Step: 10500, D Loss: 1.4267148971557617, G Loss: 0.5226021409034729\n", 343 | "Epoch: 11/30, Step: 11000, D Loss: 1.3154008388519287, G Loss: 1.0357294082641602\n", 344 | "Epoch: 12/30, Step: 11500, D Loss: 1.2607324123382568, G Loss: 0.7632520198822021\n", 345 | "Epoch: 12/30, Step: 12000, D Loss: 1.2418172359466553, G Loss: 0.8889996409416199\n", 346 | "Epoch: 13/30, Step: 12500, D Loss: 1.3362860679626465, G Loss: 0.8968085646629333\n", 347 | "Epoch: 13/30, Step: 13000, D Loss: 1.2870495319366455, G Loss: 0.8639671802520752\n", 348 | "Epoch: 14/30, Step: 13500, D Loss: 1.313111662864685, G Loss: 0.7909728288650513\n", 349 | "Epoch: 14/30, Step: 14000, D Loss: 1.3023371696472168, G Loss: 0.7487360239028931\n", 350 | "Epoch: 15/30, Step: 14500, D Loss: 1.2976658344268799, G Loss: 0.9248465299606323\n", 351 | "Epoch: 16/30, Step: 15000, D Loss: 1.3270314931869507, G Loss: 0.8751394748687744\n", 352 | "Epoch: 16/30, Step: 15500, D Loss: 1.3797385692596436, G Loss: 0.7970761656761169\n", 353 | "Epoch: 17/30, Step: 16000, D Loss: 1.29557204246521, G Loss: 0.8374907374382019\n", 354 | "Epoch: 17/30, Step: 16500, D Loss: 1.3149912357330322, G Loss: 0.9167639017105103\n", 355 | "Epoch: 18/30, Step: 17000, D Loss: 1.301594853401184, G Loss: 0.8182051777839661\n", 356 | "Epoch: 18/30, Step: 17500, D Loss: 1.2963449954986572, G Loss: 0.7822583317756653\n", 357 | "Epoch: 19/30, Step: 18000, D Loss: 1.3422776460647583, G Loss: 0.8751208186149597\n", 358 | "Epoch: 19/30, Step: 18500, D Loss: 1.3826189041137695, G Loss: 0.7738077044487\n", 359 | "Epoch: 20/30, Step: 19000, D Loss: 1.3043901920318604, G Loss: 0.8847906589508057\n", 360 | "Epoch: 20/30, Step: 19500, D Loss: 1.3643009662628174, G Loss: 0.7579598426818848\n", 361 | "Epoch: 21/30, Step: 20000, D Loss: 1.3725740909576416, G Loss: 0.8713376522064209\n", 362 | "Epoch: 21/30, Step: 20500, D Loss: 1.3675336837768555, G Loss: 0.6800622940063477\n", 363 | "Epoch: 22/30, Step: 21000, D Loss: 1.328478455543518, G Loss: 0.8010445833206177\n", 364 | "Epoch: 22/30, Step: 21500, D Loss: 1.2901370525360107, G Loss: 0.7903639078140259\n", 365 | "Epoch: 23/30, Step: 22000, D Loss: 1.3740167617797852, G Loss: 0.7188965678215027\n", 366 | "Epoch: 24/30, Step: 22500, D Loss: 1.3559741973876953, G Loss: 0.7523510456085205\n", 367 | "Epoch: 24/30, Step: 23000, D Loss: 1.3947091102600098, G Loss: 0.8877040147781372\n", 368 | "Epoch: 25/30, Step: 23500, D Loss: 1.3366261720657349, G Loss: 0.7491698861122131\n", 369 | "Epoch: 25/30, Step: 24000, D Loss: 1.3519549369812012, G Loss: 0.7902757525444031\n", 370 | "Epoch: 26/30, Step: 24500, D Loss: 1.3612239360809326, G Loss: 0.7084876298904419\n", 371 | "Epoch: 26/30, Step: 25000, D Loss: 1.3272916078567505, G Loss: 0.8394737243652344\n", 372 | "Epoch: 27/30, Step: 25500, D Loss: 1.2812349796295166, G Loss: 0.8942346572875977\n", 373 | "Epoch: 27/30, Step: 26000, D Loss: 1.417182207107544, G Loss: 0.8112509250640869\n", 374 | "Epoch: 28/30, Step: 26500, D Loss: 1.3233587741851807, G Loss: 0.8840529918670654\n", 375 | "Epoch: 28/30, Step: 27000, D Loss: 1.408776044845581, G Loss: 0.7207623720169067\n", 376 | "Epoch: 29/30, Step: 27500, D Loss: 1.3049994707107544, G Loss: 0.780764639377594\n", 377 | "Epoch: 29/30, Step: 28000, D Loss: 1.344968557357788, G Loss: 0.7138490080833435\n" 378 | ] 379 | } 380 | ], 381 | "source": [ 382 | "for epoch in range(max_epoch):\n", 383 | " for idx, (images, labels) in enumerate(data_loader):\n", 384 | " # Training Discriminator\n", 385 | " x = images.to(DEVICE)\n", 386 | " y = labels.view(batch_size, 1)\n", 387 | " y = to_onehot(y).to(DEVICE)\n", 388 | " x_outputs = D(x, y)\n", 389 | " D_x_loss = criterion(x_outputs, D_labels)\n", 390 | "\n", 391 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 392 | " z_outputs = D(G(z, y), y)\n", 393 | " D_z_loss = criterion(z_outputs, D_fakes)\n", 394 | " D_loss = D_x_loss + D_z_loss\n", 395 | " \n", 396 | " D.zero_grad()\n", 397 | " D_loss.backward()\n", 398 | " D_opt.step()\n", 399 | " \n", 400 | " if step % n_critic == 0:\n", 401 | " # Training Generator\n", 402 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 403 | " z_outputs = D(G(z, y), y)\n", 404 | " G_loss = criterion(z_outputs, D_labels)\n", 405 | "\n", 406 | " G.zero_grad()\n", 407 | " G_loss.backward()\n", 408 | " G_opt.step()\n", 409 | " \n", 410 | " if step % 500 == 0:\n", 411 | " print('Epoch: {}/{}, Step: {}, D Loss: {}, G Loss: {}'.format(epoch, max_epoch, step, D_loss.item(), G_loss.item()))\n", 412 | " \n", 413 | " if step % 1000 == 0:\n", 414 | " G.eval()\n", 415 | " img = get_sample_image(G, n_noise)\n", 416 | " imsave('samples/{}_step{}.jpg'.format(MODEL_NAME, str(step).zfill(3)), img, cmap='gray')\n", 417 | " G.train()\n", 418 | " step += 1" 419 | ] 420 | }, 421 | { 422 | "cell_type": "markdown", 423 | "metadata": {}, 424 | "source": [ 425 | "## Sample" 426 | ] 427 | }, 428 | { 429 | "cell_type": "code", 430 | "execution_count": 20, 431 | "metadata": {}, 432 | "outputs": [ 433 | { 434 | "data": { 435 | "text/plain": [ 436 | "" 437 | ] 438 | }, 439 | "execution_count": 20, 440 | "metadata": {}, 441 | "output_type": "execute_result" 442 | }, 443 | { 444 | "data": { 445 | "image/png": "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\n", 446 | "text/plain": [ 447 | "" 448 | ] 449 | }, 450 | "metadata": {}, 451 | "output_type": "display_data" 452 | } 453 | ], 454 | "source": [ 455 | "# generation to image\n", 456 | "G.eval()\n", 457 | "imshow(get_sample_image(G, n_noise), cmap='gray')" 458 | ] 459 | }, 460 | { 461 | "cell_type": "code", 462 | "execution_count": 40, 463 | "metadata": { 464 | "collapsed": true 465 | }, 466 | "outputs": [], 467 | "source": [ 468 | "def save_checkpoint(state, file_name='checkpoint.pth.tar'):\n", 469 | " torch.save(state, file_name)" 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": 41, 475 | "metadata": { 476 | "collapsed": true 477 | }, 478 | "outputs": [], 479 | "source": [ 480 | "# Saving params.\n", 481 | "save_checkpoint({'epoch': epoch + 1, 'state_dict':D.state_dict(), 'optimizer' : D_opt.state_dict()}, 'D_c.pth.tar')\n", 482 | "save_checkpoint({'epoch': epoch + 1, 'state_dict':G.state_dict(), 'optimizer' : G_opt.state_dict()}, 'G_c.pth.tar')" 483 | ] 484 | }, 485 | { 486 | "cell_type": "code", 487 | "execution_count": null, 488 | "metadata": { 489 | "collapsed": true 490 | }, 491 | "outputs": [], 492 | "source": [] 493 | } 494 | ], 495 | "metadata": { 496 | "kernelspec": { 497 | "display_name": "Python 3", 498 | "language": "python", 499 | "name": "python3" 500 | }, 501 | "language_info": { 502 | "codemirror_mode": { 503 | "name": "ipython", 504 | "version": 3 505 | }, 506 | "file_extension": ".py", 507 | "mimetype": "text/x-python", 508 | "name": "python", 509 | "nbconvert_exporter": "python", 510 | "pygments_lexer": "ipython3", 511 | "version": "3.6.3" 512 | } 513 | }, 514 | "nbformat": 4, 515 | "nbformat_minor": 2 516 | } 517 | -------------------------------------------------------------------------------- /MNIST/DCGAN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Implementation of Deep Convolutional GANs\n", 8 | "Reference: https://arxiv.org/pdf/1511.06434.pdf" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": { 15 | "collapsed": true 16 | }, 17 | "outputs": [], 18 | "source": [ 19 | "# Run the comment below only when using Google Colab\n", 20 | "# !pip install torch torchvision" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": { 27 | "collapsed": true 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "import torch\n", 32 | "import torchvision\n", 33 | "import torch.nn as nn\n", 34 | "import torch.nn.functional as F" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 2, 40 | "metadata": { 41 | "collapsed": true 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "from torch.utils.data import DataLoader\n", 46 | "from torchvision import datasets\n", 47 | "from torchvision import transforms\n", 48 | "from torchvision.utils import save_image" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": { 55 | "collapsed": true 56 | }, 57 | "outputs": [], 58 | "source": [ 59 | "import numpy as np\n", 60 | "import datetime\n", 61 | "import os, sys" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 4, 67 | "metadata": { 68 | "collapsed": true 69 | }, 70 | "outputs": [], 71 | "source": [ 72 | "from matplotlib.pyplot import imshow, imsave\n", 73 | "%matplotlib inline" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 5, 79 | "metadata": { 80 | "collapsed": true 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "MODEL_NAME = 'DCGAN'\n", 85 | "DEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 6, 91 | "metadata": { 92 | "collapsed": true 93 | }, 94 | "outputs": [], 95 | "source": [ 96 | "def get_sample_image(G, n_noise):\n", 97 | " \"\"\"\n", 98 | " save sample 100 images\n", 99 | " \"\"\"\n", 100 | " z = torch.randn(100, n_noise).to(DEVICE)\n", 101 | " y_hat = G(z).view(100, 28, 28) # (100, 28, 28)\n", 102 | " result = y_hat.cpu().data.numpy()\n", 103 | " img = np.zeros([280, 280])\n", 104 | " for j in range(10):\n", 105 | " img[j*28:(j+1)*28] = np.concatenate([x for x in result[j*10:(j+1)*10]], axis=-1)\n", 106 | " return img" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 7, 112 | "metadata": { 113 | "collapsed": true 114 | }, 115 | "outputs": [], 116 | "source": [ 117 | "class Discriminator(nn.Module):\n", 118 | " \"\"\"\n", 119 | " Convolutional Discriminator for MNIST\n", 120 | " \"\"\"\n", 121 | " def __init__(self, in_channel=1, num_classes=1):\n", 122 | " super(Discriminator, self).__init__()\n", 123 | " self.conv = nn.Sequential(\n", 124 | " # 28 -> 14\n", 125 | " nn.Conv2d(in_channel, 512, 3, stride=2, padding=1, bias=False),\n", 126 | " nn.BatchNorm2d(512),\n", 127 | " nn.LeakyReLU(0.2),\n", 128 | " # 14 -> 7\n", 129 | " nn.Conv2d(512, 256, 3, stride=2, padding=1, bias=False),\n", 130 | " nn.BatchNorm2d(256),\n", 131 | " nn.LeakyReLU(0.2),\n", 132 | " # 7 -> 4\n", 133 | " nn.Conv2d(256, 128, 3, stride=2, padding=1, bias=False),\n", 134 | " nn.BatchNorm2d(128),\n", 135 | " nn.LeakyReLU(0.2),\n", 136 | " nn.AvgPool2d(4),\n", 137 | " )\n", 138 | " self.fc = nn.Sequential(\n", 139 | " # reshape input, 128 -> 1\n", 140 | " nn.Linear(128, 1),\n", 141 | " nn.Sigmoid(),\n", 142 | " )\n", 143 | " \n", 144 | " def forward(self, x, y=None):\n", 145 | " y_ = self.conv(x)\n", 146 | " y_ = y_.view(y_.size(0), -1)\n", 147 | " y_ = self.fc(y_)\n", 148 | " return y_" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 8, 154 | "metadata": { 155 | "collapsed": true 156 | }, 157 | "outputs": [], 158 | "source": [ 159 | "class Generator(nn.Module):\n", 160 | " \"\"\"\n", 161 | " Convolutional Generator for MNIST\n", 162 | " \"\"\"\n", 163 | " def __init__(self, input_size=100, num_classes=784):\n", 164 | " super(Generator, self).__init__()\n", 165 | " self.fc = nn.Sequential(\n", 166 | " nn.Linear(input_size, 4*4*512),\n", 167 | " nn.ReLU(),\n", 168 | " )\n", 169 | " self.conv = nn.Sequential(\n", 170 | " # input: 4 by 4, output: 7 by 7\n", 171 | " nn.ConvTranspose2d(512, 256, 3, stride=2, padding=1, bias=False),\n", 172 | " nn.BatchNorm2d(256),\n", 173 | " nn.ReLU(),\n", 174 | " # input: 7 by 7, output: 14 by 14\n", 175 | " nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1, bias=False),\n", 176 | " nn.BatchNorm2d(128),\n", 177 | " nn.ReLU(),\n", 178 | " # input: 14 by 14, output: 28 by 28\n", 179 | " nn.ConvTranspose2d(128, 1, 4, stride=2, padding=1, bias=False),\n", 180 | " nn.Tanh(),\n", 181 | " )\n", 182 | " \n", 183 | " def forward(self, x, y=None):\n", 184 | " x = x.view(x.size(0), -1)\n", 185 | " y_ = self.fc(x)\n", 186 | " y_ = y_.view(y_.size(0), 512, 4, 4)\n", 187 | " y_ = self.conv(y_)\n", 188 | " return y_" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 9, 194 | "metadata": { 195 | "collapsed": true 196 | }, 197 | "outputs": [], 198 | "source": [ 199 | "D = Discriminator().to(DEVICE)\n", 200 | "G = Generator().to(DEVICE)\n", 201 | "# D.load_state_dict('D_dc.pkl')\n", 202 | "# G.load_state_dict('G_dc.pkl')" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 10, 208 | "metadata": { 209 | "collapsed": true 210 | }, 211 | "outputs": [], 212 | "source": [ 213 | "transform = transforms.Compose([transforms.ToTensor(),\n", 214 | " transforms.Normalize(mean=[0.5],\n", 215 | " std=[0.5])]\n", 216 | ")" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 11, 222 | "metadata": { 223 | "collapsed": true 224 | }, 225 | "outputs": [], 226 | "source": [ 227 | "mnist = datasets.MNIST(root='../data/', train=True, transform=transform, download=True)" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 12, 233 | "metadata": { 234 | "collapsed": true 235 | }, 236 | "outputs": [], 237 | "source": [ 238 | "batch_size = 64" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": 13, 244 | "metadata": { 245 | "collapsed": true 246 | }, 247 | "outputs": [], 248 | "source": [ 249 | "data_loader = DataLoader(dataset=mnist, batch_size=batch_size, shuffle=True, drop_last=True)" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": 14, 255 | "metadata": { 256 | "collapsed": true 257 | }, 258 | "outputs": [], 259 | "source": [ 260 | "criterion = nn.BCELoss()\n", 261 | "D_opt = torch.optim.Adam(D.parameters(), lr=0.001, betas=(0.5, 0.999))\n", 262 | "G_opt = torch.optim.Adam(G.parameters(), lr=0.001, betas=(0.5, 0.999))" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 15, 268 | "metadata": { 269 | "collapsed": true 270 | }, 271 | "outputs": [], 272 | "source": [ 273 | "max_epoch = 30 # need more than 20 epochs for training generator\n", 274 | "step = 0\n", 275 | "n_critic = 1 # for training more k steps about Discriminator\n", 276 | "n_noise = 100" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": 16, 282 | "metadata": { 283 | "collapsed": true 284 | }, 285 | "outputs": [], 286 | "source": [ 287 | "D_labels = torch.ones([batch_size, 1]).to(DEVICE) # Discriminator Label to real\n", 288 | "D_fakes = torch.zeros([batch_size, 1]).to(DEVICE) # Discriminator Label to fake" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "execution_count": 17, 294 | "metadata": { 295 | "scrolled": true 296 | }, 297 | "outputs": [ 298 | { 299 | "name": "stdout", 300 | "output_type": "stream", 301 | "text": [ 302 | "Epoch: 0/30, Step: 0, D Loss: 1.3901150226593018, G Loss: 0.645667552947998\n", 303 | "Epoch: 0/30, Step: 500, D Loss: 0.8841016292572021, G Loss: 1.032528042793274\n", 304 | "Epoch: 1/30, Step: 1000, D Loss: 0.3341742157936096, G Loss: 1.929326057434082\n", 305 | "Epoch: 1/30, Step: 1500, D Loss: 0.502487063407898, G Loss: 1.8487944602966309\n", 306 | "Epoch: 2/30, Step: 2000, D Loss: 0.5597702860832214, G Loss: 1.8412060737609863\n", 307 | "Epoch: 2/30, Step: 2500, D Loss: 0.4319043457508087, G Loss: 1.2376809120178223\n", 308 | "Epoch: 3/30, Step: 3000, D Loss: 0.5119948387145996, G Loss: 1.7091478109359741\n", 309 | "Epoch: 3/30, Step: 3500, D Loss: 0.4834495186805725, G Loss: 2.1602656841278076\n", 310 | "Epoch: 4/30, Step: 4000, D Loss: 0.3906676769256592, G Loss: 2.2380075454711914\n", 311 | "Epoch: 4/30, Step: 4500, D Loss: 0.57613605260849, G Loss: 1.8952455520629883\n", 312 | "Epoch: 5/30, Step: 5000, D Loss: 0.37664082646369934, G Loss: 2.319974660873413\n", 313 | "Epoch: 5/30, Step: 5500, D Loss: 0.46279168128967285, G Loss: 2.153512954711914\n", 314 | "Epoch: 6/30, Step: 6000, D Loss: 0.4129234254360199, G Loss: 2.554079055786133\n", 315 | "Epoch: 6/30, Step: 6500, D Loss: 0.33443957567214966, G Loss: 2.8593034744262695\n", 316 | "Epoch: 7/30, Step: 7000, D Loss: 0.3468945324420929, G Loss: 2.6473114490509033\n", 317 | "Epoch: 8/30, Step: 7500, D Loss: 0.40650618076324463, G Loss: 1.9287309646606445\n", 318 | "Epoch: 8/30, Step: 8000, D Loss: 0.6533892154693604, G Loss: 1.7906147241592407\n", 319 | "Epoch: 9/30, Step: 8500, D Loss: 0.2568785548210144, G Loss: 2.1740102767944336\n", 320 | "Epoch: 9/30, Step: 9000, D Loss: 0.45188480615615845, G Loss: 1.866640329360962\n", 321 | "Epoch: 10/30, Step: 9500, D Loss: 0.3194931447505951, G Loss: 1.7600427865982056\n", 322 | "Epoch: 10/30, Step: 10000, D Loss: 0.5581725239753723, G Loss: 2.1016454696655273\n", 323 | "Epoch: 11/30, Step: 10500, D Loss: 0.35416218638420105, G Loss: 2.4358558654785156\n", 324 | "Epoch: 11/30, Step: 11000, D Loss: 0.44659504294395447, G Loss: 1.803159475326538\n", 325 | "Epoch: 12/30, Step: 11500, D Loss: 0.368685245513916, G Loss: 3.1171088218688965\n", 326 | "Epoch: 12/30, Step: 12000, D Loss: 0.2865059971809387, G Loss: 1.6171672344207764\n", 327 | "Epoch: 13/30, Step: 12500, D Loss: 0.5770776271820068, G Loss: 1.3813045024871826\n", 328 | "Epoch: 13/30, Step: 13000, D Loss: 0.503258466720581, G Loss: 3.088622570037842\n", 329 | "Epoch: 14/30, Step: 13500, D Loss: 0.3149162232875824, G Loss: 2.2010059356689453\n", 330 | "Epoch: 14/30, Step: 14000, D Loss: 0.5541285276412964, G Loss: 2.093771457672119\n", 331 | "Epoch: 15/30, Step: 14500, D Loss: 0.41772717237472534, G Loss: 2.5844826698303223\n", 332 | "Epoch: 16/30, Step: 15000, D Loss: 0.38224175572395325, G Loss: 1.7165570259094238\n", 333 | "Epoch: 16/30, Step: 15500, D Loss: 0.38481268286705017, G Loss: 2.179786205291748\n", 334 | "Epoch: 17/30, Step: 16000, D Loss: 0.2670775055885315, G Loss: 2.555079698562622\n", 335 | "Epoch: 17/30, Step: 16500, D Loss: 0.4881252348423004, G Loss: 0.6407601237297058\n", 336 | "Epoch: 18/30, Step: 17000, D Loss: 0.44740352034568787, G Loss: 1.8447380065917969\n", 337 | "Epoch: 18/30, Step: 17500, D Loss: 0.32545846700668335, G Loss: 1.244987964630127\n", 338 | "Epoch: 19/30, Step: 18000, D Loss: 0.3907506465911865, G Loss: 2.2971487045288086\n", 339 | "Epoch: 19/30, Step: 18500, D Loss: 0.4499781131744385, G Loss: 2.0843355655670166\n", 340 | "Epoch: 20/30, Step: 19000, D Loss: 0.3507501482963562, G Loss: 1.8766827583312988\n", 341 | "Epoch: 20/30, Step: 19500, D Loss: 0.41672438383102417, G Loss: 2.4048855304718018\n", 342 | "Epoch: 21/30, Step: 20000, D Loss: 0.31802812218666077, G Loss: 2.2574410438537598\n", 343 | "Epoch: 21/30, Step: 20500, D Loss: 0.3652912676334381, G Loss: 1.845369577407837\n", 344 | "Epoch: 22/30, Step: 21000, D Loss: 0.4425152540206909, G Loss: 2.848350763320923\n", 345 | "Epoch: 22/30, Step: 21500, D Loss: 0.40185287594795227, G Loss: 3.0943799018859863\n", 346 | "Epoch: 23/30, Step: 22000, D Loss: 0.3489686846733093, G Loss: 2.381059169769287\n", 347 | "Epoch: 24/30, Step: 22500, D Loss: 0.4847504198551178, G Loss: 1.7365357875823975\n", 348 | "Epoch: 24/30, Step: 23000, D Loss: 0.4196416735649109, G Loss: 2.341548442840576\n", 349 | "Epoch: 25/30, Step: 23500, D Loss: 0.3331816494464874, G Loss: 1.4263110160827637\n", 350 | "Epoch: 25/30, Step: 24000, D Loss: 0.5935764908790588, G Loss: 2.4271726608276367\n", 351 | "Epoch: 26/30, Step: 24500, D Loss: 0.3213740885257721, G Loss: 2.7648630142211914\n", 352 | "Epoch: 26/30, Step: 25000, D Loss: 0.6007185578346252, G Loss: 2.2156314849853516\n", 353 | "Epoch: 27/30, Step: 25500, D Loss: 0.3478204011917114, G Loss: 1.6239631175994873\n", 354 | "Epoch: 27/30, Step: 26000, D Loss: 0.35690590739250183, G Loss: 2.510906457901001\n", 355 | "Epoch: 28/30, Step: 26500, D Loss: 0.3491174876689911, G Loss: 2.117020845413208\n", 356 | "Epoch: 28/30, Step: 27000, D Loss: 0.40436598658561707, G Loss: 2.0063576698303223\n", 357 | "Epoch: 29/30, Step: 27500, D Loss: 0.4856051802635193, G Loss: 2.291684627532959\n", 358 | "Epoch: 29/30, Step: 28000, D Loss: 0.2775539457798004, G Loss: 1.694042682647705\n" 359 | ] 360 | } 361 | ], 362 | "source": [ 363 | "for epoch in range(max_epoch):\n", 364 | " for idx, (images, labels) in enumerate(data_loader):\n", 365 | " # Training Discriminator\n", 366 | " x = images.to(DEVICE)\n", 367 | " x_outputs = D(x)\n", 368 | " D_x_loss = criterion(x_outputs, D_labels)\n", 369 | "\n", 370 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 371 | " z_outputs = D(G(z))\n", 372 | " D_z_loss = criterion(z_outputs, D_fakes)\n", 373 | " D_loss = D_x_loss + D_z_loss\n", 374 | " \n", 375 | " D.zero_grad()\n", 376 | " D_loss.backward()\n", 377 | " D_opt.step()\n", 378 | "\n", 379 | " if step % n_critic == 0:\n", 380 | " # Training Generator\n", 381 | " z = torch.randn(batch_size, n_noise).to(DEVICE)\n", 382 | " z_outputs = D(G(z))\n", 383 | " G_loss = criterion(z_outputs, D_labels)\n", 384 | "\n", 385 | " D.zero_grad()\n", 386 | " G.zero_grad()\n", 387 | " G_loss.backward()\n", 388 | " G_opt.step()\n", 389 | " \n", 390 | " if step % 500 == 0:\n", 391 | " print('Epoch: {}/{}, Step: {}, D Loss: {}, G Loss: {}'.format(epoch, max_epoch, step, D_loss.item(), G_loss.item()))\n", 392 | " \n", 393 | " if step % 1000 == 0:\n", 394 | " G.eval()\n", 395 | " img = get_sample_image(G, n_noise)\n", 396 | " imsave('samples/{}_step{}.jpg'.format(MODEL_NAME, str(step).zfill(3)), img, cmap='gray')\n", 397 | " G.train()\n", 398 | " step += 1" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": null, 404 | "metadata": { 405 | "collapsed": true 406 | }, 407 | "outputs": [], 408 | "source": [] 409 | }, 410 | { 411 | "cell_type": "markdown", 412 | "metadata": {}, 413 | "source": [ 414 | "## Sample" 415 | ] 416 | }, 417 | { 418 | "cell_type": "code", 419 | "execution_count": 18, 420 | "metadata": {}, 421 | "outputs": [ 422 | { 423 | "data": { 424 | "text/plain": [ 425 | "" 426 | ] 427 | }, 428 | "execution_count": 18, 429 | "metadata": {}, 430 | "output_type": "execute_result" 431 | }, 432 | { 433 | "data": { 434 | "image/png": "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\nrkJggg==\n", 435 | "text/plain": [ 436 | "" 437 | ] 438 | }, 439 | "metadata": {}, 440 | "output_type": "display_data" 441 | } 442 | ], 443 | "source": [ 444 | "# generation to image\n", 445 | "G.eval()\n", 446 | "imshow(get_sample_image(G, n_noise), cmap='gray')" 447 | ] 448 | }, 449 | { 450 | "cell_type": "code", 451 | "execution_count": null, 452 | "metadata": { 453 | "collapsed": true 454 | }, 455 | "outputs": [], 456 | "source": [] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "execution_count": 15, 461 | "metadata": { 462 | "collapsed": true 463 | }, 464 | "outputs": [], 465 | "source": [ 466 | "def save_checkpoint(state, file_name='checkpoint.pth.tar'):\n", 467 | " torch.save(state, file_name)" 468 | ] 469 | }, 470 | { 471 | "cell_type": "code", 472 | "execution_count": 16, 473 | "metadata": { 474 | "collapsed": true 475 | }, 476 | "outputs": [], 477 | "source": [ 478 | "# Saving params.\n", 479 | "# torch.save(D.state_dict(), 'D_c.pkl')\n", 480 | "# torch.save(G.state_dict(), 'G_c.pkl')\n", 481 | "save_checkpoint({'epoch': epoch + 1, 'state_dict':D.state_dict(), 'optimizer' : D_opt.state_dict()}, 'D_dc.pth.tar')\n", 482 | "save_checkpoint({'epoch': epoch + 1, 'state_dict':G.state_dict(), 'optimizer' : G_opt.state_dict()}, 'G_dc.pth.tar')" 483 | ] 484 | }, 485 | { 486 | "cell_type": "code", 487 | "execution_count": null, 488 | "metadata": { 489 | "collapsed": true 490 | }, 491 | "outputs": [], 492 | "source": [] 493 | } 494 | ], 495 | "metadata": { 496 | "kernelspec": { 497 | "display_name": "Python 3", 498 | "language": "python", 499 | "name": "python3" 500 | }, 501 | "language_info": { 502 | "codemirror_mode": { 503 | "name": "ipython", 504 | "version": 3 505 | }, 506 | "file_extension": ".py", 507 | "mimetype": "text/x-python", 508 | "name": "python", 509 | "nbconvert_exporter": "python", 510 | "pygments_lexer": "ipython3", 511 | "version": "3.6.3" 512 | } 513 | }, 514 | "nbformat": 4, 515 | "nbformat_minor": 2 516 | } 517 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GANs Tutorial 2 | Very simple implementation of GANs, DCGANs, CGANs, WGANs, and etc. with PyTorch for various dataset (MNIST, CARS, CelebA). 3 | 4 | You can run the code at Jupyter Notebook. And actually you can also run these codes by using Google Colab immediately (needed downloading some dataset)! 5 | 6 | Sometimes ipynb files do not work in Github, please clone and run it in your server. 7 | 8 | ## Requirements 9 | >* python 3.6 (Anaconda) 10 | >* pytorch 1.0.0 (updated from 0.4.0. If you want to use the previous version, then find previous commit.) 11 | 12 | ## Implementation List 13 | #### MNIST 14 | >* [Vanilla GAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/MNIST/VanillaGAN.ipynb) 15 | >* [Conditional GANs](https://github.com/Yangyangii/GAN-Tutorial/blob/master/MNIST/Conditional-GAN.ipynb) 16 | >* [DCGAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/MNIST/DCGAN.ipynb) 17 | >* [Wasserstain GAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/MNIST/W-GAN.ipynb) 18 | >* [WGAN-gp](https://github.com/Yangyangii/GAN-Tutorial/blob/master/MNIST/WGAN-GP.ipynb) 19 | >* [infoGAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/MNIST/infoGAN.ipynb) 20 | 21 | #### CARS (Stanford dataset) 22 | >* you can download the dataset from [https://ai.stanford.edu/~jkrause/cars/car_dataset.html](https://ai.stanford.edu/~jkrause/cars/car_dataset.html) 23 | >* [DCGAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/CARS/DCGAN.ipynb) 24 | >* But I think the dataset is small and needs preprocessing a lot. 25 | 26 | #### CelebA (aligned dataset) 27 | >* you can download the dataset from [http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html](http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html) 28 | >* [BEGAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/CelebA/BEGAN.ipynb) 29 | >* [R1GAN](https://github.com/Yangyangii/GAN-Tutorial/blob/master/CelebA/R1GAN.ipynb) 30 | 31 | 32 | ## Experimental Results 33 | - You can also see the samples at ipynbs. 34 | - After DCGAN, DCGAN with condition is a base model. 35 | - Trained 30 epochs respectively. 36 | 37 | ### Vanilla GAN 38 | 39 | 40 | ### Conditional GAN 41 | 42 | 43 | ### DC GAN 44 | 45 | 46 | ### WGAN-gp 47 | 48 | 49 | ### infoGAN w/ walking code 1 50 | 51 | 52 | ### infoGAN w/ walking code 2 53 | 54 | 55 | ### BEGAN random samples (20 epochs) 56 | 57 | 58 | ### BEGAN interpolation 59 | 60 | 61 | ### GAN with R1 regularization random samples (20 epochs) 62 | 63 | 64 | 65 | ### GAN with R1 regularization interpolation 66 | 67 | 68 | ## Colab 69 | - [https://colab.research.google.com](https://colab.research.google.com) 70 | - You can run it with GPU(K80) Runtime mode 71 | - Training Vanilla GAN takes only 10 minutes. 72 | ![Colab](/images/colab-usage.JPG "Optional title") 73 | -------------------------------------------------------------------------------- /images/BEGAN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/BEGAN.jpg -------------------------------------------------------------------------------- /images/CGAN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/CGAN.jpg -------------------------------------------------------------------------------- /images/Conditional-DCGAN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/Conditional-DCGAN.gif -------------------------------------------------------------------------------- /images/Conditional-GAN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/Conditional-GAN.gif -------------------------------------------------------------------------------- /images/DCGAN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/DCGAN.jpg -------------------------------------------------------------------------------- /images/R1GAN-interp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/R1GAN-interp.jpg -------------------------------------------------------------------------------- /images/R1GAN-sample1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/R1GAN-sample1.jpg -------------------------------------------------------------------------------- /images/R1GAN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/R1GAN.jpg -------------------------------------------------------------------------------- /images/Vanilla-GAN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/Vanilla-GAN.gif -------------------------------------------------------------------------------- /images/VanillaGAN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/VanillaGAN.jpg -------------------------------------------------------------------------------- /images/WGAN-gp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/WGAN-gp.gif -------------------------------------------------------------------------------- /images/WGAN-gp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/WGAN-gp.jpg -------------------------------------------------------------------------------- /images/colab-usage.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/colab-usage.JPG -------------------------------------------------------------------------------- /images/infoGAN_type1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/infoGAN_type1.jpg -------------------------------------------------------------------------------- /images/infoGAN_type2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/infoGAN_type2.jpg -------------------------------------------------------------------------------- /images/interpolation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yangyangii/GAN-Tutorial/d91ca605bc9aa23251a9cdb01b8f9d5da88ddb91/images/interpolation.jpg --------------------------------------------------------------------------------