Before you start
Compute the discriminator loss and the generator loss of a standard GAN.
A GAN trains two networks against each other. The discriminator D outputs
the probability that an input is real. It wants D(real) near 1 and
D(fake) near 0, so its loss is binary cross entropy on both batches:
d_loss = -mean(log D(real)) - mean(log(1 - D(fake)))
The generator wants its fakes to be called real. Minimising log(1 - D(fake))
gives almost no gradient early in training, when the discriminator easily
rejects every fake. So in practice the generator uses the non-saturating loss:
g_loss = -mean(log D(fake))
You are given the discriminator outputs d_real and d_fake as probabilities.
Return (d_loss, g_loss).
def gan_losses(d_real, d_fake):
Input
gan_losses(np.array([0.9]), np.array([0.1]))
Output
(0.21072103, 2.30258509)
Reasoning
The discriminator is doing well: -ln 0.9 - ln(1 - 0.1) = 0.1054 + 0.1054.
The generator is doing badly: its fake got 0.1, so its loss is
-ln 0.1 = 2.303. That large loss still gives a strong gradient, which is why
the non-saturating form is used.
d_real and d_fake are 1D arrays of probabilities and can have different
lengths.[1e-7, 1 - 1e-7] before taking logs.Check runs the visible cases against a fresh kernel. Submit runs the hidden ones too.
⇧↵run cell