Gradient disappearing after first epoch in manual linear regression
I'm new to Pytorch and I've been working through the tutorials and playing around with toy examples. I wanted to just make a super simple model to get a better handle on autograd, but I'm running into issues.

I'm trying to train a linear regression model but I keep running into the following error,

---------------------------------------------------------------------- 

RuntimeError                              Traceback (most recent call last)
&lt;ipython-input-80-ba5ca34a3a54&gt; in &lt;module&gt;()
      9   loss = torch.dot(delta, delta)
     10 
---&gt; 11   loss.backward()
     12   with torch.no_grad():
     13     w, b = w - learning_rate*w.grad.data, b - learning_rate*b.grad.data

/usr/local/lib/python3.6/dist-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
     91                 products. Defaults to ``False``.
     92         """
---&gt; 93         torch.autograd.backward(self, gradient, retain_graph, create_graph)
     94 
     95     def register_hook(self, hook):

/usr/local/lib/python3.6/dist-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     87     Variable._execution_engine.run_backward(
     88         tensors, grad_tensors, retain_graph, create_graph,
---&gt; 89         allow_unreachable=True)  # allow_unreachable flag
     90 
     91 

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn


And for reference, the code is here,

# dataset for training
X = torch.randn(100, 3)
y = -3*X[:,0] + 2.2*X[:,1] + 0.002*X[:,2] + 1

w = torch.randn(3, requires_grad=True, dtype=torch.float)  # model weights
b = torch.randn(1, requires_grad=True, dtype=torch.float)  # model bias


num_epochs = 10
learning_rate = 1e-4

for i in range(num_epochs):

  y_hat = torch.mv(X, w) + b
  delta = y_hat - y
  loss = torch.dot(delta, delta)

  loss.backward()
  with torch.no_grad():
    w, b = w - learning_rate*w.grad, b - learning_rate*b.grad


The issue seems to be that after the first epoch the gradient attribute is set to None, but I'm a little confused why this would be the case.

If I try to zero the gradient after updating the weights, then I get a similar error.

The answer lies in locally disabling gradient computation. As you can see in the first example, computations carried out with the torch.no_grad() context manager result in tensors for which requires_grad == False. Since you create "fresh" w and b instead of updating them in place, these tensors lose the requires_grad property after the first iteration and you get the error on 2nd iteration. A simple fix is to reenable gradients

with torch.no_grad(): 
    w, b = w - learning_rate*w.grad, b - learning_rate*b.grad 
    w.requires_grad_(True) 
    b.requires_grad_(True) 


If you look up the source of optimizers in pytorch optim module, such as SGD, you will see that they use the in-place operators such as add_. You can rewrite your loop in this manner

with torch.no_grad(): 
    w.sub_(learning_rate*w.grad)
    b.sub_(learning_rate*b.grad)


which will not touch the requires_grad flag, since the tensors keep their "identity" - just change values. In this case, you will need to remember to call w.zero_grad() and b.zero_grad() in each iteration or the gradient values will keep additively growing.
