Following is snippet from DCGAN pytorch tutorial
        netD.zero_grad()
        real_cpu = data[0].to(device)
        b_size = real_cpu.size(0)
        label = torch.full((b_size,), real_label, dtype=torch.float, device=device)
        output = netD(real_cpu).view(-1)
        errD_real = criterion(output, label)
        errD_real.backward() # <------------------------ BACKWARD CALLED ONCE
        D_x = output.mean().item()

        noise = torch.randn(b_size, nz, 1, 1, device=device)
        fake = netG(noise)
        label.fill_(fake_label)
        output = netD(fake.detach()).view(-1)
        errD_fake = criterion(output, label)
        errD_fake.backward() # <------------------------ BACKWARD CALLED AGAIN
        D_G_z1 = output.mean().item()
        errD = errD_real + errD_fake
        optimizerD.step()

Here backward is called twice with no issue. Gradients are “accumulated” (according to the tutorial) and are used to update the weights with optimizerD.step
However when I did the following
        D_x = netD(x)
        D_T_x = netD(T_x) 
        errD_real = criterion(D_x, label)
        errD_real.backward() # <------------------------ BACKWARD CALLED ONCE
        L_real = l2loss(D_x, D_T_x)
        L_real.backward() # <------------------------ BACKWARD CALLED AGAIN

I get this error
RuntimeError: Trying to backward through the graph a second time (or directly access saved variables after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved variables after calling backward.

And I don’t see why the former is okay but the latter isn’t when they should be concerning the same graph for the netD parameters.
Please help me clear my misunderstanding. Thank you so much.
Best,
Gordon