Wrapping the forward pass in a torch.no_grad() block will not store any intermediate activations, which would be needed to compute the gradients during the backward pass.
You would get an error in loss.backward(), but you are avoiding it by detaching the loss and setting requires_grad=True in:
loss = Variable(loss, requires_grad = True)

However, your training is still broken and the model will not be updated.
torch.no_grad() should only be used during evaluation and testing, if no gradients should be computed and no parameter updates are needed.
CC @tianle-BigRice