├── .gitignore ├── LICENSE ├── README.md └── dcgan.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | #Ipython Notebook 62 | .ipynb_checkpoints 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Yoshihiro Sugi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TensorFlow implementation of DCGAN 2 | 3 | 4 | ### What is DCGAN ? ### 5 | 6 | Deep Convolutional Generative Adversarial Networks 7 | 8 | - http://arxiv.org/abs/1511.06434 9 | 10 | 11 | #### Other implementations of DCGAN #### 12 | 13 | - https://github.com/Newmu/dcgan_code (Theano) 14 | - https://github.com/soumith/dcgan.torch (Torch) 15 | - https://github.com/mattya/chainer-DCGAN (Chainer) 16 | - https://github.com/carpedm20/DCGAN-tensorflow (TensorFlow) 17 | 18 | 19 | ### Prerequisites ### 20 | 21 | - Python >= 2.7 or 3.5 22 | - TensorFlow >= 1.0 23 | 24 | 25 | ### Usage ### 26 | 27 | #### Train #### 28 | 29 | ```python 30 | dcgan = DCGAN() 31 | train_images = 32 | losses = dcgan.loss(train_images) 33 | train_op = dcgan.train(losses) 34 | 35 | with tf.Session() as sess: 36 | sess.run(tf.global_variables_initializer()) 37 | 38 | for step in range(FLAGS.max_steps): 39 | _, g_loss_value, d_loss_value = sess.run([train_op, losses[dcgan.g], losses[dcgan.d]]) 40 | # save trained variables 41 | ``` 42 | 43 | #### Generate #### 44 | 45 | ```python 46 | dcgan = DCGAN() 47 | images = dcgan.sample_images() 48 | 49 | with tf.Session() as sess: 50 | # restore trained variables 51 | 52 | generated = sess.run(images) 53 | with open('', 'wb') as f: 54 | f.write(generated) 55 | ``` 56 | 57 | 58 | ### Example ### 59 | 60 | - https://github.com/sugyan/face-generator 61 | -------------------------------------------------------------------------------- /dcgan.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | class Generator: 5 | def __init__(self, depths=[1024, 512, 256, 128], s_size=4): 6 | self.depths = depths + [3] 7 | self.s_size = s_size 8 | self.reuse = False 9 | 10 | def __call__(self, inputs, training=False): 11 | inputs = tf.convert_to_tensor(inputs) 12 | with tf.variable_scope('g', reuse=self.reuse): 13 | # reshape from inputs 14 | with tf.variable_scope('reshape'): 15 | outputs = tf.layers.dense(inputs, self.depths[0] * self.s_size * self.s_size) 16 | outputs = tf.reshape(outputs, [-1, self.s_size, self.s_size, self.depths[0]]) 17 | outputs = tf.nn.relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 18 | # deconvolution (transpose of convolution) x 4 19 | with tf.variable_scope('deconv1'): 20 | outputs = tf.layers.conv2d_transpose(outputs, self.depths[1], [5, 5], strides=(2, 2), padding='SAME') 21 | outputs = tf.nn.relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 22 | with tf.variable_scope('deconv2'): 23 | outputs = tf.layers.conv2d_transpose(outputs, self.depths[2], [5, 5], strides=(2, 2), padding='SAME') 24 | outputs = tf.nn.relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 25 | with tf.variable_scope('deconv3'): 26 | outputs = tf.layers.conv2d_transpose(outputs, self.depths[3], [5, 5], strides=(2, 2), padding='SAME') 27 | outputs = tf.nn.relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 28 | with tf.variable_scope('deconv4'): 29 | outputs = tf.layers.conv2d_transpose(outputs, self.depths[4], [5, 5], strides=(2, 2), padding='SAME') 30 | # output images 31 | with tf.variable_scope('tanh'): 32 | outputs = tf.tanh(outputs, name='outputs') 33 | self.reuse = True 34 | self.variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='g') 35 | return outputs 36 | 37 | 38 | class Discriminator: 39 | def __init__(self, depths=[64, 128, 256, 512]): 40 | self.depths = [3] + depths 41 | self.reuse = False 42 | 43 | def __call__(self, inputs, training=False, name=''): 44 | def leaky_relu(x, leak=0.2, name=''): 45 | return tf.maximum(x, x * leak, name=name) 46 | outputs = tf.convert_to_tensor(inputs) 47 | 48 | with tf.name_scope('d' + name), tf.variable_scope('d', reuse=self.reuse): 49 | # convolution x 4 50 | with tf.variable_scope('conv1'): 51 | outputs = tf.layers.conv2d(outputs, self.depths[1], [5, 5], strides=(2, 2), padding='SAME') 52 | outputs = leaky_relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 53 | with tf.variable_scope('conv2'): 54 | outputs = tf.layers.conv2d(outputs, self.depths[2], [5, 5], strides=(2, 2), padding='SAME') 55 | outputs = leaky_relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 56 | with tf.variable_scope('conv3'): 57 | outputs = tf.layers.conv2d(outputs, self.depths[3], [5, 5], strides=(2, 2), padding='SAME') 58 | outputs = leaky_relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 59 | with tf.variable_scope('conv4'): 60 | outputs = tf.layers.conv2d(outputs, self.depths[4], [5, 5], strides=(2, 2), padding='SAME') 61 | outputs = leaky_relu(tf.layers.batch_normalization(outputs, training=training), name='outputs') 62 | with tf.variable_scope('classify'): 63 | batch_size = outputs.get_shape()[0].value 64 | reshape = tf.reshape(outputs, [batch_size, -1]) 65 | outputs = tf.layers.dense(reshape, 2, name='outputs') 66 | self.reuse = True 67 | self.variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='d') 68 | return outputs 69 | 70 | 71 | class DCGAN: 72 | def __init__(self, 73 | batch_size=128, s_size=4, z_dim=100, 74 | g_depths=[1024, 512, 256, 128], 75 | d_depths=[64, 128, 256, 512]): 76 | self.batch_size = batch_size 77 | self.s_size = s_size 78 | self.z_dim = z_dim 79 | self.g = Generator(depths=g_depths, s_size=self.s_size) 80 | self.d = Discriminator(depths=d_depths) 81 | self.z = tf.random_uniform([self.batch_size, self.z_dim], minval=-1.0, maxval=1.0) 82 | 83 | def loss(self, traindata): 84 | """build models, calculate losses. 85 | 86 | Args: 87 | traindata: 4-D Tensor of shape `[batch, height, width, channels]`. 88 | 89 | Returns: 90 | dict of each models' losses. 91 | """ 92 | generated = self.g(self.z, training=True) 93 | g_outputs = self.d(generated, training=True, name='g') 94 | t_outputs = self.d(traindata, training=True, name='t') 95 | # add each losses to collection 96 | tf.add_to_collection( 97 | 'g_losses', 98 | tf.reduce_mean( 99 | tf.nn.sparse_softmax_cross_entropy_with_logits( 100 | labels=tf.ones([self.batch_size], dtype=tf.int64), 101 | logits=g_outputs))) 102 | tf.add_to_collection( 103 | 'd_losses', 104 | tf.reduce_mean( 105 | tf.nn.sparse_softmax_cross_entropy_with_logits( 106 | labels=tf.ones([self.batch_size], dtype=tf.int64), 107 | logits=t_outputs))) 108 | tf.add_to_collection( 109 | 'd_losses', 110 | tf.reduce_mean( 111 | tf.nn.sparse_softmax_cross_entropy_with_logits( 112 | labels=tf.zeros([self.batch_size], dtype=tf.int64), 113 | logits=g_outputs))) 114 | return { 115 | self.g: tf.add_n(tf.get_collection('g_losses'), name='total_g_loss'), 116 | self.d: tf.add_n(tf.get_collection('d_losses'), name='total_d_loss'), 117 | } 118 | 119 | def train(self, losses, learning_rate=0.0002, beta1=0.5): 120 | """ 121 | Args: 122 | losses dict. 123 | 124 | Returns: 125 | train op. 126 | """ 127 | g_opt = tf.train.AdamOptimizer(learning_rate=learning_rate, beta1=beta1) 128 | d_opt = tf.train.AdamOptimizer(learning_rate=learning_rate, beta1=beta1) 129 | g_opt_op = g_opt.minimize(losses[self.g], var_list=self.g.variables) 130 | d_opt_op = d_opt.minimize(losses[self.d], var_list=self.d.variables) 131 | with tf.control_dependencies([g_opt_op, d_opt_op]): 132 | return tf.no_op(name='train') 133 | 134 | def sample_images(self, row=8, col=8, inputs=None): 135 | if inputs is None: 136 | inputs = self.z 137 | images = self.g(inputs, training=True) 138 | images = tf.image.convert_image_dtype(tf.div(tf.add(images, 1.0), 2.0), tf.uint8) 139 | images = [image for image in tf.split(images, self.batch_size, axis=0)] 140 | rows = [] 141 | for i in range(row): 142 | rows.append(tf.concat(images[col * i + 0:col * i + col], 2)) 143 | image = tf.concat(rows, 1) 144 | return tf.image.encode_jpeg(tf.squeeze(image, [0])) 145 | --------------------------------------------------------------------------------