As we closed the previous module, we left one idea hanging: every model we have built so far for TecnoMarket — the MNIST dense network, the mini-VGG for product photos, the review classifier, the sales LSTM — classifies or predicts, but none of them creates. In this lesson we cross that frontier with generative adversarial networks (GANs), an architecture in which two networks compete against each other until one of them learns to generate new data indistinguishable from the real thing. For TecnoMarket this opens a very concrete door: generating promotional images and augmenting the data for products with few photos. Here you will learn the technique and its architecture; the full guided training project comes in lesson 07-04.

Contents

  1. Discriminative vs. generative models
  2. The adversarial idea: counterfeiter versus police
  3. The latent space
  4. The training dynamics and their losses
  5. Typical GAN problems
  6. Key variants: DCGAN, conditional GAN, and company
  7. Skeleton of a DCGAN in Keras
  8. GANs at TecnoMarket: uses and limits

Discriminative vs. generative models

Every model in the course up to this point belongs to the same family: discriminative models. They take an input and produce a decision or a number:

  • The dense network from 02-05 takes a digit and answers "it's a 7".
  • The CNN from 03-04 takes a photo and answers "it's a toaster".
  • The LSTM from 04-03 takes a review and answers "negative sentiment".
  • The LSTM from 04-04 takes past sales and answers "tomorrow you'll sell 412 units".

Formally, a discriminative model learns the boundary that separates classes (or the input→output relationship). A generative model does something more ambitious: it learns what the data itself looks like — its distribution — and with that knowledge it can manufacture new examples that never existed.

Aspect Discriminative model Generative model
Question it answers "What is this?" "What does this look like?"
Learns Boundaries between classes The distribution of the data
Output Label, probability, number A new data point (image, text...)
Example in the course Product-photo CNN (03-04) GAN for promotional images
Analogy An art critic A painter

The critic-and-painter analogy is useful: the critic can tell a Velázquez from a forgery without knowing how to paint; the painter, to paint well, needs to understand light, composition, anatomy... in other words, a deeper kind of knowledge. The stroke of genius in GANs is putting a critic and a painter in the ring to train each other.

The adversarial idea: counterfeiter versus police

A GAN is made of two neural networks that compete:

  • The generator (G): the banknote counterfeiter. It takes random noise and produces fake images. At first they are scribbles; its goal is for them to pass as real.
  • The discriminator (D): the police. It receives images (some real ones from the dataset, others manufactured by G) and must say which are genuine. It is a binary classifier, exactly like the ones you already know how to build.

