当前位置: 首页 > news >正文

10、PyTorch autograd使用教程

文章目录

  • 1. 相关思考
  • 2. 矩阵求导
  • 3. 两种方法求jacobian

1. 相关思考

在这里插入图片描述

2. 矩阵求导

假设我们有如下向量:
y 1 × 3 = x 1 × 5 [ w T ] 5 × 3 + b 1 × 3 \begin{equation} y_{1\times3}=x_{1\times5}[w^T]_{5\times3}+b_{1\times3} \end{equation} y1×3=x1×5[wT]5×3+b1×3
根据公式,我们知道偏导如下:
∂ y ∂ w = x , ∂ y ∂ b = 1 \begin{equation} \frac{\partial{y}}{\partial w}=x,\frac{\partial{y}}{\partial b}=1 \end{equation} wy=x,by=1
但通过公式我们知道,y为向量,在pytorch中一般都是标量后再进行反向传播,故我们需要引入求和公式
z = y T m , m = [ 1 1 1 ] \begin{equation} z=y^Tm,m=\begin{bmatrix}1\\\\1\\\\1\end{bmatrix} \end{equation} z=yTm,m= 111

  • 那么z就是可以当作标量,可以用z做反向传播
    ∂ z ∂ y = m \begin{equation} \frac{\partial{z}}{\partial y}=m \end{equation} yz=m
  • 由链式法则可得如下:
    ∂ z ∂ w = ∂ z ∂ y ⋅ ∂ y ∂ w = m ⋅ x \begin{equation} \frac{\partial{z}}{\partial w}=\frac{\partial{z}}{\partial y}\cdot\frac{\partial{y}}{\partial w}=m\cdot x \end{equation} wz=yzwy=mx
  • 我们定义x=[0,1,2,3,4],那么梯度可得:
    ∂ z ∂ w = [ 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 ] \begin{equation} \frac{\partial{z}}{\partial w}= \begin{bmatrix} 0&1&2&3&4\\\\ 0&1&2&3&4\\\\ 0&1&2&3&4 \end{bmatrix} \end{equation} wz= 000111222333444
  • 同理:可得关于b的导数如下:
    ∂ z ∂ b = ∂ z ∂ y ⋅ ∂ y ∂ b = m = [ 1 1 1 ] \begin{equation} \frac{\partial{z}}{\partial b}=\frac{\partial{z}}{\partial y}\cdot\frac{\partial{y}}{\partial b}=m=\begin{bmatrix} 1\\\\ 1\\\\ 1 \end{bmatrix} \end{equation} bz=yzby=m= 111
  • 小结:如果要计算向量y对向量w进行求导,但pytorch的反向传播用的是标量,一般做法是引入全1向量求和,这样就将向量y对向量w的求导转换成z对w的求导,最后运用链式法则即可求出。
  • python 代码
import torch
from torch import nnif __name__ == "__main__":run_code = 0in_x = torch.arange(5,dtype=torch.float)in_w = torch.randn((3, 5), requires_grad=True)in_b = torch.arange(3, dtype=torch.float, requires_grad=True)y = in_x @ in_w.T + in_bz = torch.sum(y)print(f"*"*50)print(f"before:")print(f"x={in_x}")print(f"w=\n{in_w}")print(f"w_grad=\n{in_w.grad}")print(f"b=\n{in_b}")print(f"b_grad=\n{in_b.grad}")print(f"y={y}")print(f"before:")print(f"*"*50)z.backward()print(f"*"*50)print(f"after:")print(f"x={in_x}")print(f"w=\n{in_w}")print(f"w_grad=\n{in_w.grad}")print(f"b=\n{in_b}")print(f"b_grad=\n{in_b.grad}")print(f"b_grad=\n{in_b.grad.shape}")print(f"y={y}")print(f"after:")print(f"*"*50)
  • 结果:
