Inplace operation error with GAN

username: blakebullwinkel
cooked: <p>I am trying to train a GAN with the algorithm below but am getting the following error: <code>RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [30, 1]], which is output 0 of TBackward, is at version 2; expected version 1 instead.</code></p>
<p>I know that the problem is due to a bug described <a href="https://github.com/pytorch/pytorch/issues/39141" rel="noopener nofollow ugc">here</a> that was fixed in v1.5, but I am not sure how to correctly modify my code to solve the issue. Should I be waiting to take <code>optiG.step()</code> until after the discriminator loss has been computed? Thanks!</p>
<pre><code class="lang-auto">optiG = torch.optim.SGD(G.parameters(), lr=g_lr, momentum=momentum, nesterov=True)
optiD = torch.optim.SGD(D.parameters(), lr=d_lr, momentum=momentum, nesterov=True)

for epoch in range(niters):
        
        # Train Generator
        for p in D.parameters():
            p.requires_grad = False # turn off computation for D

        for _ in range(G_iters):
            grid_samp = problem.get_grid_sample()
            pred = G(grid_samp)
            residuals = problem.get_equation(pred, grid_samp, G)
            optiG.zero_grad()
            g_loss = criterion(D(fake), real_labels)
            g_loss.backward(retain_graph=True)
            optiG.step()

        # Train Discriminator
        for p in D.parameters():
            p.requires_grad = True # turn on computation for D

        for _ in range(D_iters):
            if wgan:
                norm_penalty = calc_gradient_penalty(D, real, fake, gp, cuda=False)
            else:
                norm_penalty = torch.zeros(1)

            real_loss = criterion(D(real), real_labels)
            fake_loss = criterion(D(fake), fake_labels)

            optiD.zero_grad()
            d_loss = (real_loss + fake_loss)/2 + norm_penalty
            d_loss.backward(retain_graph=True)
            optiD.step()
</code></pre>

username: ptrblck
cooked: <p>This line of code looks strange:</p>
<pre><code class="lang-python">g_loss.backward(retain_graph=True)
</code></pre>
<p>as it would keep the computation graph in <code>G</code> alive. Since you are also not detaching <code>fake</code> in:</p>
<pre><code class="lang-python">fake_loss = criterion(D(fake), fake_labels)
</code></pre>
<p>these operations:</p>
<pre><code class="lang-python">d_loss = (real_loss + fake_loss)/2 + norm_penalty
d_loss.backward(retain_graph=True)
</code></pre>
<p>would most likely try to backprop through <code>G</code> again (and since it’s already updated, the intermediate activations are stale and the error is raised).<br>
Remove the <code>retain_graph=True</code> usage unless you really need it and <code>detach()</code> the <code>fake</code> tensor when updating <code>D</code>.</p>

username: blakebullwinkel
cooked: <p>Awesome, thank you! If I detach the <code>fake</code> tensor when calculating <code>fake_loss</code>, can I remove <code>retain_graph=True</code> from both <code>g_loss.backward()</code> and <code>d_loss.backward()</code>?</p>

username: ptrblck
cooked: <p>I think so. You should definitely try to remove the <code>retain_graph=True</code> usage unless you have a very specific reason to use it. In a lot of cases this attribute is used as a workaround and creates other issues unfortunately, as it’s not fitting into the actual use case.</p>