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

深度学习3

五、自动微分

1、基础概念

        模块 autograd  负责自动计算张量操作的梯度,具有自动求导功能;autograd   创建一个动态计算图来跟踪张量的操作,每个张量是计算图中的一个节点,节点之间的操作构成图的边。  

        属性 requires_grad 决定是否对张量进行梯度计算,默认不进行。

        方法 backward 进行反向传播,计算张量梯度。

        tensor.grad 返回梯度值

2、计算梯度

        元素必须为浮点数类型

2.1、标量

# 张量的梯度计算
import torch
x = torch.tensor(1.0,requires_grad = True)
y = x**2 +2*x +3
y.backward() # 梯度计算,(1,求y的导数;2、将标量带入导数函数求值)
# x.grad 表示求导带入值结果
print(x.grad)
import torch
# 多标量的梯度计算
x1 = torch.tensor(1., requires_grad=True)
x2 = torch.tensor(2., requires_grad=True)
y = x1**2 + 3*x2 +5
y.backward()
print(x1.grad)
print(x2.grad)

 2.2、向量

        损失函数接收向量后,需要进行整合称为一个元素(一半使用sum)才能进行反向传播。

反向传播后自动拆分为不同元素值的结果。

# 向量的梯度计算
import torch
x = torch.tensor([1.0,2.0,3.0],requires_grad = True)
y = x**2 +2*x +5
print(y)
y = y.sum()
print(y)
y.backward()
print(x.grad)
import torch
# 多向量的梯度计算
x1 = torch.tensor([1.,2.], requires_grad=True)
x2 = torch.tensor([2.,5.], requires_grad=True)
y = x1**2 + 3*x2 +5
y1 = y.sum()
y1.backward()
print(x1.grad)
print(x2.grad)
import torch
# 多向量的梯度计算
x1 = torch.tensor([1.,2.], requires_grad=True)
x2 = torch.tensor([2.,5.], requires_grad=True)
y = x1**2 + 3*x2 +5
y2 = y.mean()
y2.backward()
print(x1.grad)
print(x2.grad)

2.3、矩阵

# 矩阵的梯度计算
import torch
x1 = torch.tensor([[1.,2.],[3.,4.]], requires_grad=True)
y = x1**2 + 3*x1 +5
y2 = y.sum()
y2.backward()
print(x1.grad)
# 多矩阵的梯度计算
import torch
x1 = torch.tensor([[1.,2.],[3.,4.]], requires_grad=True)
x2 = torch.tensor([[11.,2.],[1.,22.]], requires_grad=True)
y = x1**2 + 3*x2 +5
y2 = y.sum()
y2.backward()
print(x1.grad)
print(x2.grad)

3、梯度控制

        由于 autograd   自动计算梯度,也就是在每个损失函数操作时都会自动运行,浪费资源,所以在无需求导的损失函数时,可以进行关闭求导功能。

3.1、全局控制

        创建tensor时,默认 requires_grad 等于 False;set_grad_enabled(False)

# 全局控制
import torch
x = torch.tensor(3.0,requires_grad = False)
y = x**2 +2*x +3
try:
    y.backward() 
    print(x.grad)
except:
    print("操作报错")

x = torch.tensor(3.0,requires_grad = True)
y = x**2 +2*x +3
torch.set_grad_enabled(False)
try:
    y.backward() 
    print(x.grad)
except:
    print("操作报错")

3.2、with进行上下文管理

        with torch.no_grad():在这个代码块内创建的损失函数,不会求导

# with 控制
import torch
x = torch.tensor(3.0,requires_grad = True)
with torch.no_grad():
    y = x**2 +2*x +3
try:
    y.backward() 
    print(x.grad)
except:
    print("操作报错")

3.3、装饰器函数控制

        将with torch.no_grad() 封装到函数,其他函数需要控制计算时候,装饰这个函数即可。

# 装饰器控制
import torch

x = torch.tensor(3.0,requires_grad = True)

def zsq(func):
    def wrapper(*args):
        with torch.no_grad():
            return func(*args)
    return wrapper

@zsq  
def fun():
    y = x**2 +2*x +3
    try:
        y.backward() 
        print(x.grad)
    except:
        print("操作报错")
    
