Cost function using Torch.argmin()

ilya_L: <p>Hi everyone,</p>
<p>I’m trying to use a custom loss function which is something like:<br>
torch.dist(torch.argmin(predictedData).double(), actualData, p=2)<br>
loss.backward()<br>
This function outputs a tensor with requires_grad = False and therefore when I try to backprop I get:<br>
RuntimeError(‘element 0 of tensors does not require grad and does not have a grad_fn’<br>
*I think it’s because torch.argmin() output has requires_grad = False as well</p>
<p>Does anyone knows how can I fix this issue?</p>

jmandivarapu1: <p>Create an variable in pytorch with require_grad is True then add this loss to that variable. Then use the created variable to take the backprop</p>

KFrank: <p>Hi Ilya!</p>
<aside class="quote no-group" data-username="ilya_L" data-post="1" data-topic="76846" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/i/d78d45/48.png" class="avatar"> ilya_L:</div>
<blockquote>
<p>I’m trying to use a custom loss function which is something like:<br>
torch.dist(torch.argmin(predictedData).double(), actualData, p=2)</p>
</blockquote>
</aside>
<p>First off, I suspect that you don’t* really want to do what you think<br>
you want to do.</p>
<p>However, making some guesses about what (you think) you want,<br>
you could try something like this.</p>
<p>The key issue is that <code>argmin</code> maps onto discrete integers, and so,<br>
is not usefully differentiable.  So you can’t backpropagate through it.</p>
<p>(Note that Jaya’s suggestion of adding your non-differentiable loss<br>
to a <code>requires_grad = True</code> variable won’t work.  It will get rid of<br>
your specific error message, but it’s a fake out.  Gradients won’t<br>
backpropagate through your loss nor through <code>predictedData</code> nor<br>
through the model you used to predict <code>predicted</code> data, so you can’t<br>
use it to train your model parameters.)</p>
<p>Let me assume that <code>predictedData</code> is a vector of numbers between<br>
0 and 1.  (For simplicity, I will illustrate this without the (necessary)<br>
batch dimension.)  I will also assume that <code>actualData</code> is a single,<br>
integer “index”.  I think you want the index of your smallest probability<br>
(<code>argmin</code>) to match <code>actualData</code>, and, if it doesn’t, you want your loss<br>
to measure how far away it is in “index space.”</p>
<p>To do this in a differentiable, backpropagateable , you have to get<br>
rid of the <code>argmin</code>.</p>
<p>One approach would be to pre-compute the “index-space” distances,<br>
and not discretize your <code>predictedData</code>:</p>
<pre data-code-wrap="python"><code class="lang-python">import torch
torch.__version__

torch.manual_seed (2020)

nClass = 5
tt = torch.FloatTensor (range (nClass)).repeat (nClass).view (nClass, nClass)
dst = (tt - tt.transpose (0, 1)).abs()
dst

actualData = 2
actualData

predictedDataA = torch.ones (nClass)
predictedDataA[2] = 0.0
predictedDataB = torch.ones (nClass)
predictedDataB[4] = 0.0
predictedDataC = torch.rand (nClass)
predictedDataA
predictedDataB
predictedDataC

lossA = ((1.0 - predictedDataA) * dst[actualData]).sum(dim = 0)
lossB = ((1.0 - predictedDataB) * dst[actualData]).sum(dim = 0)
lossC = ((1.0 - predictedDataC) * dst[actualData]).sum(dim = 0)
lossA
lossB
lossC
</code></pre>
<p>Here is the output:</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; import torch
&gt;&gt;&gt; torch.__version__
'0.3.0b0+591e73e'
&gt;&gt;&gt;
&gt;&gt;&gt; torch.manual_seed (2020)
&lt;torch._C.Generator object at 0x000002CE49626630&gt;
&gt;&gt;&gt;
&gt;&gt;&gt; nClass = 5
&gt;&gt;&gt; tt = torch.FloatTensor (range (nClass)).repeat (nClass).view (nClass, nClass)
&gt;&gt;&gt; dst = (tt - tt.transpose (0, 1)).abs()
&gt;&gt;&gt; dst

 0  1  2  3  4
 1  0  1  2  3
 2  1  0  1  2
 3  2  1  0  1
 4  3  2  1  0
[torch.FloatTensor of size 5x5]

&gt;&gt;&gt;
&gt;&gt;&gt; actualData = 2
&gt;&gt;&gt; actualData
2
&gt;&gt;&gt;
&gt;&gt;&gt; predictedDataA = torch.ones (nClass)
&gt;&gt;&gt; predictedDataA[2] = 0.0
&gt;&gt;&gt; predictedDataB = torch.ones (nClass)
&gt;&gt;&gt; predictedDataB[4] = 0.0
&gt;&gt;&gt; predictedDataC = torch.rand (nClass)
&gt;&gt;&gt; predictedDataA

 1
 1
 0
 1
 1
[torch.FloatTensor of size 5]

&gt;&gt;&gt; predictedDataB

 1
 1
 1
 1
 0
[torch.FloatTensor of size 5]

&gt;&gt;&gt; predictedDataC

 0.4869
 0.1052
 0.5883
 0.1161
 0.4949
[torch.FloatTensor of size 5]

&gt;&gt;&gt;
&gt;&gt;&gt; lossA = ((1.0 - predictedDataA) * dst[actualData]).sum(dim = 0)
&gt;&gt;&gt; lossB = ((1.0 - predictedDataB) * dst[actualData]).sum(dim = 0)
&gt;&gt;&gt; lossC = ((1.0 - predictedDataC) * dst[actualData]).sum(dim = 0)
&gt;&gt;&gt; lossA

 0
[torch.FloatTensor of size 1]

&gt;&gt;&gt; lossB

 2
[torch.FloatTensor of size 1]

&gt;&gt;&gt; lossC

 3.8152
[torch.FloatTensor of size 1]
</code></pre>
<p>*)  Please give us some context about the problem you’re trying to<br>
solve.  It’s likely that your approach doesn’t make sense.  The main<br>
reason is that order of the values in <code>predictedData</code> won’t generally<br>
have any quantitative meaning (unless you train it to, but that’s<br>
another story).  So “distance” in “index space” doesn’t really have<br>
any meaning.  Asking whether <code>argmin</code> matches <code>actualData</code> can<br>
make sense, but asking how far away it is if it doesn’t match probably<br>
doesn’t.  The test against <code>argmin</code> suggests that <code>actualData</code> is an<br>
integer categorical label, and suggests that you might be working on<br>
some kind of a classification problem where <code>CrossEntropyLoss</code> might<br>
be appropriate.</p>
<p>Best.</p>
<p>K. Frank</p>

ilya_L: <p>Hi Frank,</p>
<p>Thanks for the detailed answer, I will update after I’ll give it a try,<br>
I think that cross entropy loss is a good idea</p>
<ul>
<li>I thought about this issue regarding argmin()…</li>
</ul>
<p>some context:<br>
I’m trying to build a network which will predict an inverse function for a channel distortion,<br>
I simulate a signal and pass it trough a random FIR filter (channel distortion function), later I pass this data and the actual data to the network. The network outputs filter coeffs that are suppose to inverse the FIR response.<br>
*the filter is lfilter from torch audio<br>
The argmin() suppose to be used as a detector, I calculate the distance between the reconstructed signal and the initial code signal, argmin is the detected code.<br>
example: symMap = pd.Series(data=[-1, 1j, -1j, 1], index=[0, 1, 2, 3])<br>
than if the reconstructed signal is -0.5 the detected data will be 0.</p>
<p>Thanks,<br>
Ilya</p>

ilya_L: <p>Update:<br>
for now, I used torch.dist( )  without argmin() - on the predetected signal<br>
this seems to work and the model is training</p>
<p>Thanks Frank for the advice</p>