The competition improves them both:

  1. At first, the counterfeiter produces crude banknotes and the police detects them easily.
  2. The counterfeiter studies where it fails (it receives the gradient's "blame assignment", the same backpropagation from 02-03, but flowing through the police) and improves its banknotes.
  3. The police, faced with better forgeries, sharpens its criteria: it checks the watermark, the embossing...
  4. The cycle repeats until the forgeries are so good that the police does barely better than flipping a coin.
flowchart LR
    Z[Random noise z] --> G[Generator]
    G --> F[Fake images]
    R[(Real images<br/>from the dataset)] --> D[Discriminator]
    F --> D
    D --> V{Real or fake?}
    V -- D's error --> D
    V -- gradient through D --> G

Notice the last arrow in the diagram: the generator never sees the real images. It learns only from the discriminator's verdict. All its knowledge about "what a real product photo looks like" reaches it filtered through its adversary.

The latent space

What is that "random noise" fed into the generator? It is a vector z of, say, 100 numbers drawn from a normal distribution. That vector lives in the latent space, and the generator learns to map each point of that space to an image.

This should ring a bell: in 03-04 we saw that a CNN turns images into embeddings — vectors where proximity (cosine similarity) means visual resemblance — and in 04-03 we did the same with words. A GAN's latent space is the same idea in reverse: instead of compressing an image into a vector, we expand a vector into an image. And it inherits the interesting properties of embeddings:

  • Nearby points generate similar images: nudge z slightly and the generated toaster changes angle or color a little.
  • You can interpolate: walking the straight line between z1 (which generates a red coffee maker) and z2 (a black coffee maker) produces a smooth transition of in-between coffee makers.
  • Directions with meaning: in well-trained GANs, directions of the latent space emerge that control attributes ("more brightness", "lighter background"), just as word embeddings had directions of meaning.

The generator is, in essence, a decoder from the latent space to image space. Hold on to this idea: in the next lesson (autoencoders) we will build that latent space explicitly and under our control.

The training dynamics and their losses

Training alternates two steps, repeated thousands of times:

Step 1 — train the discriminator (the generator is frozen):

  • It is shown real images labeled 1 and generated images labeled 0.
  • Its loss is the binary cross-entropy (BCE) you already used in 02-04 for binary classification. Nothing new: it is a classifier doing its job.

Step 2 — train the generator (the discriminator is frozen):

  • The generator produces images and hands them to the discriminator labeled 1 ("I want you to believe them").
  • The loss is again BCE, but measured on the discriminator's opinion. If the discriminator says "0.05 probability of real", the generator's loss is high and the gradient tells it how to adjust its weights to fool it better.

This tug of war is a minimax game: the discriminator tries to maximize its accuracy and the generator tries to minimize it. You don't need the full mathematical formalism; the operational intuition is this:

The ideal equilibrium is not for one side to win, but a high-level draw: the generator produces images so good that the discriminator answers ~0.5 ("couldn't tell you") for everything.

This has an important practical consequence that sets GANs apart from everything before: the loss curve no longer decreases monotonically until it settles, like the ones you analyzed in 02-05. The losses of G and D oscillate, rising and falling depending on the rival. To know whether the GAN is doing well, looking at the curves is not enough: you have to look at the generated images periodically.

Typical GAN problems

Training two competing networks is notoriously unstable. These are the three classic problems:

Problem What happens Symptoms Usual remedies
Mode collapse The generator discovers one image that fools the discriminator and produces it every time, ignoring the real diversity All generated samples are nearly identical (e.g., always the same coffee maker at the same angle) Diverse sample batches, variants like WGAN, minibatch discrimination
Instability / imbalance One network crushes the other: if D becomes perfect, the gradient reaching G vanishes (the vanishing gradient from 02-03 reappears) and G stops learning D's loss drops to ~0 and G's shoots up; the images stop improving Low and different learning rates for G and D, label smoothing (labels of 0.9 instead of 1), not overtraining D
Non-convergence The two networks oscillate without reaching equilibrium: G fools, D adapts, G switches strategy... in circles Losses oscillating with no pattern; image quality improves and worsens cyclically Adam with a low beta_1 (0.5), proven architectures (DCGAN), patience and frequent checkpoints

A cross-cutting tip: save generated images every N epochs and compare them. It is the visual equivalent of the train/val curves you already master.

Key variants

The original GAN (2014) used dense layers. The family has grown since; these are the variants you should know at a conceptual level:

  • DCGAN (Deep Convolutional GAN): replaces the dense layers with convolutions. The discriminator is an ordinary CNN (like those in module 3) and the generator uses transposed convolutions that travel the reverse path: from a small vector to a large image, doubling the resolution at each layer. It is the reference architecture to start with and the one we will use in 07-04.
  • Conditional GAN (cGAN): besides the noise, the generator receives a label ("generate a digit 7", "generate a coffee maker"). This controls what gets generated, not just that it looks realistic. For TecnoMarket this is the interesting variant: without a condition, the GAN generates "some product or other"; with a condition, it generates products from the category you ask for.
  • StyleGAN: the family behind the hyper-realistic faces you will have seen online; it introduces fine-grained control by level of detail (pose, features, texture).
  • CycleGAN: translates between domains without paired examples (photo↔painting, summer↔winter). A hint of its commercial usefulness: turning a photo of a sofa into "the same sofa in a Nordic living room".

There is another generative family, diffusion models, which today dominates commercial image generation; we will mention it when discussing trends in 08-03.

Skeleton of a DCGAN in Keras

Let's see how the generator and discriminator take shape for 64×64 color images (like TecnoMarket product thumbnails). This is the architectural skeleton; we will build the full alternating training loop step by step in 07-04.

from tensorflow import keras
from tensorflow.keras import layers

LATENT_DIM = 100  # size of the noise vector z

# --- GENERATOR: from a vector of 100 numbers to a 64x64x3 image ---
generator = keras.Sequential([
    # Project the noise onto a small 4x4 "map" with 512 channels
    layers.Dense(4 * 4 * 512, input_shape=(LATENT_DIM,)),
    layers.Reshape((4, 4, 512)),

    # Each Conv2DTranspose with strides=2 DOUBLES the resolution:
    # it is the inverse of the stride-2 convolution from module 3
    layers.Conv2DTranspose(256, 4, strides=2, padding="same"),  # 8x8
    layers.BatchNormalization(),          # stabilizes (covered in 05-04)
    layers.LeakyReLU(0.2),                # "leaky" ReLU: lets a little
                                          # gradient through on negatives
    layers.Conv2DTranspose(128, 4, strides=2, padding="same"),  # 16x16
    layers.BatchNormalization(),
    layers.LeakyReLU(0.2),

    layers.Conv2DTranspose(64, 4, strides=2, padding="same"),   # 32x32
    layers.BatchNormalization(),
    layers.LeakyReLU(0.2),

    # Final layer: 3 channels (RGB) and tanh -> values in [-1, 1],
    # which is why the real images are normalized to [-1, 1] too
    layers.Conv2DTranspose(3, 4, strides=2, padding="same",
                           activation="tanh"),                  # 64x64x3
], name="generator")

# --- DISCRIMINATOR: a binary CNN like those in module 3 ---
discriminator = keras.Sequential([
    # Stride-2 convolutions that HALVE the resolution
    layers.Conv2D(64, 4, strides=2, padding="same",
                  input_shape=(64, 64, 3)),                     # 32x32
    layers.LeakyReLU(0.2),

    layers.Conv2D(128, 4, strides=2, padding="same"),           # 16x16
    layers.LeakyReLU(0.2),

    layers.Conv2D(256, 4, strides=2, padding="same"),           # 8x8
    layers.LeakyReLU(0.2),

    layers.Flatten(),
    layers.Dropout(0.3),                  # regularization (05-04)
    layers.Dense(1, activation="sigmoid") # probability of "real"
], name="discriminator")

Points worth understanding well:

  • The generator is a CNN in reverse: where the module 3 CNN shrank the image with stride/pooling down to a vector, Conv2DTranspose with strides=2 grows it (4→8→16→32→64). The edges→textures→parts→objects hierarchy is traversed backwards: global structure first, then detail.
  • LeakyReLU instead of ReLU: a plain ReLU gives zero gradient for negative inputs; in such a delicate training setup, that kills neurons and destabilizes things. LeakyReLU lets a small slope (0.2) through in the negative region.
  • Final tanh and data in [-1, 1]: the generator's output range must match the range of the real images the discriminator sees; otherwise, the police would spot the banknotes by the "color of the paper" rather than by their content.
  • The discriminator, in common practice, carries no BatchNormalization in its first layer, and it does carry Dropout: we don't want it to become too good too soon.

GANs at TecnoMarket: uses and limits

Why would an online store want to generate images?

  • Promotional images: generating variations of a product photo (backgrounds, staging, banner compositions) without a photo shoot. A cGAN conditioned on category could produce creative drafts for the design team to refine.
  • Data augmentation for rare products: the photo classifier from 03-04 performs poorly on categories with few images (how many photos are there of an air fryer from a niche brand?). A GAN trained on the category can generate additional synthetic examples to rebalance the dataset, complementing the classic data augmentation we will see in 05-04.
  • Catalog prototyping: visualizing how a product would look in different colors or settings before manufacturing or photographing it.

And the limits, which are not small:

  • Quality and artifacts: a modest GAN generates images with defects (odd textures, impossible geometries). For customer-facing material you have to filter with human review — the same human review queue pattern we set up in the 03-04 pipeline.
  • Training cost: high-quality GANs demand lots of data and lots of GPU; for a mid-sized company it usually pays off more to start from already-trained models (an idea we generalize in 05-03).
  • Risks of misuse: the same technology produces deepfakes and misleading images. Publishing a synthetic image of a product that doesn't match reality is not a technical problem but an ethical and legal one; we cover it in depth in 08-01.

Common Mistakes and Tips

  • Judging the GAN by its loss curves as if it were a classifier. This is mistake number one when coming from discriminative models. The losses of G and D oscillate by design; a G loss dropping to zero is usually a bad sign (D has stopped learning). Evaluate by looking at generated samples.
  • Forgetting to align the ranges. If the real images are in [0, 255] or [0, 1] and the generator emits in [-1, 1] (tanh), the discriminator "wins" trivially. Normalize the real data to [-1, 1].
  • Overtraining the discriminator. It sounds logical ("the better the police, the better the counterfeiter will learn"), but a perfect D returns near-zero gradients to G. Balance, not perfection.
  • Expecting diversity without checking for it. Generate an 8×8 grid of samples with different z values every few epochs; if they all look alike, you have mode collapse and it's worth lowering the learning rate or switching variants.
  • Starting with exotic architectures. DCGAN with the classic hyperparameters (Adam, lr=0.0002, beta_1=0.5) is the sensible starting point; innovate only once the basics work.

Exercises

Exercise 1. Classify each of these models from the course as discriminative or generative, and justify each in one sentence: (a) the sales-forecasting LSTM from 04-04; (b) the generator of a GAN; (c) the discriminator of a GAN; (d) the review classifier from 04-03.

Exercise 2. While training a DCGAN on TecnoMarket coffee-maker photos you observe that, from epoch 40 onwards, the discriminator's loss drops towards 0.01 while the generator's loss keeps climbing, and the generated images stop improving. (a) Which of the three typical problems is this? (b) Propose two concrete remedies.

Exercise 3. In the DCGAN skeleton, work out the sequence of spatial resolutions the generator traverses from the Reshape to the output, and explain the role strides=2 plays in Conv2DTranspose by comparing it with strides=2 in a Conv2D from module 3.

Solutions

Solution 1.

  • (a) Discriminative: it maps an input (a window of past sales) to a numeric prediction; it does not model what the series "look like", only the input→output relationship.
  • (b) Generative: it manufactures new data (images) from noise; implicitly it learns the distribution of the real images.
  • (c) Discriminative: it is a real/fake binary classifier, with BCE, like any classifier from modules 2-3. Living inside a GAN doesn't change its nature.
  • (d) Discriminative: input (review) → label (sentiment).

Solution 2.

  • (a) This is the instability-through-imbalance problem: the discriminator has become nearly perfect and the useful gradient flowing through D towards G vanishes (the same vanishing gradient phenomenon from 02-03), so G can no longer learn.
  • (b) Reasonable remedies: lower the discriminator's learning rate (or train it fewer steps per G step); apply label smoothing (label the real images as 0.9 instead of 1.0 so D doesn't become so confident); add Dropout to the discriminator. Any pair of these is valid.

