Whenever you do an operation with Variables as input, PyTorch builds up a graph of the computations involved and stores any intermediate values needed for backpropagation.
For example
>>> a = Variable(torch.randn(1), requires_grad=True)
>>> b = a*a
>>> print(b.grad_fn)
<MulBackward1 object at 0x7f0f6a6d2a90>

As you can see the Variable b has a .grad_fn attribute in which PyTorch has stored the details of the calculation used to produce the value stored in b.