Pytorch training question

Luca_Pamparana: <p>I have been looking at the pytorch example for training a classifier here: <a href="https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html" rel="nofollow noopener">https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html</a></p>
<p>The training code is as follows:</p>
<pre><code class="lang-auto">for epoch in range(2):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()
        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')
</code></pre>
<p>This might be a dumb question but nowhere do we actually check if the training loss has decreased or not (except to print the statistics). Is this happening in the background so that the model is updated if the training loss is actually doing down?</p>
<p>If yes, when are the weights updated? Do the weights get updated if the training loss decreases for each minibatch or do they get updated if the average error across all the mini batches go down (i.e. for the whole epoch?)</p>
<p><strong>EDIT</strong><br>
So, it seems that the <code>optimizer.step()</code> function is the one that will update the parameters. But looking at how the optimizer is used, I see the declaration:</p>
<pre><code class="lang-auto">criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
</code></pre>
<p>Then at some point during the training we have:</p>
<pre><code class="lang-auto">outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
</code></pre>
<p>The <code>optimizer</code> itself does not seem to have any access to the loss function. So how can it know whether a GD step is actually making things better or worst!</p>

JuanFMontesinos: <p>It does not know. It backpropagates whatever result is. You don’t selectively backpropagate depending on if loss if better or now, in fact, that would be impossible.</p>
<p>Realize that, in the early stage of training, network havent seen any data. For 1st iteration, loss will decrease (ideally), for the 2nd one, data may be otally different, thus, higher loss, but you need to backpropagate in order to keep learning.</p>
<p>When you backpropagate you compute gradients and error for whatever your loss is.</p>

Luca_Pamparana: <p>Thank you for your answer! But how does the optimizer know when the current gradient direction is not optimal (i.e. to change the hyper parameters like learning rate etc.) if it has no access to the loss value.</p>

JuanFMontesinos: <p>It’s everything autograd machinery.</p>
<p>First of all, stop thinking about optimal directions, optimizer or any DL algorithm is agnostic to optimality.<br>
When you call loss.backward(), each tensor in the model computes gradients following chain rule and carry gradients back to leaf tensors. For almost each torch function there exist a backward function which computes gradients when you call backward.</p>
<p>Each tensor points to tensors from which they are composed in order to follow chain rule. Have a look at this video in which autograd is explained.<br>
<div class="lazyYT" data-youtube-id="MswxJw-8PvE" data-youtube-title="PyTorch Autograd Explained - In-depth Tutorial" data-width="480" data-height="270" data-parameters="feature=oembed&amp;wmode=opaque"></div></p>