What about this?
adversarial_loss = cross_entropy(logits_1.detach(), logits_4)
nll_loss = cross_entropy(logits_1, labels)

With that solution the only place where logits_1 is used without .detach() is in the calculation of nll_loss, so I think everything will work out exactly as desired.
The fact that you zero the grads earlier does not affect the final grads because the final grads aren’t calculated until you run loss.backward().