PyTorch:定义新的 Autograd 函数

原文:https://pytorch.org/tutorials/beginner/examples_autograd/polynomial_custom_function.html#sphx-glr-beginner-examples-autograd-polynomial-custom-function-py

校对:DrDavidS

这里我们准备一个三阶多项式,通过最小化平方欧几里得距离来训练,并预测函数 y = sin(x)-pipi上的值。

这里我们不将多项式写为y = a + bx + cx^2 + dx^3,而是将多项式写为y = a + bP_3(c + dx),其中P_3(x) = 1/2 (5x ^ 3 - 3x)是三次勒让德多项式

此实现使用了 PyTorch 张量(tensor)运算来实现前向传播,并使用 PyTorch Autograd 来计算梯度。

在此实现中,我们实现了自己的自定义 Autograd 函数来执行P'_3(x)。 从数学定义上讲,P'_3(x) = 3/2 (5x ^ 2 - 1)

  1. import torch
  2. import math
  3. class LegendrePolynomial3(torch.autograd.Function):
  4. """
  5. We can implement our own custom autograd Functions by subclassing
  6. torch.autograd.Function and implementing the forward and backward passes
  7. which operate on Tensors.
  8. """
  9. @staticmethod
  10. def forward(ctx, input):
  11. """
  12. In the forward pass we receive a Tensor containing the input and return
  13. a Tensor containing the output. ctx is a context object that can be used
  14. to stash information for backward computation. You can cache arbitrary
  15. objects for use in the backward pass using the ctx.save_for_backward method.
  16. """
  17. ctx.save_for_backward(input)
  18. return 0.5 * (5 * input ** 3 - 3 * input)
  19. @staticmethod
  20. def backward(ctx, grad_output):
  21. """
  22. In the backward pass we receive a Tensor containing the gradient of the loss
  23. with respect to the output, and we need to compute the gradient of the loss
  24. with respect to the input.
  25. """
  26. input, = ctx.saved_tensors
  27. return grad_output * 1.5 * (5 * input ** 2 - 1)
  28. dtype = torch.float
  29. device = torch.device("cpu")
  30. # device = torch.device("cuda:0") # Uncomment this to run on GPU
  31. # Create Tensors to hold input and outputs.
  32. # By default, requires_grad=False, which indicates that we do not need to
  33. # compute gradients with respect to these Tensors during the backward pass.
  34. x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
  35. y = torch.sin(x)
  36. # Create random Tensors for weights. For this example, we need
  37. # 4 weights: y = a + b * P3(c + d * x), these weights need to be initialized
  38. # not too far from the correct result to ensure convergence.
  39. # Setting requires_grad=True indicates that we want to compute gradients with
  40. # respect to these Tensors during the backward pass.
  41. a = torch.full((), 0.0, device=device, dtype=dtype, requires_grad=True)
  42. b = torch.full((), -1.0, device=device, dtype=dtype, requires_grad=True)
  43. c = torch.full((), 0.0, device=device, dtype=dtype, requires_grad=True)
  44. d = torch.full((), 0.3, device=device, dtype=dtype, requires_grad=True)
  45. learning_rate = 5e-6
  46. for t in range(2000):
  47. # To apply our Function, we use Function.apply method. We alias this as 'P3'.
  48. P3 = LegendrePolynomial3.apply
  49. # Forward pass: compute predicted y using operations; we compute
  50. # P3 using our custom autograd operation.
  51. y_pred = a + b * P3(c + d * x)
  52. # Compute and print loss
  53. loss = (y_pred - y).pow(2).sum()
  54. if t % 100 == 99:
  55. print(t, loss.item())
  56. # Use autograd to compute the backward pass.
  57. loss.backward()
  58. # Update weights using gradient descent
  59. with torch.no_grad():
  60. a -= learning_rate * a.grad
  61. b -= learning_rate * b.grad
  62. c -= learning_rate * c.grad
  63. d -= learning_rate * d.grad
  64. # Manually zero the gradients after updating weights
  65. a.grad = None
  66. b.grad = None
  67. c.grad = None
  68. d.grad = None
  69. print(f'Result: y = {a.item()} + {b.item()} * P3({c.item()} + {d.item()} x)')

脚本的总运行时间:(0 分钟 0.000 秒)

下载 Python 源码:polynomial_custom_function.py

下载 Jupyter 笔记本:polynomial_custom_function.ipynb