fun() # 调用函数

4、梯度清零

        在多个损失函数反向传播或重复反向传播情况下,梯度值将累计以和的形式返回结果

# 累计梯度
import torch
# 多个损失函数反向传播
x =torch.tensor(4.0,requires_grad=True)

y = 2*x**2 +7 # 第一个损失函数
y.backward() 
print(x.grad)  # 导数结果为 16.

z = x**2  # 第二个损失函数
z.backward()
print(x.grad) # 导数结果为 8.   累加就是24.
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

         当进行梯度计算时,无法直观反应某次梯度的值,所以需要梯度清零:grad.zero_(),需要梯度存在后才可以使用清零,否则获取梯度为None,清零会报错,清零时将元素值变成0.,不会变成None

# 梯度清理
import torch
x =torch.tensor(4.0,requires_grad=True)
y = 2*x**2 +7
try:
    x.grad.zero_()
except:
    print("梯度为None,不能清零")
y.backward() # 反向传播
print(x.grad)

z = x**2
z.backward() 
print(x.grad)

x.grad.zero_()  # 梯度清理
print(x.grad is None)
print(x.grad)
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

5、梯度下降算法结合

import torch
w = torch.tensor(5., requires_grad=True) # 初始化 w

num =0

while True: 
    num+=1
    
    if num > 50: 
        break
    
    # 创建损失函数
    loss = w**2

    a=0

    # 梯度清零
    if w.grad is None: 
        pass 
    else: 
        a = w.grad.data
        w.grad.zero_()

    # 方向传播
    loss.backward()

    b = w.grad.data

    if (b>a and a!=0) or b ==0:
        break

    # 当前斜率
    print("斜率:\n",w.grad)

    w.data = w.data - 0.4*w.grad

    # 当前斜率
    print("更新的横坐标:\n",w.data)
    # 当前斜率
    print("----------",num)
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

6、叶子节点

        当一个tensor设置为可以求导,那么其性质变换, 与普通tensor有区别,对数据操作时需要索引出一个只有其数据的普通tensor

        叶子节点 detach() ,将tensor的数据创建为新的tensor,两者内存不一样,数据共享,这时候可以对新的tensor数据操作。

import torch
x= torch.tensor([1., 2., 3.], requires_grad=True)

try:
    x2 = x.numpy() 
    # 如果x是一个可以求导的张量,那么它就不能直接当作普通tensor使用
    print(x2)
except :
    print("转化错误")

try:
    x3 = x.detach()
    # 取出叶子节点
    print(x3)
    print(x)
    x2 = x3.numpy()  # 取出叶子节点后就可以转numpy了
    print(x2)
except :
    pass


http://www.kler.cn/a/410433.html

相关文章:

  • JVM-类文件结构
  • Apollo9.0源码部署(Nvidia显卡)
  • React(六)——Redux
  • linux从0到1——shell编程9
  • 从零开始学习数据库 day0(基础)
  • QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
  • 论文笔记 网络安全图谱以及溯源算法
  • JavaScript的基础数据类型
  • 241124_基于MindSpore学习Prompt Tuning
  • 【数据分析】基于GEE实现大津算法提取洞庭湖流域水体
  • 手机无法连接服务器1302什么意思?
  • 前端预览pdf文件流
  • 【cocos creator】下拉框
  • Windows系统电脑安装TightVNC服务端结合内网穿透实现异地远程桌面
  • kafka学习-01
  • Unity 2020、2021、2022、2023、6000下载安装
  • 【测试工具JMeter篇】JMeter性能测试入门级教程(一)出炉,测试君请各位收藏了!!!
  • 2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略 完整参考论文(1)
  • [算法] 前缀函数与KMP算法
  • 数据集-目标检测系列- 荷花 莲花 检测数据集 lotus>> DataBall
  • LeetCode 0632.最小区间:优先队列
  • 成功案例 | Fortinet助力宾堡打造数字化安全“美味王国”
  • java TreeMap 详解
  • 【GAMES101笔记速查——Lecture 19 Cameras,Lenses and Light Fields】
  • C# .Net Core通过StreamLoad向Doris写入CSV数据
  • C# 创建快捷方式文件和硬链接文件