from __future__ import print_function
from torch.autograd import Variable
import torch

xx = Variable(torch.Tensor([2]), requires_grad = True)
yy = 3*xx
zz = yy**2

yy.register_hook(print)
zz.register_hook(print)
tar = Variable(torch.Tensor([100]), requires_grad = False)
loss = zz-tar
loss.backward()
#normally here follows optimizer.step()

Recently, I found that I did not even get straight with the real clear meaning of the back propagation and the optimizer.step()
So I tried the above code,  what I felt confused is that no matter what the target is : the grad of yy, zz  has the same value:
tar = Variable(torch.Tensor([100]), requires_grad = False)
tar = Variable(torch.Tensor([1000000]), requires_grad = False)
tar = Variable(torch.Tensor([1000000000000]), requires_grad = False)

tensor([ 1.])    for zz.grad
tensor([ 6.])     for yy.grad

But these two sure change when xx change,
xx = Variable(torch.Tensor([4]), requires_grad = True)

and

tensor([ 1.])   for zz.grad
tensor([ 24.])  for yy.grad

So I feel confuse that:
How could it possible that the grad of computation graph node  has  no relation to target,  from my perspective, if the loss is larger, the grad shall become larger as well, so they would optimize more in the optimizer.step()
Am I too confused about the basic knowledge about grad back propagation?
Will optimizer such as torch.optim.SGD()   would add connection between loss and grad?
Thanks a lot for reading all above!