How can test result change even when the learning rate is 0?

sayangsep: <p>Here is my simple classification model:</p>
<pre><code> def __init__(self):
     super().__init__()
     self.fc1 = nn.Linear(246, 512)
     self.bn1 = nn.BatchNorm1d(512)
     self.relu1 = nn.ReLU()
     self.dout = nn.Dropout(0.5)
     self.fc2 = nn.Linear(512, 512)
     self.bn2 = nn.BatchNorm1d(512)
     self.prelu1 = nn.ReLU()
     self.dout1 = nn.Dropout(0.5)
     self.fc3 = nn.Linear(512, 512)
     self.bn3 = nn.BatchNorm1d(512)
     self.prelu2 = nn.ReLU()
     self.dout2 = nn.Dropout(0.5)
     self.fc4 = nn.Linear(512, 512)
     self.bn4 = nn.BatchNorm1d(512)
     self.prelu3 = nn.ReLU()
     self.dout3 = nn.Dropout(0.5)
     self.fc5 = nn.Linear(512, 512)
     self.bn5 = nn.BatchNorm1d(512)
     self.prelu4 = nn.ReLU()
     self.out = nn.Linear(512,1)
     self.out_act = nn.Sigmoid()
     
 def forward(self, input_):
     a1 = self.fc1(input_)
     h1 = self.relu1(self.bn1(a1))
     dout = self.dout(h1)
     a2 = self.fc2(dout)
     h2 = self.prelu1(self.bn2(a2))
     dout1 = self.dout1(h2)
     a3 = self.fc3(dout1)
     h3 = self.prelu2(self.bn3(a3))
     dout2 = self.dout2(h3)
     a4 = self.fc4(dout2)
     h4 = self.prelu3(self.bn4(a4))
     dout3 = self.dout3(h4)
     a5 = self.fc5(dout3)
     h5 = self.prelu4(self.bn5(a5))
     a6 = self.out(h5)
     y = self.out_act(a6)
     return y
</code></pre>
<p>During training even when I am fixing the learning rate to 0 still somehow the parameters get updated and I got different test results in different epoch. How’s that possible? My understanding was if the lr =0 then the parameters update will be zero.<br>
Any help is really appreciated.</p>

ptrblck: <p>If you leave your model in training mode (not calling <code>model.eval()</code> or calling <code>model.train()</code> explicitly), the running estimates in your batchnorm layers in your model will be updated.<br>
Even without optimizing parameters, your validation outputs will change after a forward pass during training.</p>

sayangsep: <pre><code class="lang-python">for e in range(num_epochs):
        e_losses.append(train_epoch(X_train,Y_train,net, opt, criterion,4) )
        net.eval()
        x_t = Variable(X[id_cv,:])
        Y_t = Y[id_cv,:]
        with torch.no_grad():
            y_t = net(x_t)
            y_ev = [x&gt;0.5 for x in y_t]        
            yy = y_ev
            acc.append(accuracy_score(np.array(yy).astype(int),np.array(Y_t.squeeze().tolist())))
        if e%100 == 0 and e!=0:
                plt.plot(acc)
                plt.show()
</code></pre>
<p>Here’s my code where I am calling model.eval() before validation. But, still the validation results are different for different epochs.</p>

ptrblck: <p>Using your code, I get exact the same results, if I call <code>model.eval()</code> before the loop:</p>
<pre><code class="lang-python">x = torch.randn(10, 246)
target = torch.randint(0, 2, (10, 1)).float()
criterion = nn.BCELoss()
model = MyModel()
model.eval()


outputs = []
losses = []
with torch.no_grad():
    for _ in range(10):
        output = model(x)
        loss = criterion(output, target)
        outputs.append(output)
        losses.append(loss)

outputs = torch.stack(outputs)
print((outputs[0] == outputs).all())
&gt; tensor(1, dtype=torch.uint8)

losses = torch.stack(losses)
print((losses[0] == losses).all())
&gt; tensor(1, dtype=torch.uint8)
</code></pre>
<p>Note that the results will differ, if you comment <code>model.eval()</code>.</p>
<p>In your code snippet you are using <code>train_epoch</code>, which seems to train the model?<br>
If so, you will surely get different results for your evaluation, since the parameters changed.<br>
Let me know, if I misunderstood something.</p>

sayangsep: <p>Thanks for the reply. Yes, train_epoch() is training the model but since I set lr=0,  I thought that the validation results will be the same.  But, it seems like the batch norm is changing the parameters even though the learning rate is 0. Is there any way to prevent it?</p>

ptrblck: <p>Since your model is probably still in <code>.train()</code> model, the running stats will be updated:</p>
<aside class="quote no-group" data-username="ptrblck" data-post="2" data-topic="48728" 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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>If you leave your model in training mode (not calling <code>model.eval()</code> or calling <code>model.train()</code> explicitly), the running estimates in your batchnorm layers in your model will be updated.<br>
Even without optimizing parameters, your validation outputs will change after a forward pass during training.</p>
</blockquote>
</aside>
<p>Try to call <code>model.eval()</code> before the training step.</p>

ndvbd: <p>How comes that when lr=0 the train() changes the weights? I am running a training with lr=0 (with SGD) on 1 training example, and the loss changes every iteration. How come?</p>

ptrblck: <p>Your model might still use dropout layers which will also change the loss but will of course not update the parameters.<br>
An optimizer without momentum or any internal stats should not update any parameters with a learning rate of <code>0</code> so could you post a minimal and executable code snippet to reproduce the issue, please?</p>

ndvbd: <aside class="quote no-group" data-username="ptrblck" data-post="8" data-topic="48728">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>mentum or any internal stats should not update any parameters with a learning rate of <code>0</code> so could you post a minimal and executable code</p>
</blockquote>
</aside>
<p>You are absolutely right! Thanks! Once I scanned all the dropout layers and set their p=0 before the training, I could see that indeed learning rate of 0 results no change in loss over iterations.</p>