Under the hood, yes, the autograd engine does compute the gradient of the loss with respect to the output but the result is never stored but passed along backward through the graph to compute the gradient with respect to the leaves.
What are leaves: that’s exactly the tensors created with requires_grad=True.
Typically, that would be the parameters of your net and you don’t really need to explicitly set  requires_grad=True because that’s the default for parameters.
That’s why you never really want to write z_predicted = torch.tensor(z_predicted,requires_grad=True) as it breaks your autograd graph.
If you really just gradient of your loss with respect to output_label, try:
output_label = net(input)
output_label_leaf = output_label.detach()
output_label_leaf.requires_grad_()
loss = criterion(output_label_leaf)  # don't do any torch.tensor shenanigans in here
loss.backward()
print(output_label_leaf.grad)