{
  "id": 99485,
  "title": "RaLSGAN Explained",
  "url": "/competitions/generative-dog-images/discussion/99485",
  "author_name": "",
  "post_date": "2019-07-11T16:43:25.898372100Z",
  "votes": 83,
  "comment_count": 20,
  "views": 0,
  "content": "<h1>Loss Functions</h1>\n\n<p>There are currently no Kaggle kernels that use RaLSGAN. A few kernels have RaLSGAN in their name, but they are using basic DCGAN. <strong>What is RaLSGAN?</strong> RaLSGAN is just basic GAN with a different loss function.</p>\n\n<p><img src=\"http://playagricola.com/Kaggle/DIS.jpg\" alt=\"image\"></p>\n\n<p>A Discriminator can either output <code>sigmoid</code> activation or <code>linear</code> activation. If sigmoid, we have the probability of an image being real, <code>Pr(Real)</code>. If linear, we have the <a href=\"https://en.wikipedia.org/wiki/Logit\">log odds</a> of being real, <code>Logit</code>. Probabilities are between 0 and 1 inclusive. And Logits can be any number. A positive logit implies image is real, a negative logit implies image is fake.</p>\n\n<h1>Simple Loss</h1>\n\n<p>Define <code>x_r</code> to be a real image, and <code>x_f</code> to be a fake image. Define <code>D(x) = Pr(Real)</code> and <code>C(x) = Logit</code> to be the two different outputs from a Discriminator when you input an image. The simplest possible loss is below. </p>\n\n<pre><code># Take AVG over x_r and x_f in batch\ndisc_loss = (1 - D(x_r)) + (D(x_f) - 0)\ngen_loss = (1 - D(x_f))\n</code></pre>\n\n<p>Minimizing these losses says the following. The Discriminator wants <code>D(x_r)=1</code> and <code>D(x_f)=0</code>, i.e. the Discriminator wants real images to have probably 1 of being real. And wants fake images to have probability 0 of being real. The Generator wants <code>D(x_f)=1</code>, i.e. the Generator wants fakes images to have probability 1 of being real.</p>\n\n<h1>DCGAN Loss</h1>\n\n<p>Basic GAN or DCGAN use the following loss functions. Note that they use <code>D(x)</code>, i.e. probs.</p>\n\n<pre><code># Take AVG over x_r and x_f in batch\ndisc_loss = -log (D(x_r)) - log (1-D(x_f))\ngen_loss = -log (D(x_f))\n</code></pre>\n\n<h1>RaLSGAN Loss</h1>\n\n<p>RaLSGAN uses the following loss functions. Note that they use <code>C(x)</code>, i.e. logits.</p>\n\n<pre><code># Take AVG over x_r and x_f in batch\ndisc_loss = (C(x_r) - AVG(C(x_f)) - 1)^2 + (C(x_f) - AVG(C(x_r)) + 1)^2\ngen_loss = (C(x_r) - AVG(C(x_f)) + 1)^2 + (C(x_f) - AVG(C(x_r)) - 1)^2\n</code></pre>\n\n<h1>Code</h1>\n\n<p>Here's how to update the Kaggle kernel starter code. First, if you fork Kaggle's Starter Code, <strong>turn GPU on</strong>! Second, change the last line of the Discriminator to output linear activation (Logit) by removing sigmoid</p>\n\n<pre><code>       #x = torch.sigmoid(self.conv5(x))\n       x = self.conv5(x)\n</code></pre>\n\n<p>Next, change the following</p>\n\n<pre><code>    ############################\n    # (1) Update D network\n    ###########################\n    netD.zero_grad()\n    real_images = real_images.to(device)\n    batch_size = real_images.size(0)\n    labels = torch.full((batch_size, 1), real_label, device=device)\n    outputR = netD(real_images)\n    noise = torch.randn(batch_size, nz, 1, 1, device=device)\n    fake = netG(noise)\n    outputF = netD(fake.detach())\n    errD = (torch.mean((outputR - torch.mean(outputF) - labels) ** 2) + \n            torch.mean((outputF - torch.mean(outputR) + labels) ** 2))/2\n    errD.backward(retain_graph=True)\n    optimizerD.step()\n    ############################\n    # (2) Update G network\n    ###########################\n    netG.zero_grad()\n    outputF = netD(fake)   \n    errG = (torch.mean((outputR - torch.mean(outputF) + labels) ** 2) +\n            torch.mean((outputF - torch.mean(outputR) - labels) ** 2))/2\n    errG.backward()\n    optimizerG.step()\n</code></pre>\n\n<h1>Image Display</h1>\n\n<p>I notice that many kernels have dark images. This is because the image pixels have been normalized to <code>[ -1, 1 ]</code>. If you want nice looking images,  then un-normalize them with <code>plt.imshow((img+1.)/2.)</code>.</p>\n\n<h1>Have Fun</h1>\n\n<p>Have fun and enjoy the power of RaLSGAN!</p>",
  "messages": [
    {
      "id": "573007",
      "postDate": "07/11/2019 16:43:25",
      "content": "<h1>Loss Functions</h1>\n\n<p>There are currently no Kaggle kernels that use RaLSGAN. A few kernels have RaLSGAN in their name, but they are using basic DCGAN. <strong>What is RaLSGAN?</strong> RaLSGAN is just basic GAN with a different loss function.</p>\n\n<p><img src=\"http://playagricola.com/Kaggle/DIS.jpg\" alt=\"image\"></p>\n\n<p>A Discriminator can either output <code>sigmoid</code> activation or <code>linear</code> activation. If sigmoid, we have the probability of an image being real, <code>Pr(Real)</code>. If linear, we have the <a href=\"https://en.wikipedia.org/wiki/Logit\">log odds</a> of being real, <code>Logit</code>. Probabilities are between 0 and 1 inclusive. And Logits can be any number. A positive logit implies image is real, a negative logit implies image is fake.</p>\n\n<h1>Simple Loss</h1>\n\n<p>Define <code>x_r</code> to be a real image, and <code>x_f</code> to be a fake image. Define <code>D(x) = Pr(Real)</code> and <code>C(x) = Logit</code> to be the two different outputs from a Discriminator when you input an image. The simplest possible loss is below. </p>\n\n<pre><code># Take AVG over x_r and x_f in batch\ndisc_loss = (1 - D(x_r)) + (D(x_f) - 0)\ngen_loss = (1 - D(x_f))\n</code></pre>\n\n<p>Minimizing these losses says the following. The Discriminator wants <code>D(x_r)=1</code> and <code>D(x_f)=0</code>, i.e. the Discriminator wants real images to have probably 1 of being real. And wants fake images to have probability 0 of being real. The Generator wants <code>D(x_f)=1</code>, i.e. the Generator wants fakes images to have probability 1 of being real.</p>\n\n<h1>DCGAN Loss</h1>\n\n<p>Basic GAN or DCGAN use the following loss functions. Note that they use <code>D(x)</code>, i.e. probs.</p>\n\n<pre><code># Take AVG over x_r and x_f in batch\ndisc_loss = -log (D(x_r)) - log (1-D(x_f))\ngen_loss = -log (D(x_f))\n</code></pre>\n\n<h1>RaLSGAN Loss</h1>\n\n<p>RaLSGAN uses the following loss functions. Note that they use <code>C(x)</code>, i.e. logits.</p>\n\n<pre><code># Take AVG over x_r and x_f in batch\ndisc_loss = (C(x_r) - AVG(C(x_f)) - 1)^2 + (C(x_f) - AVG(C(x_r)) + 1)^2\ngen_loss = (C(x_r) - AVG(C(x_f)) + 1)^2 + (C(x_f) - AVG(C(x_r)) - 1)^2\n</code></pre>\n\n<h1>Code</h1>\n\n<p>Here's how to update the Kaggle kernel starter code. First, if you fork Kaggle's Starter Code, <strong>turn GPU on</strong>! Second, change the last line of the Discriminator to output linear activation (Logit) by removing sigmoid</p>\n\n<pre><code>       #x = torch.sigmoid(self.conv5(x))\n       x = self.conv5(x)\n</code></pre>\n\n<p>Next, change the following</p>\n\n<pre><code>    ############################\n    # (1) Update D network\n    ###########################\n    netD.zero_grad()\n    real_images = real_images.to(device)\n    batch_size = real_images.size(0)\n    labels = torch.full((batch_size, 1), real_label, device=device)\n    outputR = netD(real_images)\n    noise = torch.randn(batch_size, nz, 1, 1, device=device)\n    fake = netG(noise)\n    outputF = netD(fake.detach())\n    errD = (torch.mean((outputR - torch.mean(outputF) - labels) ** 2) + \n            torch.mean((outputF - torch.mean(outputR) + labels) ** 2))/2\n    errD.backward(retain_graph=True)\n    optimizerD.step()\n    ############################\n    # (2) Update G network\n    ###########################\n    netG.zero_grad()\n    outputF = netD(fake)   \n    errG = (torch.mean((outputR - torch.mean(outputF) + labels) ** 2) +\n            torch.mean((outputF - torch.mean(outputR) - labels) ** 2))/2\n    errG.backward()\n    optimizerG.step()\n</code></pre>\n\n<h1>Image Display</h1>\n\n<p>I notice that many kernels have dark images. This is because the image pixels have been normalized to <code>[ -1, 1 ]</code>. If you want nice looking images,  then un-normalize them with <code>plt.imshow((img+1.)/2.)</code>.</p>\n\n<h1>Have Fun</h1>\n\n<p>Have fun and enjoy the power of RaLSGAN!</p>",
      "rawMarkdown": "# Loss Functions\nThere are currently no Kaggle kernels that use RaLSGAN. A few kernels have RaLSGAN in their name, but they are using basic DCGAN. **What is RaLSGAN?** RaLSGAN is just basic GAN with a different loss function.\n\n![image](http://playagricola.com/Kaggle/DIS.jpg)\n\nA Discriminator can either output `sigmoid` activation or `linear` activation. If sigmoid, we have the probability of an image being real, `Pr(Real)`. If linear, we have the [log odds][1] of being real, `Logit`. Probabilities are between 0 and 1 inclusive. And Logits can be any number. A positive logit implies image is real, a negative logit implies image is fake.\n# Simple Loss\nDefine `x_r` to be a real image, and `x_f` to be a fake image. Define `D(x) = Pr(Real)` and `C(x) = Logit` to be the two different outputs from a Discriminator when you input an image. The simplest possible loss is below. \n \n    # Take AVG over x_r and x_f in batch\n    disc_loss = (1 - D(x_r)) + (D(x_f) - 0)\n    gen_loss = (1 - D(x_f))\n\nMinimizing these losses says the following. The Discriminator wants `D(x_r)=1` and `D(x_f)=0`, i.e. the Discriminator wants real images to have probably 1 of being real. And wants fake images to have probability 0 of being real. The Generator wants `D(x_f)=1`, i.e. the Generator wants fakes images to have probability 1 of being real.\n     \n# DCGAN Loss\nBasic GAN or DCGAN use the following loss functions. Note that they use `D(x)`, i.e. probs.\n\n    # Take AVG over x_r and x_f in batch\n    disc_loss = -log (D(x_r)) - log (1-D(x_f))\n    gen_loss = -log (D(x_f))\n\n# RaLSGAN Loss\nRaLSGAN uses the following loss functions. Note that they use `C(x)`, i.e. logits.\n\n    # Take AVG over x_r and x_f in batch\n    disc_loss = (C(x_r) - AVG(C(x_f)) - 1)^2 + (C(x_f) - AVG(C(x_r)) + 1)^2\n    gen_loss = (C(x_r) - AVG(C(x_f)) + 1)^2 + (C(x_f) - AVG(C(x_r)) - 1)^2\n\n# Code\nHere's how to update the Kaggle kernel starter code. First, if you fork Kaggle's Starter Code, **turn GPU on**! Second, change the last line of the Discriminator to output linear activation (Logit) by removing sigmoid\n\n           #x = torch.sigmoid(self.conv5(x))\n           x = self.conv5(x)\n\nNext, change the following\n\n        ############################\n        # (1) Update D network\n        ###########################\n        netD.zero_grad()\n        real_images = real_images.to(device)\n        batch_size = real_images.size(0)\n        labels = torch.full((batch_size, 1), real_label, device=device)\n        outputR = netD(real_images)\n        noise = torch.randn(batch_size, nz, 1, 1, device=device)\n        fake = netG(noise)\n        outputF = netD(fake.detach())\n        errD = (torch.mean((outputR - torch.mean(outputF) - labels) ** 2) + \n                torch.mean((outputF - torch.mean(outputR) + labels) ** 2))/2\n        errD.backward(retain_graph=True)\n        optimizerD.step()\n        ############################\n        # (2) Update G network\n        ###########################\n        netG.zero_grad()\n        outputF = netD(fake)   \n        errG = (torch.mean((outputR - torch.mean(outputF) + labels) ** 2) +\n                torch.mean((outputF - torch.mean(outputR) - labels) ** 2))/2\n        errG.backward()\n        optimizerG.step()\n\n# Image Display\nI notice that many kernels have dark images. This is because the image pixels have been normalized to `[ -1, 1 ]`. If you want nice looking images,  then un-normalize them with `plt.imshow((img+1.)/2.)`.\n\n# Have Fun\nHave fun and enjoy the power of RaLSGAN!\n\n[1]: https://en.wikipedia.org/wiki/Logit",
      "votes": null
    },
    {
      "id": "573010",
      "postDate": "07/11/2019 16:48:03",
      "content": "<p>I knew something was wrong with <a href=\"https://www.kaggle.com/speedwagon/ralsgan-dogs\">this</a> kernel! \nI only started learning GANs a few days ago. This kernel confused me. \nThank you for the clarifications! :)</p>",
      "rawMarkdown": "I knew something was wrong with [this](https://www.kaggle.com/speedwagon/ralsgan-dogs) kernel! \nI only started learning GANs a few days ago. This kernel confused me. \nThank you for the clarifications! :)",
      "votes": null
    },
    {
      "id": "573018",
      "postDate": "07/11/2019 17:03:14",
      "content": "",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "573019",
      "postDate": "07/11/2019 17:04:44",
      "content": "<p>Excellent . About time someone clarified this :)  .Thanks a lot .</p>\n\n<p>I read it from here .</p>\n\n<p><a href=\"https://github.com/AlexiaJM/RelativisticGAN\">https://github.com/AlexiaJM/RelativisticGAN</a> </p>\n\n<p>```</p>\n\n<h3>Standard GAN (non-saturating)</h3>\n\n<h1>Use torch.nn.Sigmoid() as last layer in discriminator</h1>\n\n<p>criterion = torch.nn.BCELoss()</p>\n\n<h1>Real data Discriminator loss</h1>\n\n<p>errD_real = criterion(y_pred, y)\nerrD_real.backward()</p>\n\n<h1>Fake data Discriminator loss</h1>\n\n<p>errD_fake = criterion(y_pred_fake, y2)\nerrD_fake.backward()</p>\n\n<h1>Generator loss</h1>\n\n<p>errG = criterion(y_pred_fake, y)\nerrG.backward()</p>\n\n<h3>Relativistic Standard GAN</h3>\n\n<h1>No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it</h1>\n\n<p>BCE_stable = torch.nn.BCEWithLogitsLoss()</p>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = BCE_stable(y_pred - y_pred_fake, y)\nerrD.backward()</p>\n\n<h1>Generator loss (You may want to resample again from real and fake data)</h1>\n\n<p>errG = BCE_stable(y_pred_fake - y_pred, y)\nerrG.backward()</p>\n\n<h3>Relativistic average Standard GAN</h3>\n\n<h1>No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it</h1>\n\n<p>BCE_stable = torch.nn.BCEWithLogitsLoss()</p>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y) + BCE_stable(y_pred_fake - torch.mean(y_pred), y2))/2\nerrD.backward()</p>\n\n<h1>Generator loss (You may want to resample again from real and fake data)</h1>\n\n<p>errG = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y2) + BCE_stable(y_pred_fake - torch.mean(y_pred), y))/2\nerrG.backward()</p>\n\n<h3>Relativistic average LSGAN</h3>\n\n<h1>No activation in discriminator</h1>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = (torch.mean((y_pred - torch.mean(y_pred_fake) - y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) + y) ** 2))/2\nerrD.backward()</p>\n\n<h1>Generator loss (You may want to resample again from real and fake data)</h1>\n\n<p>errG = (torch.mean((y_pred - torch.mean(y_pred_fake) + y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) - y) ** 2))/2\nerrG.backward()</p>\n\n<h3>Relativistic average HingeGAN</h3>\n\n<h1>No activation in discriminator</h1>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = (torch.mean(torch.nn.ReLU()(1.0 - (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 + (y_pred_fake - torch.mean(y_pred)))))/2\nerrD.backward()</p>\n\n<h1>Generator loss  (You may want to resample again from real and fake data)</h1>\n\n<p>errG = (torch.mean(torch.nn.ReLU()(1.0 + (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 - (y_pred_fake - torch.mean(y_pred)))))/2\nerrG.backward()\n```</p>",
      "rawMarkdown": "Excellent . About time someone clarified this :)  .Thanks a lot .\n\nI read it from here .\n\nhttps://github.com/AlexiaJM/RelativisticGAN \n\n```\n### Standard GAN (non-saturating)\n# Use torch.nn.Sigmoid() as last layer in discriminator\n\ncriterion = torch.nn.BCELoss()\n\n# Real data Discriminator loss\nerrD_real = criterion(y_pred, y)\nerrD_real.backward()\n\n# Fake data Discriminator loss\nerrD_fake = criterion(y_pred_fake, y2)\nerrD_fake.backward()\n\n# Generator loss\nerrG = criterion(y_pred_fake, y)\nerrG.backward()\n\n\n### Relativistic Standard GAN\n\n# No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it\n\nBCE_stable = torch.nn.BCEWithLogitsLoss()\n\n# Discriminator loss\nerrD = BCE_stable(y_pred - y_pred_fake, y)\nerrD.backward()\n\n# Generator loss (You may want to resample again from real and fake data)\nerrG = BCE_stable(y_pred_fake - y_pred, y)\nerrG.backward()\n\n\n### Relativistic average Standard GAN\n\n# No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it\n\nBCE_stable = torch.nn.BCEWithLogitsLoss()\n\n# Discriminator loss\nerrD = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y) + BCE_stable(y_pred_fake - torch.mean(y_pred), y2))/2\nerrD.backward()\n\n# Generator loss (You may want to resample again from real and fake data)\nerrG = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y2) + BCE_stable(y_pred_fake - torch.mean(y_pred), y))/2\nerrG.backward()\n\n\n### Relativistic average LSGAN\n\n# No activation in discriminator\n\n# Discriminator loss\nerrD = (torch.mean((y_pred - torch.mean(y_pred_fake) - y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) + y) ** 2))/2\nerrD.backward()\n\n# Generator loss (You may want to resample again from real and fake data)\nerrG = (torch.mean((y_pred - torch.mean(y_pred_fake) + y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) - y) ** 2))/2\nerrG.backward()\n\n\n### Relativistic average HingeGAN\n\n# No activation in discriminator\n\n# Discriminator loss\nerrD = (torch.mean(torch.nn.ReLU()(1.0 - (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 + (y_pred_fake - torch.mean(y_pred)))))/2\nerrD.backward()\n \n# Generator loss  (You may want to resample again from real and fake data)\nerrG = (torch.mean(torch.nn.ReLU()(1.0 + (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 - (y_pred_fake - torch.mean(y_pred)))))/2\nerrG.backward()\n```",
      "votes": null
    },
    {
      "id": "573020",
      "postDate": "07/11/2019 17:06:34",
      "content": "<p>That's where I originally saw the formula for PyTorch too. For TensorFlow, I wrote it myself.</p>\n\n<pre><code>def TF_errD(fake,real):\n    return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) - tf.ones_like(real))**2,0 )\n        + tf.reduce_mean( (fake - tf.reduce_mean(real,0) + tf.ones_like(real))**2,0 ) )/2.\n\ndef TF_errG(fake,real):\n    return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) + tf.ones_like(real))**2,0 )\n        + tf.reduce_mean( (fake - tf.reduce_mean(real,0) - tf.ones_like(real))**2,0 ) )/2.\n</code></pre>",
      "rawMarkdown": "That's where I originally saw the formula for PyTorch too. For TensorFlow, I wrote it myself.\n\n    def TF_errD(fake,real):\n        return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) - tf.ones_like(real))**2,0 )\n            + tf.reduce_mean( (fake - tf.reduce_mean(real,0) + tf.ones_like(real))**2,0 ) )/2.\n\n    def TF_errG(fake,real):\n        return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) + tf.ones_like(real))**2,0 )\n            + tf.reduce_mean( (fake - tf.reduce_mean(real,0) - tf.ones_like(real))**2,0 ) )/2.",
      "votes": null
    },
    {
      "id": "573039",
      "postDate": "07/11/2019 17:52:30",
      "content": "<p>Thanks, <a href=\"/cdeotte\">@cdeotte</a> 👍 </p>",
      "rawMarkdown": "Thanks, @cdeotte 👍",
      "votes": null
    },
    {
      "id": "573087",
      "postDate": "07/11/2019 19:00:52",
      "content": "<p>Thanks for the explanation</p>",
      "rawMarkdown": "Thanks for the explanation",
      "votes": null
    },
    {
      "id": "573111",
      "postDate": "07/11/2019 19:48:49",
      "content": "<p>Thanks for the clarification <a href=\"/cdeotte\">@cdeotte</a> .\nI finally caught the dog.... 😅 </p>",
      "rawMarkdown": "Thanks for the clarification @cdeotte .\nI finally caught the dog.... 😅",
      "votes": null
    },
    {
      "id": "573129",
      "postDate": "07/11/2019 20:21:30",
      "content": "<p>Awesome. It's super exciting when you see your first dogs being drawn. Congrats.</p>",
      "rawMarkdown": "Awesome. It's super exciting when you see your first dogs being drawn. Congrats.",
      "votes": null
    },
    {
      "id": "573460",
      "postDate": "07/12/2019 09:53:54",
      "content": "<p>Thank you very much <a href=\"/cdeotte\">@cdeotte</a> for the clear explanation and the TF implementation. Have you found that the RaLSGAN loss definitely outperforms the DCGAN one?</p>",
      "rawMarkdown": "Thank you very much @cdeotte for the clear explanation and the TF implementation. Have you found that the RaLSGAN loss definitely outperforms the DCGAN one?",
      "votes": null
    },
    {
      "id": "573486",
      "postDate": "07/12/2019 10:34:46",
      "content": "<p>I've tried relativistic loss on DCGAN. Not sure if there were any significant improvements but it didn't hurt metric either.</p>",
      "rawMarkdown": "I've tried relativistic loss on DCGAN. Not sure if there were any significant improvements but it didn't hurt metric either.",
      "votes": null
    },
    {
      "id": "573497",
      "postDate": "07/12/2019 10:49:02",
      "content": "<p>The code above is both relativistic average loss (Ra) and least squares loss (LS) combined. For me, RaLS has helped my nets converge faster. I get better results in my 150 epochs. Some participants are managing to perform 1000s of epochs so maybe they don't need RaLS.</p>\n\n<p>(Note that there is also relativistic loss (R) that doesn't use averages).</p>",
      "rawMarkdown": "The code above is both relativistic average loss (Ra) and least squares loss (LS) combined. For me, RaLS has helped my nets converge faster. I get better results in my 150 epochs. Some participants are managing to perform 1000s of epochs so maybe they don't need RaLS.\n\n(Note that there is also relativistic loss (R) that doesn't use averages).",
      "votes": null
    },
    {
      "id": "573753",
      "postDate": "07/12/2019 17:46:35",
      "content": "<p>Inspired by this post , I modified the starter code a bit and able to implement the RaLSGAN and RaHingeGAN .  I will clean up the code and share the Kernel shortly . Below are the images generated and loss graph. I didnt run longer like DCGAN , got score 82 . I am optimistic , that it will be better . Visually , what do you think is better , is there any difference at all ?\n*<em>RaLSGAN generated images *</em>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2Fd647d5a83c333d281c3f4cf2dc960427%2FRaLSGAN_Sample.png?generation=1562953386528345&amp;alt=media\" alt=\"\"></p>\n\n<p>*<em>RaHingeGAN generated images *</em>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F0efc70d52e17a797ce9dcafad2e54186%2FRaHingeGAN_Sample.png?generation=1562953518238732&amp;alt=media\" alt=\"\"></p>\n\n<p><strong>RaLSGAN loss :</strong>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F25e0fda4b4ba9c377814725111a45ff3%2FRaLSGAN_loss.png?generation=1562953553951388&amp;alt=media\" alt=\"\">\n<strong>RaHingeGAN loss :</strong>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F3725ccb421815c0f88d827496612ab91%2FRaHingeGAN_loss.png?generation=1562953591095385&amp;alt=media\" alt=\"\"></p>",
      "rawMarkdown": "Inspired by this post , I modified the starter code a bit and able to implement the RaLSGAN and RaHingeGAN .  I will clean up the code and share the Kernel shortly . Below are the images generated and loss graph. I didnt run longer like DCGAN , got score 82 . I am optimistic , that it will be better . Visually , what do you think is better , is there any difference at all ?\n**RaLSGAN generated images **\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2Fd647d5a83c333d281c3f4cf2dc960427%2FRaLSGAN_Sample.png?generation=1562953386528345&amp;alt=media)\n\n**RaHingeGAN generated images **\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F0efc70d52e17a797ce9dcafad2e54186%2FRaHingeGAN_Sample.png?generation=1562953518238732&amp;alt=media)\n\n**RaLSGAN loss :**\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F25e0fda4b4ba9c377814725111a45ff3%2FRaLSGAN_loss.png?generation=1562953553951388&amp;alt=media)\n**RaHingeGAN loss :**\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F3725ccb421815c0f88d827496612ab91%2FRaHingeGAN_loss.png?generation=1562953591095385&amp;alt=media)",
      "votes": null
    },
    {
      "id": "574501",
      "postDate": "07/14/2019 01:40:44",
      "content": "<p><a href=\"/cdeotte\">@cdeotte</a> You are so super helpful. Thanks.</p>",
      "rawMarkdown": "cdeotte You are so super helpful. Thanks.",
      "votes": null
    },
    {
      "id": "579998",
      "postDate": "07/19/2019 14:21:01",
      "content": "<p>Hello Chris,\nWanted to know how should be the ideal loss curves look for RaLSGAN G and D.\nThey dont behave as normal GAN's for sure, due to how the loss eqn's are formulated</p>",
      "rawMarkdown": "Hello Chris,\nWanted to know how should be the ideal loss curves look for RaLSGAN G and D.\nThey dont behave as normal GAN's for sure, due to how the loss eqn's are formulated",
      "votes": null
    },
    {
      "id": "580430",
      "postDate": "07/20/2019 06:18:06",
      "content": "<p>Thanks <a href=\"/cdeotte\">@cdeotte</a> </p>",
      "rawMarkdown": "Thanks @cdeotte",
      "votes": null
    },
    {
      "id": "582165",
      "postDate": "07/22/2019 20:36:34",
      "content": "<p>Can anyone please explain how to implement this loss function in Keras?</p>",
      "rawMarkdown": "Can anyone please explain how to implement this loss function in Keras?",
      "votes": null
    },
    {
      "id": "582167",
      "postDate": "07/22/2019 20:44:32",
      "content": "<p>Code is posted in comments below. <a href=\"https://www.kaggle.com/c/generative-dog-images/discussion/99485#573020\">Here</a> is a direct link.</p>\n\n<p>The function header is <code>TF_errD(fake,real)</code>. The variables <code>fake</code> and <code>real</code> are the outputs from your Discriminator network where the last neuron activation is <code>linear</code>, i.e. this loss function takes <code>Logits</code>. Variable <code>fake</code> is array of length BATCH-SIZE when generated images are inputted into Discriminator and <code>real</code> is length BATCH-SIZE of real images inputted.</p>",
      "rawMarkdown": "Code is posted in comments below. [Here][1] is a direct link.\n\nThe function header is `TF_errD(fake,real)`. The variables `fake` and `real` are the outputs from your Discriminator network where the last neuron activation is `linear`, i.e. this loss function takes `Logits`. Variable `fake` is array of length BATCH-SIZE when generated images are inputted into Discriminator and `real` is length BATCH-SIZE of real images inputted.\n\n[1]: https://www.kaggle.com/c/generative-dog-images/discussion/99485#573020",
      "votes": null
    },
    {
      "id": "582535",
      "postDate": "07/23/2019 09:40:30",
      "content": "<p>Thank you <a href=\"/cdeotte\">@cdeotte</a> </p>",
      "rawMarkdown": "Thank you @cdeotte",
      "votes": null
    },
    {
      "id": "589268",
      "postDate": "07/31/2019 17:22:51",
      "content": "<p>Excellent work. Thanks for sharing !!!</p>",
      "rawMarkdown": "Excellent work. Thanks for sharing !!!",
      "votes": null
    },
    {
      "id": "597003",
      "postDate": "08/11/2019 16:34:42",
      "content": "<p><a href=\"/cdeotte\">@cdeotte</a> \nThanks for your sharing, may I know how to implant the loss into keras?\nsorry I am new in keras, here is my naive idea:\n```</p>\n\n<h1>discriminator compile as</h1>\n\n<p>Discriminator = Sequential()\nDiscriminator.add(Conv2D(32,4,padding='same',strides= 2, input_shape=(64,64,3)))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(64,4,strides= 2, padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(128,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(256,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Dropout(0.3))\nDiscriminator.add(Conv2D(1,4,strides= 1,padding='valid'))\nDiscriminator.compile(loss=TF_errD, optimizer=optimizer_dis, metrics=['accuracy'])\n...</p>\n\n<h1>and then train like this</h1>\n\n<p>true_label = Discriminator.predict(images) # images is from a batch of real image\nnoise = np.random.normal(0,1,(batch,input_dims))\nsynthesis_img = Generator.predict(noise)\nd_loss = Discriminator.train_on_batch(synthesis_img,true_label)``\n```</p>\n\n<p>however, this does not work...\nthe loss is very large and generate meaningless image.</p>",
      "rawMarkdown": "cdeotte \nThanks for your sharing, may I know how to implant the loss into keras?\nsorry I am new in keras, here is my naive idea:\n```\n#discriminator compile as \nDiscriminator = Sequential()\nDiscriminator.add(Conv2D(32,4,padding='same',strides= 2, input_shape=(64,64,3)))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(64,4,strides= 2, padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(128,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(256,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Dropout(0.3))\nDiscriminator.add(Conv2D(1,4,strides= 1,padding='valid'))\nDiscriminator.compile(loss=TF_errD, optimizer=optimizer_dis, metrics=['accuracy'])\n...\n#and then train like this\ntrue_label = Discriminator.predict(images) # images is from a batch of real image\nnoise = np.random.normal(0,1,(batch,input_dims))\nsynthesis_img = Generator.predict(noise)\nd_loss = Discriminator.train_on_batch(synthesis_img,true_label)``\n```\n\nhowever, this does not work...\nthe loss is very large and generate meaningless image.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 573010,
      "author_name": "timetraveller98",
      "author_url": "",
      "post_date": "07/11/2019 16:48:03",
      "content": "<p>I knew something was wrong with <a href=\"https://www.kaggle.com/speedwagon/ralsgan-dogs\">this</a> kernel! \nI only started learning GANs a few days ago. This kernel confused me. \nThank you for the clarifications! :)</p>",
      "votes": null,
      "replies": [
        {
          "id": 573018,
          "author_name": "phoenix9032",
          "author_url": "",
          "post_date": "07/11/2019 17:03:14",
          "content": "",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 573019,
      "author_name": "phoenix9032",
      "author_url": "",
      "post_date": "07/11/2019 17:04:44",
      "content": "<p>Excellent . About time someone clarified this :)  .Thanks a lot .</p>\n\n<p>I read it from here .</p>\n\n<p><a href=\"https://github.com/AlexiaJM/RelativisticGAN\">https://github.com/AlexiaJM/RelativisticGAN</a> </p>\n\n<p>```</p>\n\n<h3>Standard GAN (non-saturating)</h3>\n\n<h1>Use torch.nn.Sigmoid() as last layer in discriminator</h1>\n\n<p>criterion = torch.nn.BCELoss()</p>\n\n<h1>Real data Discriminator loss</h1>\n\n<p>errD_real = criterion(y_pred, y)\nerrD_real.backward()</p>\n\n<h1>Fake data Discriminator loss</h1>\n\n<p>errD_fake = criterion(y_pred_fake, y2)\nerrD_fake.backward()</p>\n\n<h1>Generator loss</h1>\n\n<p>errG = criterion(y_pred_fake, y)\nerrG.backward()</p>\n\n<h3>Relativistic Standard GAN</h3>\n\n<h1>No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it</h1>\n\n<p>BCE_stable = torch.nn.BCEWithLogitsLoss()</p>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = BCE_stable(y_pred - y_pred_fake, y)\nerrD.backward()</p>\n\n<h1>Generator loss (You may want to resample again from real and fake data)</h1>\n\n<p>errG = BCE_stable(y_pred_fake - y_pred, y)\nerrG.backward()</p>\n\n<h3>Relativistic average Standard GAN</h3>\n\n<h1>No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it</h1>\n\n<p>BCE_stable = torch.nn.BCEWithLogitsLoss()</p>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y) + BCE_stable(y_pred_fake - torch.mean(y_pred), y2))/2\nerrD.backward()</p>\n\n<h1>Generator loss (You may want to resample again from real and fake data)</h1>\n\n<p>errG = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y2) + BCE_stable(y_pred_fake - torch.mean(y_pred), y))/2\nerrG.backward()</p>\n\n<h3>Relativistic average LSGAN</h3>\n\n<h1>No activation in discriminator</h1>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = (torch.mean((y_pred - torch.mean(y_pred_fake) - y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) + y) ** 2))/2\nerrD.backward()</p>\n\n<h1>Generator loss (You may want to resample again from real and fake data)</h1>\n\n<p>errG = (torch.mean((y_pred - torch.mean(y_pred_fake) + y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) - y) ** 2))/2\nerrG.backward()</p>\n\n<h3>Relativistic average HingeGAN</h3>\n\n<h1>No activation in discriminator</h1>\n\n<h1>Discriminator loss</h1>\n\n<p>errD = (torch.mean(torch.nn.ReLU()(1.0 - (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 + (y_pred_fake - torch.mean(y_pred)))))/2\nerrD.backward()</p>\n\n<h1>Generator loss  (You may want to resample again from real and fake data)</h1>\n\n<p>errG = (torch.mean(torch.nn.ReLU()(1.0 + (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 - (y_pred_fake - torch.mean(y_pred)))))/2\nerrG.backward()\n```</p>",
      "votes": null,
      "replies": [
        {
          "id": 573020,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "07/11/2019 17:06:34",
          "content": "<p>That's where I originally saw the formula for PyTorch too. For TensorFlow, I wrote it myself.</p>\n\n<pre><code>def TF_errD(fake,real):\n    return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) - tf.ones_like(real))**2,0 )\n        + tf.reduce_mean( (fake - tf.reduce_mean(real,0) + tf.ones_like(real))**2,0 ) )/2.\n\ndef TF_errG(fake,real):\n    return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) + tf.ones_like(real))**2,0 )\n        + tf.reduce_mean( (fake - tf.reduce_mean(real,0) - tf.ones_like(real))**2,0 ) )/2.\n</code></pre>",
          "votes": null,
          "replies": []
        },
        {
          "id": 574501,
          "author_name": "ag12345",
          "author_url": "",
          "post_date": "07/14/2019 01:40:44",
          "content": "<p><a href=\"/cdeotte\">@cdeotte</a> You are so super helpful. Thanks.</p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 597003,
          "author_name": "leolewis",
          "author_url": "",
          "post_date": "08/11/2019 16:34:42",
          "content": "<p><a href=\"/cdeotte\">@cdeotte</a> \nThanks for your sharing, may I know how to implant the loss into keras?\nsorry I am new in keras, here is my naive idea:\n```</p>\n\n<h1>discriminator compile as</h1>\n\n<p>Discriminator = Sequential()\nDiscriminator.add(Conv2D(32,4,padding='same',strides= 2, input_shape=(64,64,3)))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(64,4,strides= 2, padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(128,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(256,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Dropout(0.3))\nDiscriminator.add(Conv2D(1,4,strides= 1,padding='valid'))\nDiscriminator.compile(loss=TF_errD, optimizer=optimizer_dis, metrics=['accuracy'])\n...</p>\n\n<h1>and then train like this</h1>\n\n<p>true_label = Discriminator.predict(images) # images is from a batch of real image\nnoise = np.random.normal(0,1,(batch,input_dims))\nsynthesis_img = Generator.predict(noise)\nd_loss = Discriminator.train_on_batch(synthesis_img,true_label)``\n```</p>\n\n<p>however, this does not work...\nthe loss is very large and generate meaningless image.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 573039,
      "author_name": "coolcoder22",
      "author_url": "",
      "post_date": "07/11/2019 17:52:30",
      "content": "<p>Thanks, <a href=\"/cdeotte\">@cdeotte</a> 👍 </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 573087,
      "author_name": "khursani8",
      "author_url": "",
      "post_date": "07/11/2019 19:00:52",
      "content": "<p>Thanks for the explanation</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 573111,
      "author_name": "jolasa",
      "author_url": "",
      "post_date": "07/11/2019 19:48:49",
      "content": "<p>Thanks for the clarification <a href=\"/cdeotte\">@cdeotte</a> .\nI finally caught the dog.... 😅 </p>",
      "votes": null,
      "replies": [
        {
          "id": 573129,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "07/11/2019 20:21:30",
          "content": "<p>Awesome. It's super exciting when you see your first dogs being drawn. Congrats.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 573460,
      "author_name": "lucamassaron",
      "author_url": "",
      "post_date": "07/12/2019 09:53:54",
      "content": "<p>Thank you very much <a href=\"/cdeotte\">@cdeotte</a> for the clear explanation and the TF implementation. Have you found that the RaLSGAN loss definitely outperforms the DCGAN one?</p>",
      "votes": null,
      "replies": [
        {
          "id": 573486,
          "author_name": "dvorobiev",
          "author_url": "",
          "post_date": "07/12/2019 10:34:46",
          "content": "<p>I've tried relativistic loss on DCGAN. Not sure if there were any significant improvements but it didn't hurt metric either.</p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 573497,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "07/12/2019 10:49:02",
          "content": "<p>The code above is both relativistic average loss (Ra) and least squares loss (LS) combined. For me, RaLS has helped my nets converge faster. I get better results in my 150 epochs. Some participants are managing to perform 1000s of epochs so maybe they don't need RaLS.</p>\n\n<p>(Note that there is also relativistic loss (R) that doesn't use averages).</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 573753,
      "author_name": "phoenix9032",
      "author_url": "",
      "post_date": "07/12/2019 17:46:35",
      "content": "<p>Inspired by this post , I modified the starter code a bit and able to implement the RaLSGAN and RaHingeGAN .  I will clean up the code and share the Kernel shortly . Below are the images generated and loss graph. I didnt run longer like DCGAN , got score 82 . I am optimistic , that it will be better . Visually , what do you think is better , is there any difference at all ?\n*<em>RaLSGAN generated images *</em>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2Fd647d5a83c333d281c3f4cf2dc960427%2FRaLSGAN_Sample.png?generation=1562953386528345&amp;alt=media\" alt=\"\"></p>\n\n<p>*<em>RaHingeGAN generated images *</em>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F0efc70d52e17a797ce9dcafad2e54186%2FRaHingeGAN_Sample.png?generation=1562953518238732&amp;alt=media\" alt=\"\"></p>\n\n<p><strong>RaLSGAN loss :</strong>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F25e0fda4b4ba9c377814725111a45ff3%2FRaLSGAN_loss.png?generation=1562953553951388&amp;alt=media\" alt=\"\">\n<strong>RaHingeGAN loss :</strong>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F3725ccb421815c0f88d827496612ab91%2FRaHingeGAN_loss.png?generation=1562953591095385&amp;alt=media\" alt=\"\"></p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 579998,
      "author_name": "dhruuv111",
      "author_url": "",
      "post_date": "07/19/2019 14:21:01",
      "content": "<p>Hello Chris,\nWanted to know how should be the ideal loss curves look for RaLSGAN G and D.\nThey dont behave as normal GAN's for sure, due to how the loss eqn's are formulated</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 580430,
      "author_name": "akhileshrai",
      "author_url": "",
      "post_date": "07/20/2019 06:18:06",
      "content": "<p>Thanks <a href=\"/cdeotte\">@cdeotte</a> </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 582165,
      "author_name": "techytushar",
      "author_url": "",
      "post_date": "07/22/2019 20:36:34",
      "content": "<p>Can anyone please explain how to implement this loss function in Keras?</p>",
      "votes": null,
      "replies": [
        {
          "id": 582167,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "07/22/2019 20:44:32",
          "content": "<p>Code is posted in comments below. <a href=\"https://www.kaggle.com/c/generative-dog-images/discussion/99485#573020\">Here</a> is a direct link.</p>\n\n<p>The function header is <code>TF_errD(fake,real)</code>. The variables <code>fake</code> and <code>real</code> are the outputs from your Discriminator network where the last neuron activation is <code>linear</code>, i.e. this loss function takes <code>Logits</code>. Variable <code>fake</code> is array of length BATCH-SIZE when generated images are inputted into Discriminator and <code>real</code> is length BATCH-SIZE of real images inputted.</p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 582535,
          "author_name": "techytushar",
          "author_url": "",
          "post_date": "07/23/2019 09:40:30",
          "content": "<p>Thank you <a href=\"/cdeotte\">@cdeotte</a> </p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 589268,
      "author_name": "suneelpatel",
      "author_url": "",
      "post_date": "07/31/2019 17:22:51",
      "content": "<p>Excellent work. Thanks for sharing !!!</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "573007": "# Loss Functions\nThere are currently no Kaggle kernels that use RaLSGAN. A few kernels have RaLSGAN in their name, but they are using basic DCGAN. **What is RaLSGAN?** RaLSGAN is just basic GAN with a different loss function.\n\n![image](http://playagricola.com/Kaggle/DIS.jpg)\n\nA Discriminator can either output `sigmoid` activation or `linear` activation. If sigmoid, we have the probability of an image being real, `Pr(Real)`. If linear, we have the [log odds][1] of being real, `Logit`. Probabilities are between 0 and 1 inclusive. And Logits can be any number. A positive logit implies image is real, a negative logit implies image is fake.\n# Simple Loss\nDefine `x_r` to be a real image, and `x_f` to be a fake image. Define `D(x) = Pr(Real)` and `C(x) = Logit` to be the two different outputs from a Discriminator when you input an image. The simplest possible loss is below. \n \n    # Take AVG over x_r and x_f in batch\n    disc_loss = (1 - D(x_r)) + (D(x_f) - 0)\n    gen_loss = (1 - D(x_f))\n\nMinimizing these losses says the following. The Discriminator wants `D(x_r)=1` and `D(x_f)=0`, i.e. the Discriminator wants real images to have probably 1 of being real. And wants fake images to have probability 0 of being real. The Generator wants `D(x_f)=1`, i.e. the Generator wants fakes images to have probability 1 of being real.\n     \n# DCGAN Loss\nBasic GAN or DCGAN use the following loss functions. Note that they use `D(x)`, i.e. probs.\n\n    # Take AVG over x_r and x_f in batch\n    disc_loss = -log (D(x_r)) - log (1-D(x_f))\n    gen_loss = -log (D(x_f))\n\n# RaLSGAN Loss\nRaLSGAN uses the following loss functions. Note that they use `C(x)`, i.e. logits.\n\n    # Take AVG over x_r and x_f in batch\n    disc_loss = (C(x_r) - AVG(C(x_f)) - 1)^2 + (C(x_f) - AVG(C(x_r)) + 1)^2\n    gen_loss = (C(x_r) - AVG(C(x_f)) + 1)^2 + (C(x_f) - AVG(C(x_r)) - 1)^2\n\n# Code\nHere's how to update the Kaggle kernel starter code. First, if you fork Kaggle's Starter Code, **turn GPU on**! Second, change the last line of the Discriminator to output linear activation (Logit) by removing sigmoid\n\n           #x = torch.sigmoid(self.conv5(x))\n           x = self.conv5(x)\n\nNext, change the following\n\n        ############################\n        # (1) Update D network\n        ###########################\n        netD.zero_grad()\n        real_images = real_images.to(device)\n        batch_size = real_images.size(0)\n        labels = torch.full((batch_size, 1), real_label, device=device)\n        outputR = netD(real_images)\n        noise = torch.randn(batch_size, nz, 1, 1, device=device)\n        fake = netG(noise)\n        outputF = netD(fake.detach())\n        errD = (torch.mean((outputR - torch.mean(outputF) - labels) ** 2) + \n                torch.mean((outputF - torch.mean(outputR) + labels) ** 2))/2\n        errD.backward(retain_graph=True)\n        optimizerD.step()\n        ############################\n        # (2) Update G network\n        ###########################\n        netG.zero_grad()\n        outputF = netD(fake)   \n        errG = (torch.mean((outputR - torch.mean(outputF) + labels) ** 2) +\n                torch.mean((outputF - torch.mean(outputR) - labels) ** 2))/2\n        errG.backward()\n        optimizerG.step()\n\n# Image Display\nI notice that many kernels have dark images. This is because the image pixels have been normalized to `[ -1, 1 ]`. If you want nice looking images,  then un-normalize them with `plt.imshow((img+1.)/2.)`.\n\n# Have Fun\nHave fun and enjoy the power of RaLSGAN!\n\n[1]: https://en.wikipedia.org/wiki/Logit",
    "573010": "I knew something was wrong with [this](https://www.kaggle.com/speedwagon/ralsgan-dogs) kernel! \nI only started learning GANs a few days ago. This kernel confused me. \nThank you for the clarifications! :)",
    "573018": "",
    "573019": "Excellent . About time someone clarified this :)  .Thanks a lot .\n\nI read it from here .\n\nhttps://github.com/AlexiaJM/RelativisticGAN \n\n```\n### Standard GAN (non-saturating)\n# Use torch.nn.Sigmoid() as last layer in discriminator\n\ncriterion = torch.nn.BCELoss()\n\n# Real data Discriminator loss\nerrD_real = criterion(y_pred, y)\nerrD_real.backward()\n\n# Fake data Discriminator loss\nerrD_fake = criterion(y_pred_fake, y2)\nerrD_fake.backward()\n\n# Generator loss\nerrG = criterion(y_pred_fake, y)\nerrG.backward()\n\n\n### Relativistic Standard GAN\n\n# No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it\n\nBCE_stable = torch.nn.BCEWithLogitsLoss()\n\n# Discriminator loss\nerrD = BCE_stable(y_pred - y_pred_fake, y)\nerrD.backward()\n\n# Generator loss (You may want to resample again from real and fake data)\nerrG = BCE_stable(y_pred_fake - y_pred, y)\nerrG.backward()\n\n\n### Relativistic average Standard GAN\n\n# No sigmoid activation in last layer of discriminator because BCEWithLogitsLoss() already adds it\n\nBCE_stable = torch.nn.BCEWithLogitsLoss()\n\n# Discriminator loss\nerrD = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y) + BCE_stable(y_pred_fake - torch.mean(y_pred), y2))/2\nerrD.backward()\n\n# Generator loss (You may want to resample again from real and fake data)\nerrG = ((BCE_stable(y_pred - torch.mean(y_pred_fake), y2) + BCE_stable(y_pred_fake - torch.mean(y_pred), y))/2\nerrG.backward()\n\n\n### Relativistic average LSGAN\n\n# No activation in discriminator\n\n# Discriminator loss\nerrD = (torch.mean((y_pred - torch.mean(y_pred_fake) - y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) + y) ** 2))/2\nerrD.backward()\n\n# Generator loss (You may want to resample again from real and fake data)\nerrG = (torch.mean((y_pred - torch.mean(y_pred_fake) + y) ** 2) + torch.mean((y_pred_fake - torch.mean(y_pred) - y) ** 2))/2\nerrG.backward()\n\n\n### Relativistic average HingeGAN\n\n# No activation in discriminator\n\n# Discriminator loss\nerrD = (torch.mean(torch.nn.ReLU()(1.0 - (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 + (y_pred_fake - torch.mean(y_pred)))))/2\nerrD.backward()\n \n# Generator loss  (You may want to resample again from real and fake data)\nerrG = (torch.mean(torch.nn.ReLU()(1.0 + (y_pred - torch.mean(y_pred_fake)))) + torch.mean(torch.nn.ReLU()(1.0 - (y_pred_fake - torch.mean(y_pred)))))/2\nerrG.backward()\n```",
    "573020": "That's where I originally saw the formula for PyTorch too. For TensorFlow, I wrote it myself.\n\n    def TF_errD(fake,real):\n        return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) - tf.ones_like(real))**2,0 )\n            + tf.reduce_mean( (fake - tf.reduce_mean(real,0) + tf.ones_like(real))**2,0 ) )/2.\n\n    def TF_errG(fake,real):\n        return (tf.reduce_mean( (real - tf.reduce_mean(fake,0) + tf.ones_like(real))**2,0 )\n            + tf.reduce_mean( (fake - tf.reduce_mean(real,0) - tf.ones_like(real))**2,0 ) )/2.",
    "573039": "Thanks, @cdeotte 👍",
    "573087": "Thanks for the explanation",
    "573111": "Thanks for the clarification @cdeotte .\nI finally caught the dog.... 😅",
    "573129": "Awesome. It's super exciting when you see your first dogs being drawn. Congrats.",
    "573460": "Thank you very much @cdeotte for the clear explanation and the TF implementation. Have you found that the RaLSGAN loss definitely outperforms the DCGAN one?",
    "573486": "I've tried relativistic loss on DCGAN. Not sure if there were any significant improvements but it didn't hurt metric either.",
    "573497": "The code above is both relativistic average loss (Ra) and least squares loss (LS) combined. For me, RaLS has helped my nets converge faster. I get better results in my 150 epochs. Some participants are managing to perform 1000s of epochs so maybe they don't need RaLS.\n\n(Note that there is also relativistic loss (R) that doesn't use averages).",
    "573753": "Inspired by this post , I modified the starter code a bit and able to implement the RaLSGAN and RaHingeGAN .  I will clean up the code and share the Kernel shortly . Below are the images generated and loss graph. I didnt run longer like DCGAN , got score 82 . I am optimistic , that it will be better . Visually , what do you think is better , is there any difference at all ?\n**RaLSGAN generated images **\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2Fd647d5a83c333d281c3f4cf2dc960427%2FRaLSGAN_Sample.png?generation=1562953386528345&amp;alt=media)\n\n**RaHingeGAN generated images **\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F0efc70d52e17a797ce9dcafad2e54186%2FRaHingeGAN_Sample.png?generation=1562953518238732&amp;alt=media)\n\n**RaLSGAN loss :**\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F25e0fda4b4ba9c377814725111a45ff3%2FRaLSGAN_loss.png?generation=1562953553951388&amp;alt=media)\n**RaHingeGAN loss :**\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F2234817%2F3725ccb421815c0f88d827496612ab91%2FRaHingeGAN_loss.png?generation=1562953591095385&amp;alt=media)",
    "574501": "cdeotte You are so super helpful. Thanks.",
    "579998": "Hello Chris,\nWanted to know how should be the ideal loss curves look for RaLSGAN G and D.\nThey dont behave as normal GAN's for sure, due to how the loss eqn's are formulated",
    "580430": "Thanks @cdeotte",
    "582165": "Can anyone please explain how to implement this loss function in Keras?",
    "582167": "Code is posted in comments below. [Here][1] is a direct link.\n\nThe function header is `TF_errD(fake,real)`. The variables `fake` and `real` are the outputs from your Discriminator network where the last neuron activation is `linear`, i.e. this loss function takes `Logits`. Variable `fake` is array of length BATCH-SIZE when generated images are inputted into Discriminator and `real` is length BATCH-SIZE of real images inputted.\n\n[1]: https://www.kaggle.com/c/generative-dog-images/discussion/99485#573020",
    "582535": "Thank you @cdeotte",
    "589268": "Excellent work. Thanks for sharing !!!",
    "597003": "cdeotte \nThanks for your sharing, may I know how to implant the loss into keras?\nsorry I am new in keras, here is my naive idea:\n```\n#discriminator compile as \nDiscriminator = Sequential()\nDiscriminator.add(Conv2D(32,4,padding='same',strides= 2, input_shape=(64,64,3)))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(64,4,strides= 2, padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(128,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Conv2D(256,4,strides= 2,padding='same'))\nDiscriminator.add(LeakyReLU(alpha=0.2))\nDiscriminator.add(Dropout(0.3))\nDiscriminator.add(Conv2D(1,4,strides= 1,padding='valid'))\nDiscriminator.compile(loss=TF_errD, optimizer=optimizer_dis, metrics=['accuracy'])\n...\n#and then train like this\ntrue_label = Discriminator.predict(images) # images is from a batch of real image\nnoise = np.random.normal(0,1,(batch,input_dims))\nsynthesis_img = Generator.predict(noise)\nd_loss = Discriminator.train_on_batch(synthesis_img,true_label)``\n```\n\nhowever, this does not work...\nthe loss is very large and generate meaningless image."
  },
  "source": "meta"
}