Solution 3.

The sequence is 4×4 → 8×8 → 16×16 → 32×32 → 64×64: the Reshape creates a 4×4×512 map and each of the four Conv2DTranspose layers with strides=2 doubles the height and width. In an ordinary Conv2D, strides=2 means "jump two positions at a time when sliding the filter", so the output has half the resolution (downsampling, as in module 3). In Conv2DTranspose the operation is inverted: each input position "paints" a neighborhood onto a larger output, so strides=2 doubles the resolution. The generator thus traverses the CNN hierarchy in reverse: from an abstract, small representation to a concrete, large image.

Conclusion

You have crossed the frontier between classifying and creating. The key ideas: generative models learn the distribution of the data, not just boundaries; a GAN pits a generator (counterfeiter) against a discriminator (police) in a minimax game whose goal is a high-level draw; the generator maps a latent space — a close cousin of the embeddings you already knew — to images; and training is unstable by nature, with mode collapse and imbalance as the usual enemies. With the DCGAN you have the reference architecture, and in 07-04 we will train it end to end.

But one question remains open: the GAN builds its latent space "blindly", pushed by an adversary. What if we could construct that latent space directly, by forcing the network to compress and reconstruct the real data? That is exactly the autoencoder, the star of the next lesson — and, along the way, the tool with which TecnoMarket is going to detect fraud.

© Copyright 2026. All rights reserved