You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by GitBox <gi...@apache.org> on 2018/11/07 00:26:41 UTC

[GitHub] anirudhacharya commented on a change in pull request #13144: [MXNET-1203] Tutorial infogan

anirudhacharya commented on a change in pull request #13144: [MXNET-1203] Tutorial infogan 
URL: https://github.com/apache/incubator-mxnet/pull/13144#discussion_r231344020
 
 

 ##########
 File path: docs/tutorials/gluon/info_gan.md
 ##########
 @@ -0,0 +1,438 @@
+
+# Image similarity search with InfoGAN
+
+This notebook shows how to implement an InfoGAN based on Gluon. InfoGAN is an extension of GANs, where the generator input is split in 2 parts: random noise and a latent code c (see [InfoGAN Paper](https://arxiv.org/pdf/1606.03657.pdf)). 
+The codes are made meaningful by maximizing the mutual information between code and generator output. InfoGAN learns a disentangled representation in a completely unsupervised manner. It can be used for many applications such as image similarity search. This notebook uses the DCGAN example from the [Straight Dope Book](https://gluon.mxnet.io/chapter14_generative-adversarial-networks/dcgan.html) and extends it to create an InfoGAN. 
+
+
+```python
+from __future__ import print_function
+from datetime import datetime
+import sys
+import os
+import logging
+import time
+import tarfile
+
+from matplotlib import pyplot as plt
+import mxnet as mx
+from mxnet import gluon
+from mxnet import ndarray as nd
+from mxnet.gluon import nn, utils
+from mxnet import autograd
+from mxboard import SummaryWriter
+import numpy as np
+
+```
+
+The latent code vector c can contain several variables, which can be categorical and/or continuous. We set `n_continuous` to 2 and `n_categories` to 10.
+
+
+```python
+batch_size   = 64
+z_dim        = 100
+n_continuous = 2
+n_categories = 10
+ctx = mx.gpu() if mx.test_utils.list_gpus() else mx.cpu()
+```
+
+Some functions to load and normalize images.
+
+
+```python
+lfw_url = 'http://vis-www.cs.umass.edu/lfw/lfw-deepfunneled.tgz'
+data_path = 'lfw_dataset'
+if not os.path.exists(data_path):
+    os.makedirs(data_path)
+    data_file = utils.download(lfw_url)
+    with tarfile.open(data_file) as tar:
+        tar.extractall(path=data_path)
+
+```
+
+
+```python
+def transform(data, width=64, height=64):
+    data = mx.image.imresize(data, width, height)
+    data = nd.transpose(data, (2,0,1))
+    data = data.astype(np.float32)/127.5 - 1
+    if data.shape[0] == 1:
+        data = nd.tile(data, (3, 1, 1))
+    return data.reshape((1,) + data.shape)
+```
+
+
+```python
+def get_files(data_dir):
+    images    = []
+    filenames = []
+    for path, _, fnames in os.walk(data_dir):
+        for fname in fnames:
+            if not fname.endswith('.jpg'):
+                continue
+            img = os.path.join(path, fname)
+            img_arr = mx.image.imread(img)
+            img_arr = transform(img_arr)
+            images.append(img_arr)
+            filenames.append(path + "/" + fname)
+    return images, filenames        
+```
+
+Load the dataset `lfw_dataset` which contains images of celebrities.
+
+
+```python
+data_dir          =  'lfw_dataset'
+images, filenames = get_files(data_dir)
+split             = int(len(images)*0.8)
+test_images       = images[split:]
+test_filenames    = filenames[split:]
+train_images      = images[:split]
+train_filenames   = filenames[:split]
+
+train_data        = gluon.data.ArrayDataset(nd.concatenate(train_images))
+train_dataloader  = gluon.data.DataLoader(train_data, batch_size=batch_size, shuffle=True, last_batch='rollover', num_workers=4)
+```
+
+## Generator
+Define the Generator model. Architecture is taken from the DCGAN implementation in [Straight Dope Book](https://gluon.mxnet.io/chapter14_generative-adversarial-networks/dcgan.html). The Generator consist of  4 layers where each layer involves a strided convolution, batch normalization, and rectified nonlinearity. It takes as input random noise and the latent code `c` and produces an `(64,64,3)` output image.
+
+
+```python
+class Generator(gluon.HybridBlock):
+    def __init__(self, **kwargs):
+        super(Generator, self).__init__(**kwargs)
+        with self.name_scope():
+            self.prev = nn.HybridSequential()
+            self.prev.add(nn.Dense(1024, use_bias=False), nn.BatchNorm(), nn.Activation(activation='relu'))
+            self.G = nn.HybridSequential()
+         
+            self.G.add(nn.Conv2DTranspose(64 * 8, 4, 1, 0, use_bias=False))
+            self.G.add(nn.BatchNorm())
+            self.G.add(nn.Activation('relu'))
+            self.G.add(nn.Conv2DTranspose(64 * 4, 4, 2, 1, use_bias=False))
+            self.G.add(nn.BatchNorm())
+            self.G.add(nn.Activation('relu'))
+            self.G.add(nn.Conv2DTranspose(64 * 2, 4, 2, 1, use_bias=False))
+            self.G.add(nn.BatchNorm())
+            self.G.add(nn.Activation('relu'))
+            self.G.add(nn.Conv2DTranspose(64, 4, 2, 1, use_bias=False))
+            self.G.add(nn.BatchNorm())
+            self.G.add(nn.Activation('relu'))
+            self.G.add(nn.Conv2DTranspose(3, 4, 2, 1, use_bias=False))
+            self.G.add(nn.Activation('tanh'))
+
+    def hybrid_forward(self, F, x):
+        x = self.prev(x)
+        x = F.reshape(x, (0, -1, 1, 1))
+        return self.G(x)
+```
+
+## Discriminator
+Define the Discriminator and Q model. The Q model shares many layers with the Discriminator. Its task is to estimate the code `c` for a given fake image.  It is used to maximize the lower bound to the mutual information.
+
+
+```python
+class Discriminator(gluon.HybridBlock):
+    def __init__(self, **kwargs):
+        super(Discriminator, self).__init__(**kwargs)
+        with self.name_scope():
+            self.D = nn.HybridSequential()
+            self.D.add(nn.Conv2D(64, 4, 2, 1, use_bias=False))
+            self.D.add(nn.LeakyReLU(0.2))
+            self.D.add(nn.Conv2D(64 * 2, 4, 2, 1, use_bias=False))
+            self.D.add(nn.BatchNorm())
+            self.D.add(nn.LeakyReLU(0.2))
+            self.D.add(nn.Conv2D(64 * 4, 4, 2, 1, use_bias=False))
+            self.D.add(nn.BatchNorm())
+            self.D.add(nn.LeakyReLU(0.2))
+            self.D.add(nn.Conv2D(64 * 8, 4, 2, 1, use_bias=False))
+            self.D.add(nn.BatchNorm())
+            self.D.add(nn.LeakyReLU(0.2))
+
+            self.D.add(nn.Dense(1024, use_bias=False), nn.BatchNorm(), nn.Activation(activation='relu'))
+       
+            self.prob = nn.Dense(1)
+            self.feat = nn.HybridSequential()
+            self.feat.add(nn.Dense(128, use_bias=False), nn.BatchNorm(), nn.Activation(activation='relu'))
+            self.category_prob = nn.Dense(n_categories)
+            self.continuous_mean = nn.Dense(n_continuous)
+            self.Q = nn.HybridSequential()
+            self.Q.add(self.feat, self.category_prob, self.continuous_mean)
+
+    def hybrid_forward(self, F, x):
+        x               = self.D(x)
+        prob            = self.prob(x)
+        feat            = self.feat(x)
+        category_prob   = self.category_prob(feat)
+        continuous_mean = self.continuous_mean(feat)
+        
+        return prob, category_prob, continuous_mean
+```
+
+The InfoGAN has the following layout.
+<img src="https://raw.githubusercontent.com/NRauschmayr/web-data/master/mxnet/doc/tutorials/info_gan/InfoGAN.png" style="width:800px;height:250px;">
+Discriminator and Generator are the same as in the DCGAN example. On top of the Disciminator is the Q model, which is estimating the code `c` for given fake images. The Generator's input is random noise and the latent code `c`.  
+
+## Training Loop
+Initialize Generator and Discriminator and define correspoing trainer function.
+
+
+```python
+generator = Generator()
+generator.hybridize()
+generator.initialize(mx.init.Normal(0.002), ctx=ctx)
+
+discriminator = Discriminator()
+discriminator.hybridize()
+discriminator.initialize(mx.init.Normal(0.002), ctx=ctx)
+
+lr   = 0.0001
+beta = 0.5
+
+g_trainer = gluon.Trainer(generator.collect_params(), 'adam', {'learning_rate': lr, 'beta1': beta})
+d_trainer = gluon.Trainer(discriminator.collect_params(), 'adam', {'learning_rate': lr, 'beta1': beta})
+q_trainer = gluon.Trainer(discriminator.Q.collect_params(), 'adam', {'learning_rate': lr, 'beta1': beta})
+```
+
+Create vectors with real (=1) and fake labels (=0).
+
+
+```python
+real_label = nd.ones((batch_size,), ctx=ctx)
+fake_label = nd.zeros((batch_size,),ctx=ctx)
+```
+
+Load a pertrained model.
+
+
+```python
+if os.path.isfile("infogan_d_latest.params") and os.path.isfile("infogan_g_latest.params"):
+    discriminator.load_parameters('infogan_d_latest.params', ctx=ctx, allow_missing=True, ignore_extra=True)
+    generator.load_parameters('infogan_g_latest.params', ctx=ctx, allow_missing=True, ignore_extra=True)
+```
+
+The latent code $c$ is part of the Generator input and it contains mutliple variables (continuous, categorical) that can represent different distributions. In order to make sure that the Generator uses the latent code, mutual information is introduced into the GAN loss term. Mutual information measures how much X is known given Y or vice versa. It is defined as:
+
+![gif](https://raw.githubusercontent.com/NRauschmayr/web-data/master/mxnet/doc/tutorials/info_gan/entropy.gif) 
+
+The InfoGAN loss is:
+
+![gif](https://raw.githubusercontent.com/NRauschmayr/web-data/master/mxnet/doc/tutorials/info_gan/loss.gif)
 
 Review comment:
   same as above.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services