**************************************************
before:
x=tensor([0., 1., 2., 3., 4.])
w=
tensor([[-1.5762, -0.0040,  1.7958,  0.2164,  0.7108],[ 0.6488, -0.8668,  0.0572, -1.1207,  0.0568],[-0.5594,  0.1091,  0.6546,  0.0851,  1.1287]], requires_grad=True)
w_grad=
None
b=
tensor([0., 1., 2.], requires_grad=True)
b_grad=
None
y=tensor([ 7.0800, -2.8872,  8.1886], grad_fn=<AddBackward0>)
before:
**************************************************
**************************************************
after:
x=tensor([0., 1., 2., 3., 4.])
w=
tensor([[-1.5762, -0.0040,  1.7958,  0.2164,  0.7108],[ 0.6488, -0.8668,  0.0572, -1.1207,  0.0568],[-0.5594,  0.1091,  0.6546,  0.0851,  1.1287]], requires_grad=True)
w_grad=
tensor([[0., 1., 2., 3., 4.],[0., 1., 2., 3., 4.],[0., 1., 2., 3., 4.]])
b=
tensor([0., 1., 2.], requires_grad=True)
b_grad=
tensor([1., 1., 1.])
b_grad=
torch.Size([3])
y=tensor([ 7.0800, -2.8872,  8.1886], grad_fn=<AddBackward0>)
after:
**************************************************

3. 两种方法求jacobian

  • 方法一:直接使用 from torch.autograd.functional import jacobian
  • 方法二:将f(x)的向量按照每个元素是标量的方式,对每个标量进行反向传播,最后将结果叠加起来。
import torch
from torch.autograd.functional import jacobian# 定义函数 f(x)
def funx(x):return torch.stack([x[0] ** 2 + 2 * x[1],3 * x[0] + 4 * x[1] ** 2])if __name__ == "__main__":# 初始化输入张量并启用梯度in_x = torch.tensor([1.0, 2.0], dtype=torch.float, requires_grad=True)# 计算函数输出y = funx(in_x)# 初始化一个零矩阵,用于保存手动计算的雅可比矩阵manual_jacobian = torch.zeros(len(y), len(in_x))# 手动计算雅可比矩阵for i in range(len(y)):# 每次 backward 计算一个分量的梯度in_x.grad = None  # 清除之前的梯度y[i].backward(retain_graph=True)manual_jacobian[i] = in_x.grad# 使用 autograd.functional.jacobian 验证雅可比auto_jacobian = jacobian(funx, in_x)print(f"Manual Jacobian:\n{manual_jacobian}")print(f"Auto Jacobian:\n{auto_jacobian}")
  • 结果:
Manual Jacobian:
tensor([[ 2.,  2.],[ 3., 16.]])
Auto Jacobian:
tensor([[ 2.,  2.],[ 3., 16.]])

http://www.mrgr.cn/news/78023.html

相关文章:

  • 详细教程-Linux上安装单机版的Hadoop
  • URL在线编码解码- 加菲工具
  • 【君正T31开发记录】8.了解rtsp协议及设计模式
  • 量子感知机
  • opencv进行rtsp推流
  • 数据结构:链表进阶
  • 生成对抗网络模拟缺失数据,辅助PAMAP2数据集仿真实验
  • 手机发展史介绍
  • 韩顺平 一周学会Linux | Linux 实操篇-实用指令
  • 卡达掐发展史
  • 【Pytest+Yaml+Allure】实现接口自动化测试框架
  • Java基础-内部类与异常处理
  • openssl颁发包含主题替代名的证书–SAN
  • skywalking es查询整理
  • Java基础-Java多线程机制
  • Java基础-I/O流
  • Java基础-组件及事件处理(下)
  • Java基础-Java中的常用类(上)
  • openssl创建自签名证书
  • Linux 正则表达式(basic and extened)
  • Linux笔记---进程:进程切换与O(1)调度算法
  • 懂微百择唯供应链RankingGoodsList2存在SQL注入漏洞
  • PIMPL模式和D指针
  • C语言:深入理解指针
  • MPI 直接传递 GPU buffer 数据的原理——调试 libmpi.so from MPI with-cuda
  • 《Spring 实战:小型项目开发初体验》