{"id":2141,"date":"2024-08-07T22:44:01","date_gmt":"2024-08-07T22:44:01","guid":{"rendered":"https:\/\/www.w3computing.com\/articles\/?p=2141"},"modified":"2024-08-07T22:44:05","modified_gmt":"2024-08-07T22:44:05","slug":"implementing-gans-generative-adversarial-networks-from-scratch","status":"publish","type":"post","link":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/","title":{"rendered":"Implementing GANs (Generative Adversarial Networks) from Scratch"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is nearly indistinguishable from real data. From generating realistic images to creating synthetic data for training, GANs have a wide range of applications. This tutorial will guide you through the process of implementing GANs from scratch using Python and TensorFlow.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before diving into the implementation, it&#8217;s essential to have a good grasp of the following concepts:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Neural Networks and Deep Learning basics.<\/li>\n\n\n\n<li>Python programming.<\/li>\n\n\n\n<li>TensorFlow or PyTorch basics.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial assumes that you are comfortable with these prerequisites.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction to GANs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">GANs, introduced by Ian Goodfellow and his colleagues in 2014, consist of two neural networks: the Generator and the Discriminator. These two networks compete against each other in a game-theoretic framework. The Generator tries to create realistic data, while the Discriminator attempts to distinguish between real and fake data. Over time, both networks improve, resulting in a Generator capable of producing highly realistic data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Basic Structure of GANs<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Generator<\/strong>: Takes random noise as input and generates data.<\/li>\n\n\n\n<li><strong>Discriminator<\/strong>: Takes data (either real or generated) as input and outputs a probability that the data is real.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The Generator and Discriminator are trained together in a two-player minimax game:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The Discriminator is trained to maximize the probability of assigning the correct label to both real and generated data.<\/li>\n\n\n\n<li>The Generator is trained to minimize the probability that the Discriminator assigns the correct label to the generated data.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Mathematically, the objective can be expressed as:<\/p>\n\n\n<p>$latex \\min_G \\max_D V(D, G) = \\mathbb{E}{x \\sim p{\\text{data}}(x)} [\\log D(x)] + \\\\<br \/>\n\\mathbb{E}_{z \\sim p_z(z)} [\\log(1 &#8211; D(G(z)))]&#038;s=2$<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Where:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=G&#038;bg=ffffff&#038;fg=000&#038;s=2&#038;c=20201002\" alt=\"G\" class=\"latex\" \/> is the Generator.<\/li>\n\n\n\n<li><img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=D&#038;bg=ffffff&#038;fg=000&#038;s=2&#038;c=20201002\" alt=\"D\" class=\"latex\" \/> is the Discriminator.<\/li>\n\n\n\n<li><img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=p_%7B%5Ctext%7Bdata%7D%7D%28x%29&#038;bg=ffffff&#038;fg=000&#038;s=2&#038;c=20201002\" alt=\"p_{&#92;text{data}}(x)\" class=\"latex\" \/> is the distribution of real data.<\/li>\n\n\n\n<li><img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=p_z%28z%29&#038;bg=ffffff&#038;fg=000&#038;s=2&#038;c=20201002\" alt=\"p_z(z)\" class=\"latex\" \/> is the distribution of the noise input to the Generator.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step-by-Step Implementation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We will implement a simple GAN to generate handwritten digits similar to those in the MNIST dataset. The MNIST dataset contains 28&#215;28 grayscale images of handwritten digits (0-9).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Setup and Dependencies<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">First, we need to install and import the necessary libraries. We will use TensorFlow for building and training our GAN.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-keyword\">import<\/span> tensorflow <span class=\"hljs-keyword\">as<\/span> tf\n<span class=\"hljs-keyword\">from<\/span> tensorflow.keras <span class=\"hljs-keyword\">import<\/span> layers\n<span class=\"hljs-keyword\">import<\/span> numpy <span class=\"hljs-keyword\">as<\/span> np\n<span class=\"hljs-keyword\">import<\/span> matplotlib.pyplot <span class=\"hljs-keyword\">as<\/span> plt\n\n<span class=\"hljs-comment\"># Ensure we are using TensorFlow 2.x<\/span>\n<span class=\"hljs-keyword\">assert<\/span> tf.__version__.startswith(<span class=\"hljs-string\">'2'<\/span>)\n\n<span class=\"hljs-comment\"># Set random seed for reproducibility<\/span>\nnp.random.seed(<span class=\"hljs-number\">42<\/span>)\ntf.random.set_seed(<span class=\"hljs-number\">42<\/span>)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 2: Data Preparation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We will use the MNIST dataset, which is available in TensorFlow Datasets. The dataset will be normalized to have values between -1 and 1, which is a common practice when training GANs.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-comment\"># Load and preprocess the MNIST dataset<\/span>\n(train_images, _), (_, _) = tf.keras.datasets.mnist.load_data()\ntrain_images = train_images.reshape(train_images.shape&#91;<span class=\"hljs-number\">0<\/span>], <span class=\"hljs-number\">28<\/span>, <span class=\"hljs-number\">28<\/span>, <span class=\"hljs-number\">1<\/span>).astype(<span class=\"hljs-string\">'float32'<\/span>)\ntrain_images = (train_images - <span class=\"hljs-number\">127.5<\/span>) \/ <span class=\"hljs-number\">127.5<\/span>  <span class=\"hljs-comment\"># Normalize the images to &#91;-1, 1]<\/span>\n\n<span class=\"hljs-comment\"># Batch and shuffle the data<\/span>\nBUFFER_SIZE = <span class=\"hljs-number\">60000<\/span>\nBATCH_SIZE = <span class=\"hljs-number\">256<\/span>\n\ntrain_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 3: Build the Generator<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Generator takes random noise as input and produces an image. We&#8217;ll use a simple neural network with Dense and Conv2DTranspose layers to generate 28&#215;28 images.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">make_generator_model<\/span><span class=\"hljs-params\">()<\/span>:<\/span>\n    model = tf.keras.Sequential()\n    model.add(layers.Dense(<span class=\"hljs-number\">7<\/span>*<span class=\"hljs-number\">7<\/span>*<span class=\"hljs-number\">256<\/span>, use_bias=<span class=\"hljs-literal\">False<\/span>, input_shape=(<span class=\"hljs-number\">100<\/span>,)))\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n\n    model.add(layers.Reshape((<span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">256<\/span>)))\n    <span class=\"hljs-keyword\">assert<\/span> model.output_shape == (<span class=\"hljs-literal\">None<\/span>, <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">256<\/span>)  <span class=\"hljs-comment\"># Note: None is the batch size<\/span>\n\n    model.add(layers.Conv2DTranspose(<span class=\"hljs-number\">128<\/span>, (<span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">5<\/span>), strides=(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">1<\/span>), padding=<span class=\"hljs-string\">'same'<\/span>, use_bias=<span class=\"hljs-literal\">False<\/span>))\n    <span class=\"hljs-keyword\">assert<\/span> model.output_shape == (<span class=\"hljs-literal\">None<\/span>, <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">128<\/span>)\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n\n    model.add(layers.Conv2DTranspose(<span class=\"hljs-number\">64<\/span>, (<span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">5<\/span>), strides=(<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">2<\/span>), padding=<span class=\"hljs-string\">'same'<\/span>, use_bias=<span class=\"hljs-literal\">False<\/span>))\n    <span class=\"hljs-keyword\">assert<\/span> model.output_shape == (<span class=\"hljs-literal\">None<\/span>, <span class=\"hljs-number\">14<\/span>, <span class=\"hljs-number\">14<\/span>, <span class=\"hljs-number\">64<\/span>)\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n\n    model.add(layers.Conv2DTranspose(<span class=\"hljs-number\">1<\/span>, (<span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">5<\/span>), strides=(<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">2<\/span>), padding=<span class=\"hljs-string\">'same'<\/span>, use_bias=<span class=\"hljs-literal\">False<\/span>, activation=<span class=\"hljs-string\">'tanh'<\/span>))\n    <span class=\"hljs-keyword\">assert<\/span> model.output_shape == (<span class=\"hljs-literal\">None<\/span>, <span class=\"hljs-number\">28<\/span>, <span class=\"hljs-number\">28<\/span>, <span class=\"hljs-number\">1<\/span>)\n\n    <span class=\"hljs-keyword\">return<\/span> model\n\ngenerator = make_generator_model()<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 4: Build the Discriminator<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Discriminator takes an image as input and outputs a scalar indicating whether the image is real or fake. We&#8217;ll use a convolutional neural network for this task.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">make_discriminator_model<\/span><span class=\"hljs-params\">()<\/span>:<\/span>\n    model = tf.keras.Sequential()\n    model.add(layers.Conv2D(<span class=\"hljs-number\">64<\/span>, (<span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">5<\/span>), strides=(<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">2<\/span>), padding=<span class=\"hljs-string\">'same'<\/span>, input_shape=&#91;<span class=\"hljs-number\">28<\/span>, <span class=\"hljs-number\">28<\/span>, <span class=\"hljs-number\">1<\/span>]))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(<span class=\"hljs-number\">0.3<\/span>))\n\n    model.add(layers.Conv2D(<span class=\"hljs-number\">128<\/span>, (<span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">5<\/span>), strides=(<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">2<\/span>), padding=<span class=\"hljs-string\">'same'<\/span>))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(<span class=\"hljs-number\">0.3<\/span>))\n\n    model.add(layers.Flatten())\n    model.add(layers.Dense(<span class=\"hljs-number\">1<\/span>))\n\n    <span class=\"hljs-keyword\">return<\/span> model\n\ndiscriminator = make_discriminator_model()<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 5: Define the Loss and Optimizers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The loss functions for the Generator and Discriminator are crucial for the training process. We will use binary cross-entropy loss for both. The Generator tries to minimize <code>-log(D(G(z)))<\/code>, while the Discriminator tries to maximize <code>log(D(x)) + log(1 - D(G(z)))<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\">cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=<span class=\"hljs-literal\">True<\/span>)\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">discriminator_loss<\/span><span class=\"hljs-params\">(real_output, fake_output)<\/span>:<\/span>\n    real_loss = cross_entropy(tf.ones_like(real_output), real_output)\n    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)\n    total_loss = real_loss + fake_loss\n    <span class=\"hljs-keyword\">return<\/span> total_loss\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">generator_loss<\/span><span class=\"hljs-params\">(fake_output)<\/span>:<\/span>\n    <span class=\"hljs-keyword\">return<\/span> cross_entropy(tf.ones_like(fake_output), fake_output)\n\ngenerator_optimizer = tf.keras.optimizers.Adam(<span class=\"hljs-number\">1e-4<\/span>)\ndiscriminator_optimizer = tf.keras.optimizers.Adam(<span class=\"hljs-number\">1e-4<\/span>)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 6: Define the Training Loop<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The training loop involves generating random noise, using it to produce fake images with the Generator, and then training both the Generator and Discriminator. We will also periodically generate and save images to monitor the progress of the training.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\">EPOCHS = <span class=\"hljs-number\">50<\/span>\nnoise_dim = <span class=\"hljs-number\">100<\/span>\nnum_examples_to_generate = <span class=\"hljs-number\">16<\/span>\n\n<span class=\"hljs-comment\"># We will reuse this seed over time (so it's easier to visualize progress in the GIF)<\/span>\nseed = tf.random.normal(&#91;num_examples_to_generate, noise_dim])\n\n<span class=\"hljs-comment\"># Notice the use of `tf.function`<\/span>\n<span class=\"hljs-comment\"># This annotation causes the function to be \"compiled\".<\/span>\n<span class=\"hljs-meta\">@tf.function<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">train_step<\/span><span class=\"hljs-params\">(images)<\/span>:<\/span>\n    noise = tf.random.normal(&#91;BATCH_SIZE, noise_dim])\n\n    <span class=\"hljs-keyword\">with<\/span> tf.GradientTape() <span class=\"hljs-keyword\">as<\/span> gen_tape, tf.GradientTape() <span class=\"hljs-keyword\">as<\/span> disc_tape:\n        generated_images = generator(noise, training=<span class=\"hljs-literal\">True<\/span>)\n\n        real_output = discriminator(images, training=<span class=\"hljs-literal\">True<\/span>)\n        fake_output = discriminator(generated_images, training=<span class=\"hljs-literal\">True<\/span>)\n\n        gen_loss = generator_loss(fake_output)\n        disc_loss = discriminator_loss(real_output, fake_output)\n\n    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)\n    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)\n\n    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))\n    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">train<\/span><span class=\"hljs-params\">(dataset, epochs)<\/span>:<\/span>\n    <span class=\"hljs-keyword\">for<\/span> epoch <span class=\"hljs-keyword\">in<\/span> range(epochs):\n        <span class=\"hljs-keyword\">for<\/span> image_batch <span class=\"hljs-keyword\">in<\/span> dataset:\n            train_step(image_batch)\n\n        <span class=\"hljs-comment\"># Produce images for the GIF as we go<\/span>\n        display.clear_output(wait=<span class=\"hljs-literal\">True<\/span>)\n        generate_and_save_images(generator, epoch + <span class=\"hljs-number\">1<\/span>, seed)\n\n        <span class=\"hljs-comment\"># Save the model every 15 epochs<\/span>\n        <span class=\"hljs-keyword\">if<\/span> (epoch + <span class=\"hljs-number\">1<\/span>) % <span class=\"hljs-number\">15<\/span> == <span class=\"hljs-number\">0<\/span>:\n            checkpoint.save(file_prefix = checkpoint_prefix)\n\n    <span class=\"hljs-comment\"># Generate after the final epoch<\/span>\n    display.clear_output(wait=<span class=\"hljs-literal\">True<\/span>)\n    generate_and_save_images(generator, epochs, seed)\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">generate_and_save_images<\/span><span class=\"hljs-params\">(model, epoch, test_input)<\/span>:<\/span>\n    <span class=\"hljs-comment\"># Notice `training` is set to False.<\/span>\n    <span class=\"hljs-comment\"># This is so all layers run in inference mode (batchnorm).<\/span>\n    predictions = model(test_input, training=<span class=\"hljs-literal\">False<\/span>)\n\n    fig = plt.figure(figsize=(<span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">4<\/span>))\n\n    <span class=\"hljs-keyword\">for<\/span> i <span class=\"hljs-keyword\">in<\/span> range(predictions.shape&#91;<span class=\"hljs-number\">0<\/span>]):\n        plt.subplot\n\n(<span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">4<\/span>, i+<span class=\"hljs-number\">1<\/span>)\n        plt.imshow(predictions&#91;i, :, :, <span class=\"hljs-number\">0<\/span>] * <span class=\"hljs-number\">127.5<\/span> + <span class=\"hljs-number\">127.5<\/span>, cmap=<span class=\"hljs-string\">'gray'<\/span>)\n        plt.axis(<span class=\"hljs-string\">'off'<\/span>)\n\n    plt.savefig(<span class=\"hljs-string\">'image_at_epoch_{:04d}.png'<\/span>.format(epoch))\n    plt.show()<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 7: Train the GAN<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Now, we can train our GAN on the MNIST dataset.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\">train(train_dataset, EPOCHS)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Visualizing the Results<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once the training is complete, we can visualize the generated images and see how the Generator has improved over time.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Python\" data-shcb-language-slug=\"python\"><span><code class=\"hljs language-python\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">def<\/span> <span class=\"hljs-title\">display_image<\/span><span class=\"hljs-params\">(epoch_no)<\/span>:<\/span>\n    <span class=\"hljs-keyword\">return<\/span> PIL.Image.open(<span class=\"hljs-string\">'image_at_epoch_{:04d}.png'<\/span>.format(epoch_no))\n\ndisplay_image(EPOCHS)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Python<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">python<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This concludes our implementation of a simple GAN from scratch. We have walked through the process of building, training, and visualizing a GAN using TensorFlow. While this is a basic implementation, it provides a solid foundation for exploring more advanced GAN architectures and techniques.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced Topics<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Conditional GANs (cGANs)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Conditional GANs extend the standard GAN framework by conditioning both the Generator and Discriminator on some extra information. This information can be anything from class labels to other modalities. For example, in a cGAN, the Generator could be conditioned on a class label to generate images of a specific class.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">DCGANs (Deep Convolutional GANs)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Deep Convolutional GANs (DCGANs) are a popular and effective GAN architecture that replaces fully connected layers with convolutional layers. DCGANs have been shown to produce high-quality images and are widely used in practice. The architecture and training techniques introduced in DCGANs can be applied to various GAN variants.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wasserstein GANs (WGANs)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Wasserstein GANs (WGANs) improve the training stability of GANs by using the Earth Mover&#8217;s (Wasserstein) distance instead of the Jensen-Shannon divergence. This modification leads to a more stable training process and better quality of generated samples. WGANs require a slight modification to the Discriminator (called the Critic in WGANs) and the use of weight clipping.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">GAN Applications<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GANs have numerous applications, including:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Image Generation<\/strong>: Creating realistic images from random noise.<\/li>\n\n\n\n<li><strong>Image-to-Image Translation<\/strong>: Translating images from one domain to another, such as turning sketches into photographs.<\/li>\n\n\n\n<li><strong>Data Augmentation<\/strong>: Generating synthetic data to augment training datasets.<\/li>\n\n\n\n<li><strong>Super-Resolution<\/strong>: Enhancing the resolution of images.<\/li>\n\n\n\n<li><strong>Text-to-Image Synthesis<\/strong>: Generating images from textual descriptions.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Tips for Training GANs<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Use Batch Normalization<\/strong>: Helps stabilize training.<\/li>\n\n\n\n<li><strong>Use LeakyReLU Activation<\/strong>: Helps gradients flow through the network.<\/li>\n\n\n\n<li><strong>Label Smoothing<\/strong>: Smooth the labels for real and fake images to help the Discriminator generalize better.<\/li>\n\n\n\n<li><strong>Avoid Mode Collapse<\/strong>: Monitor and adjust training to avoid the Generator producing limited varieties of outputs.<\/li>\n\n\n\n<li><strong>Use Progressive Training<\/strong>: Start with a low resolution and gradually increase the resolution of generated images.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Implementing GANs from scratch provides a deep understanding of their underlying mechanics and challenges. While we have covered the basics and some advanced topics, the field of GANs is rapidly evolving with continuous research and new techniques. Experimenting with different architectures, loss functions, and training strategies will help you gain more insights and potentially contribute to the development of more robust and versatile GAN models.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is nearly indistinguishable from real data. From generating realistic images to creating synthetic data for training, GANs have a wide range of applications. This tutorial will guide you through the process of implementing GANs from scratch using [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[18,4,6],"tags":[],"class_list":["post-2141","post","type-post","status-publish","format-standard","category-artificial-intelligence","category-programming-languages","category-python","entry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Implementing Generative Adversarial Networks from Scratch<\/title>\n<meta name=\"description\" content=\"Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Implementing Generative Adversarial Networks from Scratch\" \/>\n<meta property=\"og:description\" content=\"Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/\" \/>\n<meta property=\"article:published_time\" content=\"2024-08-07T22:44:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-08-07T22:44:05+00:00\" \/>\n<meta name=\"author\" content=\"w3compadmin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"w3compadmin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/\"},\"author\":{\"name\":\"w3compadmin\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"headline\":\"Implementing GANs (Generative Adversarial Networks) from Scratch\",\"datePublished\":\"2024-08-07T22:44:01+00:00\",\"dateModified\":\"2024-08-07T22:44:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/\"},\"wordCount\":1003,\"articleSection\":[\"Artificial Intelligence\",\"Programming Languages\",\"Python\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/\",\"name\":\"Implementing Generative Adversarial Networks from Scratch\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\"},\"datePublished\":\"2024-08-07T22:44:01+00:00\",\"dateModified\":\"2024-08-07T22:44:05+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"description\":\"Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/implementing-gans-generative-adversarial-networks-from-scratch\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Articles Home\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Programming Languages\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Implementing GANs (Generative Adversarial Networks) from Scratch\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\",\"name\":\"Developer Articles Hub\",\"description\":\"\",\"alternateName\":\"Developer Articles\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\",\"name\":\"w3compadmin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"contentUrl\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"caption\":\"w3compadmin\"},\"sameAs\":[\"http:\\\/\\\/w3computing.com\\\/articles\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Implementing Generative Adversarial Networks from Scratch","description":"Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/","og_locale":"en_US","og_type":"article","og_title":"Implementing Generative Adversarial Networks from Scratch","og_description":"Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is","og_url":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/","article_published_time":"2024-08-07T22:44:01+00:00","article_modified_time":"2024-08-07T22:44:05+00:00","author":"w3compadmin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"w3compadmin","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/#article","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/"},"author":{"name":"w3compadmin","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"headline":"Implementing GANs (Generative Adversarial Networks) from Scratch","datePublished":"2024-08-07T22:44:01+00:00","dateModified":"2024-08-07T22:44:05+00:00","mainEntityOfPage":{"@id":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/"},"wordCount":1003,"articleSection":["Artificial Intelligence","Programming Languages","Python"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/","url":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/","name":"Implementing Generative Adversarial Networks from Scratch","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/#website"},"datePublished":"2024-08-07T22:44:01+00:00","dateModified":"2024-08-07T22:44:05+00:00","author":{"@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"description":"Generative Adversarial Networks (GANs) have revolutionized the field of artificial intelligence by enabling machines to create data that is","breadcrumb":{"@id":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.w3computing.com\/articles\/implementing-gans-generative-adversarial-networks-from-scratch\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Articles Home","item":"https:\/\/www.w3computing.com\/articles\/"},{"@type":"ListItem","position":2,"name":"Programming Languages","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/"},{"@type":"ListItem","position":3,"name":"Implementing GANs (Generative Adversarial Networks) from Scratch"}]},{"@type":"WebSite","@id":"https:\/\/www.w3computing.com\/articles\/#website","url":"https:\/\/www.w3computing.com\/articles\/","name":"Developer Articles Hub","description":"","alternateName":"Developer Articles","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.w3computing.com\/articles\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561","name":"w3compadmin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","url":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","contentUrl":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","caption":"w3compadmin"},"sameAs":["http:\/\/w3computing.com\/articles"]}]}},"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"w3compadmin","author_link":"https:\/\/www.w3computing.com\/articles\/author\/w3compadmin\/"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2141","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/comments?post=2141"}],"version-history":[{"count":6,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2141\/revisions"}],"predecessor-version":[{"id":2147,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2141\/revisions\/2147"}],"wp:attachment":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/media?parent=2141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/categories?post=2141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/tags?post=2141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}