Hello! Welcome to our next lesson on generative models.
In our last session, we implemented a Deep Convolutional GAN (DCGAN). We saw how a set of specific architectural guidelines—like using strided convolutions, batch normalization, and specific activation functions—dramatically improved the stability and output quality compared to a simple MLP-based GAN. However, even with these improvements, the fundamental training process can still be brittle. The loss function we used, Binary Cross-Entropy, doesn't always correlate with image quality, and training can still suffer from vanishing gradients or mode collapse.
Today, we will address these core issues by changing the loss function itself. Your learning outcome is to implement Wasserstein GANs (WGANs) for improved training stability. This is a significant theoretical step forward, introducing a loss function grounded in a more robust measure of distance between probability distributions.
We'll cover:
- The theoretical flaws of the standard GAN loss function (which approximates Jensen-Shannon divergence).
- The concept of Wasserstein distance (or Earth Mover's distance) and why it's a better metric for training GANs.
- The architectural and loss function changes required to build a WGAN, including the role of the "critic" and the Lipschitz constraint.
- Implementing the original WGAN using weight clipping.
- Identifying the drawbacks of weight clipping and implementing the improved WGAN with Gradient Penalty (WGAN-GP).
By the end of this lesson, you'll understand and be able to implement a more robust and principled GAN training framework that has become a cornerstone of modern generative modeling.
1. The Trouble with Divergence: Why GANs are Hard to Train
The core problem with vanilla GAN training lies in its loss function. The minimax game with an optimal discriminator aims to minimize the Jensen-Shannon (JS) divergence between the real data distribution and the generated data distribution .
This sounds reasonable, but it has a major practical flaw. As your previous experience with programming might suggest, a good cost function should provide a useful signal (a non-zero gradient) to guide optimization. The JS divergence fails to do this when the two distributions are "disjoint"—that is, when they don't have significant overlap.
In high-dimensional spaces like images, it's almost certain that the manifold of real images and the manifold of generated images will be disjoint, especially early in training.
To understand this problem more deeply, let's read a section from Lilian Weng's excellent blog post, 'From GAN to WGAN'. This will provide the theoretical foundation for why we need a new approach.
Read the section titled 'Problems in GANs'. Focus on the subsections 'Low dimensional supports' and 'Vanishing gradient'. These parts explain how disjoint distributions lead to a perfect discriminator and, counter-intuitively, zero gradient for the generator.
As the article explains, when the distributions are disjoint, the discriminator can become "perfect" very quickly, classifying real and fake images with 100% accuracy. For the generator, this is a dead end: the discriminator's gradient becomes zero, providing no information on how to improve. It's like a student getting a score of 0, but with no feedback on what they did wrong.

2. A Better Metric: The Wasserstein (Earth Mover's) Distance
To solve the vanishing gradient problem, the WGAN paper proposed using a different metric: the Wasserstein-1 distance, also known as the Earth Mover's (EM) distance.
The intuition is simple: imagine the two probability distributions are two piles of dirt. The EM distance is the minimum "cost" to transform one pile into the shape of the other. The cost is defined as the amount of dirt moved multiplied by the distance it is moved.
Unlike JS divergence, which gives a binary "they are different" or "they are the same" signal for disjoint distributions, the Wasserstein distance provides a smooth, continuous measure of how far apart they are. This gives the generator a meaningful gradient to follow, even when its outputs are easily distinguishable from real data.
Let's formalize this intuition. The 'What is Wasserstein distance?' section from the 'From GAN to WGAN' article provides a great explanation, starting with a simple discrete example and building up to the continuous case.
Read the subsections 'What is Wasserstein distance?' and 'Why Wasserstein is better than JS or KL divergence?'. This will solidify your understanding of the core concept behind WGANs.
The WGAN Loss Function
Calculating the EM distance directly is intractable. However, the Kantorovich-Rubinstein duality allows us to re-express it in a more usable form:
This looks complex, but the idea is powerful:
- We need to find a function that has a Lipschitz constant of at most 1 (it is 1-Lipschitz). This essentially means the function's gradient norm is bounded by 1 everywhere.
- The GAN's discriminator is repurposed into a "critic". Its job is no longer to output a probability, but to learn the function that maximizes the difference between the scores for real images () and fake images ().
- The value of this maximization is the Wasserstein distance, which becomes the critic's loss.
- The generator's loss is simply , as it tries to produce images that get a high score from the critic.
3. Implementing the Original WGAN with Weight Clipping
Let's put this theory into practice. Our starting point will be the DCGAN code from the previous lesson. The changes are surprisingly minimal. The first WGAN paper proposed a simple (though flawed) way to enforce the 1-Lipschitz constraint: weight clipping. After each critic update, we simply clamp all its weights to a small range, like [-0.01, 0.01].
WGAN implementation from scratch (with gradient penalty)
The video 'WGAN implementation from scratch' by Aladdin Persson, from the same creator as our last lesson's video, walks through converting a DCGAN to a WGAN. This is a perfect hands-on guide.
Watch from the beginning to 15:47. This covers the theory and the complete implementation of the original WGAN. Intro & Theory (00:00 - 06:46): A recap of the theory we just discussed, including the WGAN objective and the Lipschitz constraint. Practical Steps (06:46 - 09:11): An overview of the implementation details, including the critic update ratio and weight clipping. Code Implementation (09:11 - 15:47): Follow along as the DCGAN code is modified. Pay close attention to: Removing the Sigmoid from the discriminator. Changing the loss calculation for both the critic and generator. Using the clamp_ function to perform weight clipping. Training the critic for several iterations for every one generator update (a common practice in WGANs).
This WGAN with weight clipping is already a huge improvement. The loss of the critic now meaningfully correlates with the quality of the generated images—as the loss goes down, the image quality goes up. This gives us a reliable metric to track training progress, something we lacked with standard GANs.
4. An Improvement: WGAN with Gradient Penalty (WGAN-GP)
Weight clipping is a simple hack, but it has significant problems.
- Reduced Model Capacity: It forces the network to learn a much simpler function than it might need to by pushing weights to the boundaries (
-cand+c). - Vanishing/Exploding Gradients: If the clipping value
cis too small, gradients can vanish. If it's too large, it takes a long time to have any effect, making training unstable.

A much better way to enforce the Lipschitz constraint is with a gradient penalty. The theory states that a differentiable function is 1-Lipschitz if and only if its gradients have a norm of at most 1 everywhere.
The WGAN-GP paper proposes adding a "penalty" term to the critic's loss. This term punishes the critic if the norm of its gradient (with respect to its input) deviates from 1.
The penalty is calculated on images that are interpolated between real () and fake () samples: .
The new critic loss becomes:
5. Implementing WGAN-GP
This brings us to the modern, standard implementation of WGAN. The main change is to replace the weight clipping loop with a function that calculates this gradient penalty and adds it to the loss. Your CS background will be useful here, as this involves using PyTorch's autograd capabilities more directly.
WGAN implementation from scratch (with gradient penalty)
Let's continue with the same video, which now introduces and implements the gradient penalty.
Watch from 15:47 to the end (26:00). WGAN-GP Intro (15:47 - 18:42): This section explains the limitations of weight clipping and introduces the gradient penalty concept, showing the new loss function. gradient_penalty Function (18:42 - 22:27): This is the most important part. Follow the implementation of the gradient_penalty function. Note how torch.autograd.grad is used to compute the gradients of the critic's output with respect to the interpolated input images. Final Training Loop (22:27 - 26:00): See how the gradient_penalty is integrated into the critic's loss, the weight clipping loop is removed, and the optimizer is switched to Adam with specific beta values (beta1=0.0, beta2=0.9) as recommended by the WGAN-GP paper.
Test your understanding!
In the WGAN-GP loss, the gradient penalty term aims to keep the L2 norm of the critic's gradient with respect to its input close to 1. Why is the penalty calculated on interpolated images () rather than just on real or fake images?
Show answer
The theory requires the 1-Lipschitz constraint to hold everywhere. Enforcing it only on real or fake samples is not enough; the critic could still have undesirable behavior in the space between the real and generated distributions. By sampling points along the straight lines connecting pairs of real and fake images, we enforce the constraint over a much wider and more relevant portion of the input space. This empirically proves to be sufficient to stabilize training and ensures the critic behaves well everywhere that matters.
Conclusion
Congratulations on completing this lesson! You've tackled one of the most important theoretical and practical advancements in GANs. Moving from a standard GAN to a WGAN-GP fundamentally changes the training dynamic, making it more stable and interpretable.
Key Takeaways:
- Standard GANs suffer from training instability because their loss function (approximating JS divergence) provides vanishing gradients for disjoint distributions.
- Wasserstein distance offers a smoother metric that provides useful gradients even when the critic can easily distinguish real from fake.
- WGANs repurpose the discriminator into a critic that outputs a real-valued score. The training goal is to estimate the Wasserstein distance.
- This requires enforcing a 1-Lipschitz constraint on the critic.
- Weight clipping was the first method proposed but is flawed, as it reduces model capacity and is sensitive to hyperparameters.
- WGAN-GP is the superior, modern approach, using a gradient penalty to enforce the constraint, leading to much more stable training and higher-quality results.
Preview of the next lesson:
Now that we have a stable foundation for GAN training with WGAN-GP, we can explore more advanced architectures that offer greater control over the generation process and can produce even higher-fidelity images. In our next lesson, we will dive into advanced GAN architectures, focusing on Conditional GANs (cGANs), which allow us to guide image generation with labels, and getting a first look at the ideas behind StyleGAN, a model famous for its photorealistic outputs.