Hi Mnauf!



 mnauf:

I am working on a toy dataset to play with. I am trying to calculate loss via BCEWithLogitsLoss(), but loss is decreasing very slowly. And prediction giving by Neural network also is not correct.
model = nn.Linear(1,1)
input_tensor = th.tensor([[5.8],[6.0],[5.5],[4.5],[4.1],[3.5]],requires_grad=True)
target_tensor = th.tensor([[1.0],[1],[1],[0],[0],[0]],requires_grad=False)
criterion = nn.BCEWithLogitsLoss()
...

Loss values:
tensor(1.7171)
tensor(1.3382)
...
tensor(0.4616)
tensor(0.4613)

print(model(th.tensor([80.5]))) gives tensor([139.4498], grad_fn=<AddBackward0>)


I suspect that you are misunderstanding how to interpret the
predictions made by this network.
First, you are using, as you say, BCEWithLogitsLoss.  Therefore you
are training your predictions to be “logits.”  These are “raw scores,”
if you will, that are real numbers ranging from -infinity to +infinity.
Values less than 0 predict class “0” and values greater than 0
predict class “1”.
(When pumped though a sigmoid function, they become predicted
probabilities of the sample in question being in the “1” class.  We
generally convert that to a non-probabilistic prediction by saying
P < 0.5 --> class “0”, and P > 0.5 --> class “1”.)
Second, your model is a simple (one-dimensional) linear function.
Therefore it can’t cluster predictions together – it can only get the
boundary between class “0” and class “1” right.  (Because of this,
you will not ever be able to drive your loss to zero, even if your
prediction accuracy is perfect.)  From your six data points that
boundary is somewhere around 5.0.
Anyway, your model works for me.
Note, I’ve run the below test using pytorch version 0.3.0, so I had
to tweak your code a little bit.
Here is my complete script:
import torch
print (torch.__version__)

torch.manual_seed (2019)

model = torch.nn.Linear (1, 1)
print ('model.weight =', model.weight.data[0][0])
print ('model.bias =', model.bias.data[0])

input_tensor = torch.autograd.Variable (torch.Tensor([[5.8],[6.0],[5.5],[4.5],[4.1],[3.5]]))
target_tensor = torch.autograd.Variable (torch.Tensor([[1.0],[1],[1],[0],[0],[0]]))
criterion = torch.nn.BCEWithLogitsLoss()
optimizer = torch.optim.SGD(model.parameters(), lr =0.1)

for  i in range (500):
    optimizer.zero_grad()
    predict_tensor = model(input_tensor)
    loss = criterion(predict_tensor,target_tensor)
    loss.backward()
    optimizer.step()
    if  (i + 1) % 100 == 0:
        print (loss.data[0])
        pd = predict_tensor.data
        print (pd[0][0], pd[1][0], pd[2][0], pd[3][0], pd[4][0], pd[5][0])

print ('model.weight =', model.weight.data[0][0])
print ('model.bias =', model.bias.data[0])

And here is the complete output:
>>> import torch
>>> print (torch.__version__)
0.3.0b0+591e73e
>>>
>>> torch.manual_seed (2019)
<torch._C.Generator object at 0x000001FFD89F5630>
>>>
>>> model = torch.nn.Linear (1, 1)
>>> print ('model.weight =', model.weight.data[0][0])
model.weight = -0.41710567474365234
>>> print ('model.bias =', model.bias.data[0])
model.bias = 0.1750929355621338
>>>
>>> input_tensor = torch.autograd.Variable (torch.Tensor([[5.8],[6.0],[5.5],[4.5],[4.1],[3.5]]))
>>> target_tensor = torch.autograd.Variable (torch.Tensor([[1.0],[1],[1],[0],[0],[0]]))
>>> criterion = torch.nn.BCEWithLogitsLoss()
>>> optimizer = torch.optim.SGD(model.parameters(), lr =0.1)
>>>
>>> for  i in range (500):
...     optimizer.zero_grad()
...     predict_tensor = model(input_tensor)
...     loss = criterion(predict_tensor,target_tensor)
...     loss.backward()
...     optimizer.step()
...     if  (i + 1) % 100 == 0:
...         print (loss.data[0])
...         pd = predict_tensor.data
...         print (pd[0][0], pd[1][0], pd[2][0], pd[3][0], pd[4][0], pd[5][0])
...
0.6329450607299805
0.4733131527900696 0.5083065032958984 0.42082297801971436 0.2458558976650238 0.17586903274059296 0.07088879495859146
0.5748059749603271
0.5860824584960938 0.650752604007721 0.489077091217041 0.16572602093219757 0.03638556972146034 -0.15762503445148468
0.5252929329872131
0.6919865608215332 0.7841049432754517 0.5538088083267212 0.09321644902229309 -0.09102052450180054 -0.3673758804798126
0.48296624422073364
0.7910601496696472 0.9085955619812012 0.6147568225860596 0.027079343795776367 -0.20799170434474945 -0.5605981349945068
0.4465940296649933
0.8835896849632263 1.024709701538086 0.6719093322753906 -0.03369140625 -0.3159317672252655 -0.7392921447753906
>>> print ('model.weight =', model.weight.data[0][0])
model.weight = 0.7067369818687439
>>> print ('model.bias =', model.bias.data[0])
model.bias = -3.2145912647247314

The loss goes down systematically (but, as noted above, doesn’t
go to zero).  And at the end of the run the prediction accuracy is
perfect on your set of six samples (with the predictions understood
as described above).
Good luck.
K. Frank
[Edit:]
Please let me correct an incorrect statement I made.  I said that
you can’t drive the loss all the way to zero, but in fact you can.
As the “weight” in the model – the multiplicative factor in the linear
function – becomes larger and larger, the logits predicted by the
model get pushed out towards -infinity and +infinity.  This will cause
the sigmoid (that is implicit in BCEWithLogitsLoss) to saturate at
0 and 1, so the predictions will become (increasing close to) exactly
correct (provided the bias is adjusted according, which the training
algorithm does), and the loss approaches zero.
Here are the last twenty loss values obtained by running Mnauf’s
training loop for 10,000 iterations:
0.06364566087722778
0.06364051252603531
0.06363534182310104
0.06363023072481155
0.06362506002187729
0.06361991167068481
0.06361475586891174
0.06360962986946106
0.06360447406768799
0.06359934061765671
0.06359419226646423
0.06358903646469116
0.06358392536640167
0.0635787770152092
0.06357365846633911
0.06356850266456604
0.06356338411569595
0.06355825066566467
0.06355313956737518
0.0635480210185051

So the loss does approach zero, although very slowly.  Note, as the
sigmoid saturates, its gradients go to zero, so (with a fixed learning
rate) the training slows way down.