PyTorch runtime error: retain_graph=True

Nikolaos_Sintoris: <p>Hello everyone.</p>
<p>I have 2 different jupyter notebooks that almost do the same thing.</p>
<p>In the first notebook I do the following:<br>
a) I downloaded vgg16<br>
b) Pass my images to vgg16 and take the output vector from an intermidiate layer<br>
c) Create a matrix with all those vectors.<br>
d) Create my own MLP and train it with this matrix.</p>
<p>In the second notebook I do the exactly same thing as the previous one, but the only difference is that instead of the vgg16 model I have resnet50 with the pre-trained weights of MoCo model. All the other code is the same.</p>
<p>My problem is that when I train my MLP with resnet50 MoCo model I have the following error: “Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time”.</p>
<p>So after a search I did, I change loss.backward() to loss.backward(retain_graph=True) and it worked.<br>
But the problem is, that it is running very very slow.</p>
<p>I do not understand why this is happening when I have resnet50 MoCo model and not with vgg16.</p>
<p>Can anyone help me how to fix this?</p>
<p>My train function was the following for both notebooks in the beginning:</p>
<pre><code class="lang-auto">def train_model(model, data, actual_labels):
    model.train()
    
    optimizer.zero_grad()
    
    predicted_training_labels = model(data)

    loss = loss_function(predicted_training_labels, actual_labels)
    
    accuracy = compute_accuracy(predicted_training_labels, actual_labels)

    loss.backward()

    optimizer.step()
    
    return loss.item()
</code></pre>
<p>Thanks a lot.</p>

Alexey_Demyanchuk: <p>It might be you are trying to backward through resnet as well. It is hard to guess without knowledge of how exactly you collect the features and what <code>data</code> argument represent in the <code>train_model</code> function: could be batch or full matrix.</p>

Nikolaos_Sintoris: <p>Hmmm, I do not think that I understand what you said.</p>
<p>To help you, my data is a matrix with shape 1000x2048. Every row of the matrix is the output from a intermediate layer of resnet50 MoCo model. First I create the matrix, so when I train my MLP, I do not use resnet50 at all. I use it only in the beginning in order to create the matrix.</p>

Alexey_Demyanchuk: <p>I can not reproduce the error using your code and some toy data and model.</p>
<pre><code class="lang-auto">def train_model(model, data, actual_labels):
    model.train()
    
    optimizer.zero_grad()
    
    predicted_training_labels = model(data)

    loss = loss_function(predicted_training_labels, actual_labels)
    
    # accuracy = compute_accuracy(predicted_training_labels, actual_labels)

    loss.backward()

    optimizer.step()
    
    return loss.item()

data = torch.randn(1000, 2048)
labels = torch.empty(1000, dtype=torch.long).random_(3)
loss_function = nn.CrossEntropyLoss()
model = nn.Linear(2048, 3)
optimizer = torch.optim.Adam(model.parameters())

for i in range(10):
    l = train_model(model, data, labels)
    print(l)
</code></pre>
<p>This code is working fine and without any error.</p>

Nikolaos_Sintoris: <p>Yes and for me when I use vgg16 it works perfect without error and very fast.</p>
<p>Can you explain to me what do you mean with this sentence “It might be you are trying to backward through resnet as well.”</p>
<p>I believe the problem is something with resnet50 MoCo model because it is the only thing that I change.</p>

Alexey_Demyanchuk: <p>It would be helpful to take a look on the code there you collect the features from resnet. “backward through resnet” means: if you collect your features then resnet in training mode and do it without <code>with torch.no_grad</code> context your matrix will be connected to resnet computational graph.</p>

Alexey_Demyanchuk: <p>Consider this code:</p>
<pre><code class="lang-auto">rn18 = models.resnet18()
rn18.fc = nn.Linear(512, 2048)
images = torch.randn(1000, 3, 32, 32)
data = rn18(images)

data = rn18(images)
labels = torch.empty(1000, dtype=torch.long).random_(3)
loss_function = nn.CrossEntropyLoss()
model = nn.Linear(2048, 3)
optimizer = torch.optim.Adam(model.parameters())

for i in range(10):
    l = train_model(model, data, labels)
    print(l)
</code></pre>
<p>It will fail, because it is traying to propogate through resnet as wel as through MLP. Also single pass takes much longer now.</p>

Alexey_Demyanchuk: <p>And using those changes:</p>
<pre><code class="lang-auto">rn18 = models.resnet18()
rn18.fc = nn.Linear(512, 2048)
rn18.eval()
images = torch.randn(1000, 3, 32, 32)
with torch.no_grad():
    data = rn18(images)

labels = torch.empty(1000, dtype=torch.long).random_(3)
loss_function = nn.CrossEntropyLoss()
model = nn.Linear(2048, 3)
optimizer = torch.optim.Adam(model.parameters())

for i in range(10):
    l = train_model(model, data, labels)
    print(l)
</code></pre>
<p>Everything is working fine.<br>
Also, you can do <code>data.detach_()</code> on your matrix.</p>

Nikolaos_Sintoris: <p>If I do detach_() in my data, I realize that my new model (train_model(model, data, labels)) does not update its parameters. So eventually I do not train it.</p>

Alexey_Demyanchuk: <p>True. You should detach it only once and only after collecting the features using the Resnet. Then, you can train as usual. The code snippet in my previous post is the preferred way to do so (in my opinion), as it is more explicit: you don’t need to train Resnet - set it to <code>eval</code>, you don’t want pytorch to compute gradients while you extracting the features - use <code>with torch.no_grad()</code> context.</p>

Nikolaos_Sintoris: <p>Thank you very much.<br>
You were right. With <code>with torch.no_grad()</code>, worked perfect.</p>

Alexey_Demyanchuk: <p>Great to hear it helps <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"><br>
All the best!</p>