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

深度学习中的autograd与jacobian

1. autograd

对于一个很简单的例子,如下图所示,对于一个神经元z,接收数据x作为输入,经过\sigma激活函数,获得激活后的结果,最后利用损失函数L获得损失,然后梯度反向回传。

 上图右侧即梯度反向回传的过程,其中字母上加一条线代表损失函数对该参数的偏导

  1. 损失函数L对自己的偏导为0
  2. 损失函数对y的偏导为\bar{y} = \bar{L}\cdot (y-t) = y-t
  3. 损失函数对z的偏导为\bar{z} = \bar{y}\cdot {\sigma }'(z)
  4. 损失函数对w的偏导为\bar{w} = \bar{z}\cdot x
  5. 损失函数对b的偏导为\bar{b} = \bar{z}\cdot 1 = \bar{z}

在实际使用中我们会将复杂的操作分解成若干个简单操作:

1.1 标量 梯度反向回传

以下是pytorch官网的一个小示例:

import torch

x = torch.ones(5)  # input tensor
y = torch.zeros(3)  # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)

loss.backward()  # 这里需要注意,只有标量才能直接调用,如果loss是一个张量的话需要在backward()中传入一个向量,且这个向量和loss的shape必须一样,一般而言向量元素全为1

print(w.grad)

print(b.grad)

 

 1.2 张量 梯度反向回传

inp = torch.eye(4, 5, requires_grad=True)  # 创建一个对角矩阵,shape: [4, 5]
out = (inp+1).pow(2).t()  # 矩阵元素加1,然后平方,再转置,shape: [5, 4]
out.backward(torch.ones_like(out), retain_graph=True)  # 梯度反向回传,并且设置了保留梯度,可以多次调用,这个例子中out是一个shape: [5,4] 的张量,因此在backward中传入了一个shape:[5, 4] 的全1矩阵。
print(f"First call\n{inp.grad}")
out.backward(torch.ones_like(out), retain_graph=True)  # 第二次调用,由于梯度未清零,因此会叠加
print(f"\nSecond call\n{inp.grad}")
inp.grad.zero_()  # 梯度清零
out.backward(torch.ones_like(out), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")

First call
tensor([[4., 2., 2., 2., 2.],
        [2., 4., 2., 2., 2.],
        [2., 2., 4., 2., 2.],
        [2., 2., 2., 4., 2.]])

Second call
tensor([[8., 4., 4., 4., 4.],
        [4., 8., 4., 4., 4.],
        [4., 4., 8., 4., 4.],
        [4., 4., 4., 8., 4.]])

Call after zeroing gradients
tensor([[4., 2., 2., 2., 2.],
        [2., 4., 2., 2., 2.],
        [2., 2., 4., 2., 2.],
        [2., 2., 2., 4., 2.]])

 

2. 向量与张量的jarobian 矩阵计算

from torch.autograd.functional import jacobian
import torchdef func(x):return x.exp().sum(dim=1)x = torch.rand(2,3)
print(jacobian(func, x))

经过func之后的x由原来的shape: [2, 3] 变为了shape: [2],而jacobian计算的过程是shape: [2]中的每个元素,对shape: [2, 3]中的每个元素求偏导,结果中为0的元素,代表func返回的结果中的第一个元素与x中第二行没关系,func返回的结果中的第二个元素与x中第一行没关系。

tensor([[[1.0939, 2.4570, 1.3270],
         [0.0000, 0.0000, 0.0000]],

        [[0.0000, 0.0000, 0.0000],
         [1.3719, 1.8973, 1.8708]]])

torch.manual_seed(5)
a = torch.randn(3)
print(a)
def func2(x):return a+x
x = torch.rand(3)
print(jacobian(func2, x))

 tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]])

 其他的示例懒得写了,代码放在这,有兴趣的可以自己看看,拷贝下来之后,把日志部分删掉或者改成print就可以跑了。

