Py学习  »  机器学习算法

动手学习深度学习 | 2 预备知识-2.5 自动微分

GIS研发 • 1 月前 • 64 次点击  
2.5.1 一个简单的例子
2.5.2 非标量变量的反向传播
2.5.3 分离计算
2.5.4 Python控制流的梯度计算

https://www.bilibili.com/video/BV1CueXzdEmy?vd_source=2d1af2a9b2aa8124af12180f29fb55f6&spm_id_from=333.788.player.switch&p=17

补充:

1. 标量的反向传播
import numpy as np import torch 
# f(x) = a*x**2 + b*x + c的导数
# 创建需要求导的张量,requires_grad=True表示需要计算梯度x = torch.tensor(0.0, requires_grad=True)  # x需要被求导
# 创建常数张量(不需要求导,默认requires_grad=False)a = torch.tensor(1.0)b = torch.tensor(-2.0)c = torch.tensor(1.0)
# 定义函数 y = ax² + bx + cy = a*torch.pow(x,2) + b*x + c 
# 反向传播,计算梯度y.backward()
# 获取x的梯度值(即dy/dx在x=0处的值)dy_dx = x.gradprint(dy_dx)

数学原理

函数 f(x) = x² - 2x + 1 的导数是:

  • f'(x) = 2x - 2

当 x = 0 时:

  • f'(0) = 2×0 - 2 = -2

因此输出 tensor(-2.) 正确。

PyTorch自动求导机制

  1. 计算图构建:PyTorch会动态构建一个计算图,记录所有运算

  2. requires_grad=True:标记需要计算梯度的张量

  3. backward():自动计算所有requires_grad张量的梯度

  4. x.grad:存储计算得到的梯度值


2. 非标量的反向传播

import numpy as np import torch 
# f(x) = a*x**2 + b*x + c
x = torch.tensor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导a = torch.tensor(1.0)b = torch.tensor(-2.0)c = torch.tensor(1.0)y = a*torch.pow(x,2) + b*x + c 
gradient = torch.tensor([[1.0,1.0],[1.0,1.0]])
print("x:\n",x)print("y:\n",y)y.backward(gradient = gradient)x_grad = x.gradprint("x_grad:\n",x_grad)

输出:x: tensor([[0., 0.],         [1., 2.]], requires_grad=True)y: tensor([[1., 1.],        [0., 1.]], grad_fn=)x_grad: tensor([[-2., -2.],        [ 0.,  2.]])

1.计算过程

x = [[00],     [12]]

2. 函数 f(x) = x² - 2x + 1 的计算

对每个元素应用函数:

  • f(0) = 0² - 2×0 + 1 = 1

  • f(0) = 1

  • f(1) = 1² - 2×1 + 1 = 0

  • f(2) = 2² - 2×2 + 1 = 1

所以输出y

y = [[11],     [01]]

3. 导数 f'(x) = 2x - 2

对每个位置计算导数:

  • f'(0) = -2

  • f'(0) = -2

  • f'(1) = 0

  • f'(2) = 2

关键点:gradient参数

当输出不是标量时,需要传入一个与输出y形状相同的gradient参数作为"权重":

gradient = torch.tensor([[1.01.0], [1.0, 1.0]])
这相当于计算:
y.backward(gradient) = sum(y * gradient) 的梯度

实际计算过程

实际上计算的是:
loss = y[0,0]*1 + y[0,1]*1 + y[1,0]*1 + y[1,1]*1gradient = d(loss)/dx
于gradient全为1,最终x.grad就是每个位置的导数:
x_grad = [[f'(0), f'(0)],           [f'(1), f'(2)]] = [[-2, -2], [02]]

数学验证

  • 位置[0,0]: x=0, f'(0) = -2 ✓

  • 位置[0,1]: x=0, f'(0) = -2 ✓

  • 位置[1,0]: x=1, f'(1) = 0 ✓

  • 位置[1,1]: x=2, f'(2) = 2 ✓

3.非标量的反向传播可以用标量的反向传播实现
import numpy as np import torch 
# f(x) = a*x**2 + b*x + c
x = torch.tensor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导a = torch.tensor(1.0)b = torch.tensor(-2.0)c = torch.tensor(1.0)y = a*torch.pow(x,2) + b*x + c 
gradient = torch.tensor([[1.0,1.0],[1.0,1.0]])z = torch.sum(y*gradient)
print("x:",x)print("y:",y)z.backward()x_grad = x.gradprint("x_grad:\n",x_grad)

输出:x: tensor([[0., 0.],        [1., 2.]], requires_grad=True)y: tensor([[1., 1.],        [0., 1.]], grad_fn=)x_grad: tensor([[-2., -2.],        [ 0.,  2.]])
参考:https://download.csdn.net/blog/column/9886176/108303645
动手学习深度学习 | 2 预备知识-2.4 微积分
动手学习深度学习 | 2 预备知识-2.3 线性代数
动手学习深度学习 | 2 预备知识-2.1 数据操作 2.2 数据预处理
动手学习深度学习 | 安装

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/193183