diff --git a/README.md b/README.md index e06fa78..ef35068 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,41 @@ -## Bugs ## -There are a few bugs in the code, and convergence issues that I hope to fix soon the moment I get access to a decent GPU / have some more time. Please do not waste hours training the model as is. If you get a chance to fix anything, please make a PR. - - -## KERAS-DCGAN ## -Implementation of http://arxiv.org/abs/1511.06434 with the (awesome) [keras](https://github.com/fchollet/keras) library, for generating artificial images with deep learning. - -This trains two adversarial deep learning models on real images, in order to produce artificial images that look real. - -The generator model tries to produce images that look real and get a high score from the discriminator. - -The discriminator model tries to tell apart between real images and artificial images from the generator. - -Usage ------ -**Training:** - `python dcgan.py --mode train --path --batch_size ` - - python dcgan.py --mode train --path ~/images --batch_size 128 - -**Image generation:** -`python dcgan.py --mode generate --batch_size ` - -python dcgan.py --mode generate --batch_size 128 - +## KERAS-DCGAN ## +Implementation of http://arxiv.org/abs/1511.06434 with the (awesome) [keras](https://github.com/fchollet/keras) library, for generating artificial images with deep learning. + +This trains two adversarial deep learning models on real images, in order to produce artificial images that look real. + +The generator model tries to produce images that look real and get a high score from the discriminator. + +The discriminator model tries to tell apart between real images and artificial images from the generator. + +Usage +----- +**Training:** + `python dcgan.py --mode train --batch_size ` + + python dcgan.py --mode train --path ~/images --batch_size 128 + +**Image generation:** +`python dcgan.py --mode generate --batch_size ` + +`python dcgan.py --mode generate --batch_size --nice` : top 5% images according to discriminator + +python dcgan.py --mode generate --batch_size 128 + + +## Result + +**generated images :** ** + +![generated_image.png](.\assets\generated_image.png) + + +![nice_generated_image.png](.\assets\nice_generated_image.png) + + +**train process :** + +![training_process.gif](.\assets\training_process.gif) + + +--- + diff --git a/assets/generated_image.png b/assets/generated_image.png new file mode 100644 index 0000000..159782f Binary files /dev/null and b/assets/generated_image.png differ diff --git a/assets/nice_generated_image.png b/assets/nice_generated_image.png new file mode 100644 index 0000000..5fc8d5f Binary files /dev/null and b/assets/nice_generated_image.png differ diff --git a/assets/training_process.gif b/assets/training_process.gif new file mode 100644 index 0000000..174fdaf Binary files /dev/null and b/assets/training_process.gif differ diff --git a/dcgan.py b/dcgan.py index 313af5d..59d7ced 100644 --- a/dcgan.py +++ b/dcgan.py @@ -81,8 +81,8 @@ def train(BATCH_SIZE): generator = generator_model() discriminator_on_generator = \ generator_containing_discriminator(generator, discriminator) - d_optim = SGD(lr=0.0005, momentum=0.6, nesterov=True) - g_optim = SGD(lr=0.0005, momentum=0.6, nesterov=True) + d_optim = SGD(lr=0.0005, momentum=0.9, nesterov=True) + g_optim = SGD(lr=0.0005, momentum=0.9, nesterov=True) generator.compile(loss='binary_crossentropy', optimizer="SGD") discriminator_on_generator.compile( loss='binary_crossentropy', optimizer=g_optim) @@ -118,23 +118,46 @@ def train(BATCH_SIZE): discriminator.save_weights('discriminator', True) -def generate(BATCH_SIZE): +def generate(BATCH_SIZE, nice=False): generator = generator_model() generator.compile(loss='binary_crossentropy', optimizer="SGD") generator.load_weights('generator') - noise = np.zeros((BATCH_SIZE, 100)) - for i in range(BATCH_SIZE): - noise[i, :] = np.random.uniform(-1, 1, 100) - generated_images = generator.predict(noise, verbose=1) - image = combine_images(generated_images) + if nice: + discriminator = discriminator_model() + discriminator.compile(loss='binary_crossentropy', optimizer="SGD") + discriminator.load_weights('discriminator') + noise = np.zeros((BATCH_SIZE*20, 100)) + for i in range(BATCH_SIZE*20): + noise[i, :] = np.random.uniform(-1, 1, 100) + generated_images = generator.predict(noise, verbose=1) + d_pret = discriminator.predict(generated_images, verbose=1) + index = np.arange(0, BATCH_SIZE*20) + index.resize((BATCH_SIZE*20, 1)) + pre_with_index = list(np.append(d_pret, index, axis=1)) + pre_with_index.sort(key=lambda x: x[0], reverse=True) + nice_images = np.zeros((BATCH_SIZE, 1) + + (generated_images.shape[2:]), dtype=np.float32) + for i in range(int(BATCH_SIZE)): + idx = int(pre_with_index[i][1]) + nice_images[i, 0, :, :] = generated_images[idx, 0, :, :] + image = combine_images(nice_images) + else: + noise = np.zeros((BATCH_SIZE, 100)) + for i in range(BATCH_SIZE): + noise[i, :] = np.random.uniform(-1, 1, 100) + generated_images = generator.predict(noise, verbose=1) + image = combine_images(generated_images) image = image*127.5+127.5 - Image.fromarray(image.astype(np.uint8)).save("generated_image.png") + Image.fromarray(image.astype(np.uint8)).save( + "generated_image.png") def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--mode", type=str) parser.add_argument("--batch_size", type=int, default=128) + parser.add_argument("--nice", dest="nice", action="store_true") + parser.set_defaults(nice=False) args = parser.parse_args() return args @@ -143,4 +166,4 @@ if __name__ == "__main__": if args.mode == "train": train(BATCH_SIZE=args.batch_size) elif args.mode == "generate": - generate(BATCH_SIZE=args.batch_size) + generate(BATCH_SIZE=args.batch_size, nice=args.nice)