Perturbing the output of a loss function

elliotto: <p>Hi all,</p>
<p>As part of my team’s research, we are investigating applying a perturbation to the loss function of a neural network, to backpropagate using a noisy loss rather than the true loss. We are experimenting with normal noise with mean 0, and changing the standard deviation. We have implemented the following code:</p>
<p>loss_noisy = loss + np.random.normal(0, scale) * loss / loss.detach()</p>
<p>loss_noisy.backward()</p>
<p>This adds the normalised loss vector to itself, with a random scaling, to emulate the equation</p>
<p>L = L + N(0, Scale)</p>
<p>We have produced results which show degraded performance of the network with increased scaling. However, we are unsure exactly how this is working under the hood. In particular, if a Loss value is composed of multiple samples, it is unclear how the perturbation is ‘distributed’ amongst the individual sample backpropagation steps.</p>
<p>I was hoping that someone might have some experience with this, and would understand how the perturbation is distributed during backpropagation.</p>
<p>Regards,</p>
<p>Elliott</p>

KFrank: <p>Hi Elliott!</p>
<aside class="quote no-group quote-modified" data-username="elliotto" data-post="1" data-topic="153728" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/elliotto/48/50077_2.png" class="avatar"> elliotto:</div>
<blockquote>
<p>loss_noisy = loss + np.random.normal(0, scale) * loss / loss.detach()</p>
<p>loss_noisy.backward()</p>
<p>This adds the normalised loss vector to itself, with a random scaling, to emulate the equation</p>
<p>L = L + N(0, Scale)<br>
…<br>
it is unclear how the perturbation is ‘distributed’ amongst the individual sample backpropagation steps.</p>
</blockquote>
</aside>
<p>Let’s first cut to the chase and understand how your perturbation<br>
affects the gradients computed by <code>.backward()</code>.</p>
<p>You have:</p>
<pre data-code-wrap="python"><code class="lang-python">loss_noisy = (1 + fac) * loss
</code></pre>
<p>where <code>fac</code> is a random deviate divided by <code>loss.detach()</code>.</p>
<p><code>loss.detach()</code> is numerically equal to <code>loss</code>, but is not, itself,<br>
differentiated in the backpropagation process.</p>
<p>The whole gradient-computation process is linear in the final <code>loss</code><br>
scalar, so if <code>unperturbed_grad</code> is the result you would have obtained<br>
by backpropagating <code>loss</code>, backpropagating <code>loss_noisy</code> will give you:</p>
<pre data-code-wrap="python"><code class="lang-python">some_parameter.grad = (1 + fac) * unperturbed_grad
</code></pre>
<p>As for how the perturbation is distributed among individual samples,<br>
your <code>loss</code> will typically be a sum (or average) over samples:</p>
<pre data-code-wrap="python"><code class="lang-python">loss = loss_batch = loss_samples.sum()
</code></pre>
<p>(where <code>loss_samples</code> is a vector of length <code>nBatch</code> of per-sample<br>
losses).</p>
<p>If you were to compute:</p>
<pre><code class="lang-auto">loss_samples_noisy = (1 + fac) * loss_samples
</code></pre>
<p>(where <code>fac</code> does include the <code>loss.detach()</code> that has been summed<br>
over the samples), then</p>
<pre><code class="lang-auto">loss_noisy = loss_samples_noisy.sum()
</code></pre>
<p>So your perturbation gets distributed over the per-sample losses simply<br>
by multiplying them individually by the same linear factor you used to<br>
produce <code>loss_noisy</code>.</p>
<p>As an aside, I would probably perturb (add noise to) the predictions<br>
of your model or to your target values, rather than perturbing <code>loss</code><br>
directly.</p>
<p>Best.</p>
<p>K. Frank</p>

elliotto: <p>Hi KFrank!</p>
<p>Thanks for the detailed response, this has given us a lot to chew on. The observation that</p>
<pre><code class="lang-auto">some_parameter.grad = (1 + fac) * unperturbed_grad
</code></pre>
<p>was incredibly helpful for us to investigate our problem.</p>
<p>Regards,<br>
Elliott</p>