My network's weights get updated despite using torch.no_grad()

nbusser: <p>Hi everyone <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>I want to implement an early stopping mechanic to my DNN. Thus, I have to calculate the validation loss for each epoch.<br>
I use <code>@torch.no_grad()</code> during the validation loss calculation to avoid any gradient computation that would alter the training.</p>
<p>Here is my training loop:</p>
<pre data-code-wrap="python"><code class="lang-python">def main():
    training_dataset = torch.load("dataset/training_dataset.pth")

    net = dnn.Net()

    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(net.parameters(), lr=0.0005)

    early_stopping = EarlyStopping(tolerance=5, min_delta=10)
    validation_dataset = torch.load("dataset/validation_dataset.pth")

    n_epochs = 150
    for epoch in tqdm.tqdm(range(n_epochs)):
        epoch_train_loss = train_epoch(training_dataset, net, criterion, optimizer)
        with torch.no_grad():
            epoch_validate_loss, _ = validation.validate(
                validation_dataset, net, criterion
            )
</code></pre>
<p>Here is the validation function:</p>
<pre><code class="lang-auto">@torch.no_grad()
def validate(
    validation_dataset: torch.utils.data.Dataset, net: nn.Module, criterion: nn.Module
):
    net.eval()
    validation_loader = torch.utils.data.DataLoader(validation_dataset, batch_size=1)

    correct = 0.0
    loss = 0

    for inputs, target in validation_loader:
        output = net(inputs)
        loss = criterion(output, target)

        _, pred = output.max(1)
        correct += (pred == target).sum()

    accuracy = correct / len(validation_dataset) * 100.0
    return loss, accuracy
</code></pre>
<p><em>NB: I know that using both <code>@torch.no_grad</code> and <code>with torch.no_grad()</code> is overkill</em></p>
<p>I run the training on 150 epochs.<br>
After the training, I run calculate the accuracy on the validation set.</p>
<p>Here is what I obtain when:</p>
<ul>
<li><strong>NOT</strong> calculating validation loss for each epoch: <strong>91.67%</strong></li>
<li>Calculating validation loss for each epoch: <strong>97.22%</strong></li>
</ul>
<p>It then seems that calculating the validation loss for each epoch has definitely alters training by <strong>leaking validation data</strong>.</p>
<p>Can you tell me what I am doing wrong here?</p>

ptrblck: <aside class="quote no-group" data-username="nbusser" data-post="1" data-topic="201687">
<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/n/e8c25b/48.png" class="avatar"> nbusser:</div>
<blockquote>
<p>by <strong>leaking validation data</strong></p>
</blockquote>
</aside>
<p>Not necessarily, as you could also observe noise creating by additional calls to the pseudorandom number generator. You could check how sensitive your training is to the seed.</p>

nbusser: <p>Oh sure I did not think of it! Socan I safely conclude that there is nothing wrong here?</p>

ptrblck: <p>You could run additional tests using different seeds to estimate the <code>mean</code> and <code>stddev</code> of e.g. the accuracy or loss of your current training routine and compare it to the currently observed difference. You could also double check that weights are never updated explicitly by comparing (some) parameters before and after the validation run, just to make sure.</p>

nbusser: <p>I’ve explicitely checked the model’s weights and they are not modified after the validation run. Thank you for your time and your answer!</p>