'''
1.讲解jarcobin矩阵
2.讲解向量和矩阵的梯度求解
'''
from torch.autograd.functional import jacobian
import torch
import loggerlogger1 = logger.logger_(__file__)def func(x):return x.exp().sum(dim=1)x1 = torch.rand(2,3, requires_grad=True)
print(jacobian(func, x1))'''经过func之后的x由原来的shape: [2, 3] 变为了shape: [2],
而jacobian计算的过程是shape: [2]中的每个元素,对shape: [2, 3]中的每个元素求偏导,
结果中为0的元素,代表func返回的结果中的第一个元素与x中第二行没关系,
func返回的结果中的第二个元素与x中第一行没关系。'''
torch.manual_seed(5)
a = torch.randn(3)
print(a)
def func2(x):return a+x
x2 = torch.rand(3)
print(jacobian(func2, x2))#- 利用jacobian矩阵与某个全1的矩阵相乘,获得与反向回传相同的结果
def func(x):return x.exp().sum(dim=1)x1 = torch.rand(2,3, requires_grad=True)
print(jacobian(func, x1))y = func(x1)
y.backward(torch.ones_like(y))  # 这里为什么要加一个torch.ones_like(y)呢?
# 其实可以理解为Loss就是y,即loss = func(x1), Loss对Loss本身求偏导,那自然是全1,然后再对x求偏导,得到x' = loss'× func'(x1)
print(x1.grad)logger1.info(torch.ones_like(y) @ jacobian(func, x1))a = torch.randn(2, 3, requires_grad=True)
b = torch.randn(3, 3, requires_grad=True)
print(a)
print(b)
y = a @ b
y.backward(torch.ones_like(y))
logger1.info(f'a.grad is : {a.grad}')
logger1.info(f'b.grad is : {b.grad}')def func_a(a):return a @ b
def func_b(b):return a @ b
jacobian_a0 = jacobian(func_a, a[0])
jacobian_a1 = jacobian(func_a, a[1])
logger1.info(f'jacobian_a0 is : {jacobian_a0}')
logger1.info(f'jacobian_a1 is : {jacobian_a1}')
loss_jacobian_a0 = torch.ones_like(func_a(a[0])) @ jacobian_a0
loss_jacobian_a1 = torch.ones_like(func_a(a[1])) @ jacobian_a1
logger1.info(f'loss_jacobian_a0 is : {loss_jacobian_a0}')
logger1.info(f'loss_jacobian_a1 is : {loss_jacobian_a1}')jacobian_b0 = jacobian(func_b, b[:, 0])
jacobian_b1 = jacobian(func_b, b[:, 1])
jacobian_b2 = jacobian(func_b, b[:, 2])
logger1.info(f'jacobian_b0 is : {jacobian_b0}')
logger1.info(f'jacobian_b1 is : {jacobian_b1}')
logger1.info(f'jacobian_b2 is : {jacobian_b2}')
loss_jacobian_b0 = torch.ones_like(func_b(b[:, 0])) @ jacobian_b0
loss_jacobian_b1 = torch.ones_like(func_b(b[:, 1])) @ jacobian_b1
loss_jacobian_b2 = torch.ones_like(func_b(b[:, 2])) @ jacobian_b2
logger1.info(f'loss_jacobian_b0 is : {loss_jacobian_b0}')
logger1.info(f'loss_jacobian_b1 is : {loss_jacobian_b1}')
logger1.info(f'loss_jacobian_b2 is : {loss_jacobian_b2}')

相关文章:

  • 分布式id的两大门派!时钟回拨问题的解决方案!
  • Redisson分布式锁的Key设计之道:确保业务高可靠与一致性
  • very_easy_sql(SSRF+SQL注入)
  • 中科固源:蓝牙协议栈架构与核心协议深度剖析
  • 数据库同步方案:构建企业数据流通的高速通道
  • SQL Server 中的 GO 及其与其他数据库的对比
  • 正则表达式非捕获分组?:
  • AI训练服务器概述
  • 混合云安全实战:如何构建稳固的云安全防线?
  • 【ARM AMBA AHB 入门 3 -- AHB 总线介绍】
  • 数字康养新范式:七彩喜平台重构智慧养老生态的深度实践
  • 欧姆龙 PLC串口转网口模块cjcp系列SG-CJCP-110
  • 浅谈广告投放从业者底层思维逻辑
  • 结构体的学习
  • eclipse开发环境中缺少JavaEE组件如何安装
  • shell操作文件上传
  • 第十节:图像处理基础-图像算术运算 (加法、减法、混合)
  • C++ 静态成员
  • void*在c语言中什么意思(非常详细)
  • 【MVCP】基于解纠缠表示学习和跨模态-上下文关联挖掘的多模态情感分析
  • 广西百色通报:极端强对流天气致墙体倒塌,3人遇难7人受伤
  • 广西钦州:坚决拥护自治区党委对钟恒钦进行审查调查的决定
  • 习近平会见委内瑞拉总统马杜罗
  • 玉渊谭天丨中方为何此时同意与美方接触?出于这三个考虑
  • 马上评丨维护学术诚信别陷入“唯AI检测”误区
  • 国博馆刊|北朝至唐初夏州酋豪李氏家族的发展与身份记忆