It supposedly trying to backward through the graph a second time, because differentiate gr_a and gr_b involves parameters of neural network. Why didn’t it raise RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. error?

I suppose because there are two separate graphs. I.e., the first graph for
loss = torch.mean((f_z-z)**2)
which was “done” (in the sense of “completed”) by calling
loss.backward(der_shape)
and then you build a second graph,
gr_a = a.grad.clone()
gr_b = b.grad.clone()
var_loss = torch.mean((gr_a+gr_b-5)**2)

that was then evaluated by var_loss.backward()
example, the following would work
a = torch.tensor([-2.], requires_grad=True)
b = torch.tensor([-2.], requires_grad=True)

var_loss = a/b
var_loss.backward()

var_loss = a/b
var_loss.backward()

but the following would cause the error you mentioned:
a = torch.tensor([-2.], requires_grad=True)
b = torch.tensor([-2.], requires_grad=True)

var_loss = a/b
var_loss.backward()

var_loss.backward()

Note in the last example, I don’t redefine var_loss and hence no new graph is built