Quant Memo
Advanced

Generative Adversarial Networks

A generative adversarial network trains two neural networks against each other, one trying to produce fake data convincing enough to fool the other, and the other trying to catch every fake, until the fakes become hard to tell from the real thing.

Prerequisites: The Multilayer Perceptron, Variational Autoencoders

Most models learn from a fixed dataset and a fixed loss function that never changes during training. A generative adversarial network (GAN) does something stranger: it sets up a contest between two networks whose losses are each other's problem, and lets that contest itself do the training.

Picture a forger and an appraiser locked in a loop. The forger paints a fake, the appraiser inspects it and says real or fake, and both learn from the outcome — the forger studies what gave it away and paints a better fake next time, the appraiser studies what fooled them and sharpens their eye next time. Neither one ever sees a rulebook for "what makes a good painting"; both improve purely by competing against an opponent who is also improving. Run that loop long enough and the forger's fakes become good enough that the appraiser is reduced to guessing.

The mechanics, one symbol at a time

The generator GG takes random noise zz (just a vector of random numbers, the raw material it sculpts into a fake) and produces a fake sample G(z)G(z). The discriminator DD takes a sample — real or fake — and outputs a number between 0 and 1, its estimate of the probability the sample is real. They're trained on opposing objectives:

minGmaxD  E[logD(x)]+E[log(1D(G(z)))]\min_G \max_D \; \mathbb{E}[\log D(x)] + \mathbb{E}[\log(1 - D(G(z)))]

In words: the discriminator DD wants to maximize this expression — assign real data xx a high probability of being real (D(x)D(x) close to 1, making logD(x)\log D(x) close to 0, its best case) and assign generated fakes G(z)G(z) a low probability of being real (D(G(z))D(G(z)) close to 0, making log(1D(G(z)))\log(1-D(G(z))) close to 0 too). The generator GG wants to minimize the same expression, which it can only do by making D(G(z))D(G(z)) close to 1 — fooling the discriminator into thinking its fakes are real. Training alternates: hold GG fixed and update DD to get better at catching the current fakes, then hold DD fixed and update GG to get better at fooling the current discriminator, back and forth.

Worked example 1: one discriminator update, scored

A discriminator sees a batch of one real sample and one fake sample. On the real sample xx, it outputs D(x)=0.6D(x) = 0.6 (60% confident it's real — a middling call). On the fake G(z)G(z), it outputs D(G(z))=0.7D(G(z)) = 0.7 (70% confident the fake is real — it's actually being fooled here).

Discriminator's loss contribution: [log(0.6)+log(10.7)]=[log(0.6)+log(0.3)]=[0.511+(1.204)]=1.715-[\log(0.6) + \log(1-0.7)] = -[\log(0.6) + \log(0.3)] = -[-0.511 + (-1.204)] = 1.715.

Compare to a discriminator doing its job well: D(x)=0.95D(x) = 0.95, D(G(z))=0.05D(G(z)) = 0.05. Loss: [log(0.95)+log(0.95)]=[0.051+0.051]=0.103-[\log(0.95) + \log(0.95)] = -[-0.051 + -0.051] = 0.103, much lower. The gradient computed from the first, higher-loss scenario pushes the discriminator's weights toward being more skeptical of samples like that particular fake — sharpening exactly the blind spot the generator just exploited.

Worked example 2: the generator exploiting that same blind spot

Continue from the first discriminator above, which currently rates the fake G(z)G(z) at D(G(z))=0.7D(G(z)) = 0.7 — already fooling it more than half the time. The generator's loss (in the common practical form, maximize logD(G(z))\log D(G(z)) rather than the theoretically equivalent minimize form, because it produces stronger gradients early in training) is log(0.7)=0.357-\log(0.7) = 0.357.

If instead the discriminator had confidently caught the fake, D(G(z))=0.05D(G(z)) = 0.05: the generator's loss is log(0.05)=3.00-\log(0.05) = 3.00, over 8 times larger. That larger loss produces a much stronger gradient pushing the generator's weights to change — specifically, in whatever direction makes future outputs like this one score higher under the current discriminator. This is the mechanism, concretely: whichever network is currently losing the contest gets the larger gradient, which is what keeps the competition balanced instead of one side running away with it early.

Gradient descent
parameter →
position -0.623loss -0.141gradient -0.930converging

GAN training is notoriously harder to watch converge than the single, well-behaved loss surface in the explorer above — because GG and DD are each other's moving target, the loss can oscillate rather than settle, and the explorer's clean "crawling vs. converging vs. overshooting" distinction is a simplification of a genuinely trickier two-player dynamic.

Generator Discriminator z G(z) real / fake? gradient back to generator real data
Real data and generated fakes both flow into the discriminator; its verdict produces gradients that improve the discriminator's judgment and the generator's fakes at the same time.

What this means in practice

GANs are used to generate synthetic financial time series and order-book data for stress-testing and augmenting scarce training data (rare regimes, crisis periods) without waiting for history to repeat itself. Training is genuinely finicky compared to a normal network: the two-player game can fail to converge, oscillate indefinitely, or collapse into mode collapse, where the generator finds one narrow type of output that reliably fools the current discriminator and stops exploring anything else — producing samples that are realistic individually but far less diverse than the real data. Diagnosing a GAN therefore requires watching both losses together and checking output diversity directly, not just watching one loss curve go down the way you would for an ordinary supervised model.

A GAN pits a generator against a discriminator in a minimax game — the generator tries to fool, the discriminator tries to catch — and training alternates between them so each one's improvement forces the other to improve in response, with realistic synthetic data as the byproduct.

The classic confusion: watching the generator's loss go down and concluding the generated samples are getting better. A falling generator loss can just as easily mean the discriminator has gotten worse (stuck, or overwhelmed by mode collapse) rather than the generator getting better — because the loss is relative to a moving opponent, it is not, on its own, a reliable measure of output quality, and diversity and realism should be checked directly, not inferred from either loss curve alone.

Related concepts

Practice in interviews

Further reading

  • Goodfellow et al., Generative Adversarial Networks
  • Goodfellow, Bengio & Courville, Deep Learning, ch. 20
ShareTwitterLinkedIn