Repository: pytorch
Issue: `create_graph=True` results in grad_fn error for differentiable functions
Labels: module: autograd,triaged

Disclaimer: this ticket is not about a "bug" per se, but rather, a design choice that can cause unexpected behavior for users.

### Summary

The documentation of torch.autograd.grad states that option `create_graph=True` allows users to compute higher order derivative products. However, when a function has a 2nd-order derivative of zero, the 1st-order derivatives are given `grad_fn=None`. Thus when we call grad-of-grad, rather than learn that our function has a 2nd-order derivative of zero, we get a confusing error message suggesting that our function did not have a coherent gradient tape (even though it is in fact fully differentiable).

code example:
```python
x = torch.tensor(1.0, requires_grad=True)
f = 2 * x
g = torch.autograd.grad(f, x, create_graph=True)[0]
g2 = torch.autograd.grad(g, x)[0]
```

error message:
```
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/var/folders/2l/510bgy8104sdl7p1bd9_wx7h0000gn/T/ipykernel_79429/14671407.py in <module>
      6 f = 2 * x
      7 g = torch.autograd.grad(f, x, create_graph=True)[0]
----> 8 g2 = torch.autograd.grad(g, x)[0]

~/opt/anaconda3/envs/default/lib/python3.9/site-packages/torch/autograd/__init__.py in grad(outputs, inputs, grad_outputs, retain_graph, create_graph, only_inputs, allow_unused)
    232         retain_graph = create_graph
    233 
--> 234     return Variable._execution_engine.run_backward(
    235         outputs, grad_outputs_, retain_graph, create_graph,
    236         inputs, allow_unused, accumulate_grad=False)

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
```

### Suggestion
When called with `create_graph=True`, it would be helpful if torch.autograd.grad would create a dummy grad_fn that evaluates to zero instead of grad_fn=None for these cases. This seems like the most intuitive approach in my opinion.

### Versions

Collecting environment information...
PyTorch version: 1.10.2
Is debug build: False
CUDA used to build PyTorch: None
ROCM used to build PyTorch: N/A

OS: macOS 12.1 (x86_64)
GCC version: Could not collect
Clang version: 13.0.0 (clang-1300.0.29.30)
CMake version: version 3.20.2
Libc version: N/A

Python version: 3.9.7 (default, Sep 16 2021, 08:50:36)  [Clang 10.0.0 ] (64-bit runtime)
Python platform: macOS-10.16-x86_64-i386-64bit
Is CUDA available: False
CUDA runtime version: No CUDA
GPU models and configuration: No CUDA
Nvidia driver version: No CUDA
cuDNN version: No CUDA
HIP runtime version: N/A
MIOpen runtime version: N/A

Versions of relevant libraries:
[pip3] numpy==1.20.3
[pip3] torch==1.10.2
[pip3] torchmin==0.0.2
[pip3] torchvision==0.11.3
[conda] blas                      1.0                         mkl
[conda] ffmpeg                    4.3                  h0a44026_0    pytorch
[conda] mkl                       2021.4.0           hecd8cb5_637
[conda] mkl-service               2.4.0            py39h9ed2024_0
[conda] mkl_fft                   1.3.1            py39h4ab4a9b_0
[conda] mkl_random                1.2.2            py39hb2f4e1b_0
[conda] numpy                     1.20.3           py39h4b4dc7a_0
[conda] numpy-base                1.20.3           py39he0bd621_0
[conda] pytorch                   1.10.2                  py3.9_0    pytorch
[conda] torchvision               0.11.3                 py39_cpu    pytorch

cc @ezyang @albanD @zou3519 @gqchen @pearu @nikitaved @soulitzer @Lezcano @Varal7