【PyTorch】第二节:梯度的求解

news2024/10/6 18:32:23

作者🕵️‍♂️:让机器理解语言か

专栏🎇:PyTorch

描述🎨:PyTorch 是一个基于 Torch 的 Python 开源机器学习库。

寄语💓:🐾没有白走的路,每一步都算数!🐾 

介绍

        本实验首先讲解了梯度的定义和求解方式,然后引入 PyTorch 中的相关函数,完成了张量的梯度定义、梯度计算、梯度清空以及关闭梯度等操作。

知识点🍉

  • 🍓张量的属性
  • 🍓计算图
  • 🍓梯度的计算

梯度计算

张量的梯度计算

        在一元函数中,某点的梯度表示的就是某点的导数。在多元函数中某点的梯度表示的是,由每个自变量所对应的偏导值所组成的向量。如 f(x,y,z) 的梯度向量就是(\frac{\partial f}{\partial x},\frac{\partial f}{\partial y},\frac{\partial f}{\partial z})

梯度的方向就是函数值上升最快的方向🚀。

requires_grad=True 对指定变量求取偏导

        我们一般可以使用 torch.autograd.backward() 来自动计算变量的梯度,该函数会对指定的变量进行偏导的求取。为了辨别函数中哪些变量需要求偏导,哪些不需要求偏导,我们一般会在定义张量时,加上 requires_grad=True,表示该变量可以求偏导

import torch
x = torch.randn(1, requires_grad=True)
y = torch.randn(1)
z = torch.randn(1)
f1 = 2*x+y
f2 = y+z
# 查看变量是否存在求梯度函数
print(f1.grad_fn)
print(f2.grad_fn)
# <AddBackward0 object at 0x7faf5a2f2b50>
# None

        从结果可以看出, x 被定义成可以求偏导的变量,因此,它所对应的变量 f1 就是可求导的(通过 torch.grad_fn 查看)。

✅background() 获取函数的梯度、x.grad展示偏导的值

        接下来让我利用 f1.backward() 求取 f1 的梯度(即所有变量的偏导),然后利用 x.grad 展示 \frac{\partial f_1}{\partial x}​​ 的值。

f1.backward()
print(x.grad)  # df1/dx
# tensor([2.])

        当然除了上面简单的一元函数求偏导外,我们还可以使用上面的方法来求取复合函数的偏导

x = torch.randn(3, requires_grad=True)  # x 中存了三个变量 x1,x2,x3 
# tensor([-1.0625, -1.6651, -0.8413], requires_grad=True)
y = x + 2
# tensor([0.9375, 0.3349, 1.1587], grad_fn=<AddBackward0>)
z = y * y * 3
# tensor([2.6368, 0.3364, 4.0280], grad_fn=<MulBackward0>)
z = z.mean()
print(z)  # tensor(2.3338, grad_fn=<MeanBackward0>)
print(z.grad_fn)    # <MeanBackward0 object at 0x7faf54282b50>
# <MeanBackward0 object at 0x7faf542dfe50>

验证:

        根据上面代码可知,我们定义了一个 z 关于变量 x 的多元复合函数,如下:

y = x+2

z = \frac{1}{n}\sum_{i=1}^n 3y_i^2

我们手动计算一下 z 关于 x 的偏导数。首先我们将 z 进行展开。

z = \frac{1}{n}\sum_{i=1}^n 3y_i^2=\frac{1}{3}(3y_{1}^2+3y_{2}^2+3y_{3}^2)

特别的,我们计算 z 对于 x_{1}的偏导,\frac{\partial z}{\partial x_{1}} = \frac{\partial z}{\partial y_{1}} \cdot \frac{\partial y_{1}}{\partial x_{1}},其他的计算类似。

首先计算 \frac{\partial z}{\partial y_{1}}

\frac{\partial z}{\partial y_{1}} = \frac{1}{3}*3*2*y_{1}=2y_{1}

接着计算\frac{\partial y_{1}}{\partial x_{1}}为:

\frac{\partial y_{1}}{\partial x_{1}} = 1

所以最终 \frac{\partial z}{\partial x_{1}} 为:

\frac{\partial z}{\partial x_{1}} = \frac{\partial z}{\partial y_{1}} \cdot \frac{\partial y_{1}}{\partial x_{1}} = 2y_{1}=2(x_{1}+2)

        我们也可以使用 z.backward() 求取梯度,该张量的梯度结果会被放在所对应变量的 grad 属性中。下面我们比较一下通过 z.backward() 求取梯度和我们上面推导出的结果是否一样。

z.backward()
print(x.grad)  # dz/dx = dz/d(x+2) = dz/dy
# tensor([1.8750, 0.6698, 2.3175])

print(2*(x+2)) # 比较直接计算的结果
# tensor([1.8750, 0.6698, 2.3175], grad_fn=<MulBackward0>)

        上面结果为函数 z 的梯度向量,即函数 z 分别关于x_1,x_2,x_3 的偏导数。

✅background( )参数:grad_variables

        简单的说, torch.autograd.backward 就是使用链式法则对变量的偏导进行了求解。该函数有一个参数 grad_variables,该参数相当于给原梯度进行了一个加权

如果使用函数 k.backward(p) 则得到的的变量 x.grad 的值为:

x.grad=p\cdot \frac{dk}{dx}

x = torch.randn(3, requires_grad=True)

k = x * 2
for _ in range(10):
    k = k * 2        # 最后得到  k = 2^11 * x = 2048 * x

print(k)  # tensor([-736.0573, 1320.2373, -650.0005], grad_fn=<MulBackward0>)
print(k.shape)  # torch.Size([3])
p = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float32)

k.backward(p)
print(x.grad) # tensor([2.0480e+02, 2.0480e+03, 2.0480e-01])

停止张量的梯度计算🚫

如果我们不需要某些张量的梯度计算,我们就可以使用下面三种方法告诉计算机停止梯度的计算:

  • x.requires_grad_(False)
  • x.detach()
  • with torch.no_grad():

下面举例展示一下三种方法如何使用:

  • 🌿x.requires_grad_(False)就地更改现有标志

a = torch.randn(2, 2, requires_grad=True)
b = ((a * 3) / (a - 1))
print(b.grad_fn)  # 此时可偏导,求取梯度的函数存在
a.requires_grad_(False)
b = ((a * 3) / (a - 1))
print(b.grad_fn)  # 此时不可偏导了,求取梯度的函数不存在了
# <DivBackward0 object at 0x7faf54282310>
# None
  •  🌿x.detach() 获取具有相同内容但不能进行梯度计算的新张量

a = torch.randn(2, 2, requires_grad=True)
b = a.detach()
print(a.requires_grad)
print(b.requires_grad)
# True
# False
  • 🌿with torch.no_grad() 在该作用域中定义的都是不进行梯度计算的张量

a = torch.randn(2, 2, requires_grad=True)
print((a ** 2).requires_grad)
with torch.no_grad():  # 该作用域下定义的都是不进行梯度计算的张量
    print((a ** 2).requires_grad)
# True
# False

梯度的清空💨

        在 PyTorch 中,如果我们利用 torch.autograd.backward 求取张量的梯度时。但是,如果我们多次运行该函数,该函数会将计算得到的梯度累加起来,如下所示:

x = torch.ones(4, requires_grad=True)
y = (2*x+1).sum()
z = (2*x).sum()
y.backward()
print("第一次偏导:", x.grad)  # dy/dx
z.backward()
print("第二次偏导:", x.grad)  # dy/dx+dz/dx
# 第一次偏导: tensor([2., 2., 2., 2.])
# 第二次偏导: tensor([4., 4., 4., 4.])

        从上面的结果可以看到,如果我们对张量 y 和 z 分别求梯度,那么它们关于 x 的偏导都会被放入 x.grad 中,形成累加的局面。

        为了避免这种情况,一般我们在计算完梯度后,都会清空梯度,即清空 x.grad 。在清空梯度后,我们再进行其他张量的梯度求解。

我们可以使用 x.grad.zero_() 清空梯度

x = torch.ones(4, requires_grad=True)
y = (2*x+1).sum()
z = (2*x).sum()
y.backward()
print("第一次偏导:", x.grad)  # dy/dx
x.grad.zero_()
z.backward()
print("第二次偏导:", x.grad)  # dz/dx
# 第一次偏导: tensor([2., 2., 2., 2.])
# 第二次偏导: tensor([2., 2., 2., 2.])

        这个性质是非常重要的,特别是在后面我们将要学到的梯度下降算法之中。

        因为我们训练模型时需要循环求梯度,如果这时梯度一直叠加,那么我们求出来的结果就没有意义。因此,可以使用上面方法对张量的偏导进行清空。

        除了张量中存在梯度清空函数,优化器中也存在这样的函数:zero_grad()

optimizer = torch.optim.SGD([x], lr=0.1)
optimizer.step()
optimizer.zero_grad()
optimizer

       关于上面代码中的提到的优化器知识,我们将在后面的实验中学到,这里只需要知道优化器也需要进行梯度清空即可。

实验总结🔑

        本实验首先讲解了梯度的含义,然后利用 PyTorch 定义了可以自动求偏导的张量,然后对张量进行了梯度求解,最后阐述了梯度清空的重要性和必要性。在下一个实验中,我们会利用梯度求解函数,详细的阐述神经网络中的正向传播和反向传播。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/416224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python提取多个pdf特定页,并合并为新pdf文件

文章目录1&#xff0c;代码结构2&#xff0c;代码详解2.1&#xff0c;将范围字符串转成list2.2&#xff0c;获取pdf文件特定页2.3&#xff0c;将pdf页list合并为pdf文件并保存2.4&#xff0c;遍历所有要合并的文件&#xff0c;进行合并2.5&#xff0c;给出要合并的pdf文件及范围…

大模型学习

大模型学习计算机视觉方向ViTImage Token EmbeddingMulti-head Self-attentionStable Diffusionstable diffusion支持功能stable diffusion整体结构ClipText如何训练图像信息创建器&#xff08;Image information creator&#xff09;自动编码解码器&#xff08;降噪绘制图形&a…

One Note插件——gem for onenote的安装

文章目录一、前言二、报错原因三、解决方法一、前言 平时写笔记都是用的OneNote来记录&#xff0c;但是Onenote没有 Markdown编辑器 ,写起来很不方便&#xff0c;搜索了解后知道gem for OneNote这个插件&#xff0c;于是下载安装了&#xff0c;但是插件每次都要手动勾选&#…

什么是小程序SDK?安全吗?

前面分享了很多小程序相关的内容&#xff0c;常常提到小程序SDK的概念&#xff0c;但似乎有很多小伙伴不是很理解&#xff0c;今天就来跟大家聊聊小程序SDK。 什么是小程序SDK&#xff1f; 小程序SDK是一种开发工具包&#xff0c;用于开发和构建小程序应用程序。它提供了一系列…

【thingsboard+chirpstack 下行数据通信测试】

这里写目录标题 7. 节点未收到 tb 平台下发数据原因分析7.1 收到的size为07.2 节点收不到数据7.3 可以收到数据的一组例子7.4 节点没收到数据原因分析本文主要描述 tb 下发的数据,节点接收不到原因分析。 主要是数据格式以及解析脚本的对应关系 7. 节点未收到 tb 平台下发数据…

Golang数据类型比较

直接使用比较的情况 分类说明是否能比较说明基本类型整型&#xff08; int/uint/int8/uint8/int16/uint16/int32/uint32/int64/uint64/byte/rune等&#xff09;浮点数&#xff08; float32/float64&#xff09;复数类型&#xff08; complex64/complex128&#xff09;字符串&a…

《Vue3实战》 第一章 nods/npm安装、配置

1、nods.js安装&#xff08;Windows&#xff09; 1.1、下载并安装node https://nodejs.org/en/ , 安装到d盘nodejs目录 1.2、配置环境变量 path配置 1.3、配置全局包存放目录和缓存目录 在根目录下创建node_global&#xff08;全局包存放目录&#xff09;和node_cache&…

关于药物|新药|药品市场调研报告(实操资料分享)

药品市场调研报告是指对药品行业进行详细的市场情况研究和分析。往往伴随着药品市场调研目的地不同&#xff0c;如战略探索、新药开发、投资决策等&#xff0c;报告编辑的内容要点要求也不一样。但总的核心要点内容笔者已提炼&#xff0c;如下&#xff1a; 一、药品市场调研报告…

DeePMD-kit 配置环境备忘

版本 Conda Conda是一个开源的包管理系统和环境管理系统&#xff0c;用于安装多个版本的软件包及其依赖项&#xff0c;并在它们之间轻松切换。它可以在Linux、OS X和Windows上运行&#xff0c;是为Python程序创建的&#xff0c;但可以打包和分发任何软件。 conda enactivatec…

为何ChatGPT如此擅长编造故事?

“幻觉”——人工智能中的一个偏见性术语 AI聊天机器人(如OpenAI的ChatGPT)依赖于一种称为“大型语言模型”(LLM)的人工智能来生成它们的响应。LLM是一种计算机程序&#xff0c;经过数百万文本源的训练&#xff0c;可以阅读并生成“自然语言”文本语言&#xff0c;就像人类自然…

TCP报头结构和TCP协议特性

TCP报头结构 原端口号/目的端口号&#xff1a;表示数据是从哪个进程来&#xff0c;到哪个进程去&#xff1b; 32位序号/32位确认号&#xff1a;这个序号是取的发送方发送所用数据下一个字节的序号&#xff0c;发送方的序列号和接收方的确认号一样&#xff0c;才算接收成功&…

敏捷开发模式下如何用 PingCode 这类工具进行版本发布管理

在软件团队工作中&#xff0c;版本发布要达到好的发布效果&#xff0c;需要在版本发布前做好版本发布的规划&#xff0c;并对发布流程和进度进行管理 准备工作&#xff1a; 您已经创建了一个 PingCode 帐户【快速注册入口】 您创建了一个 PingCode Scrum或 Kanban 项目 您的…

【周末闲谈】文心一言,模仿还是超越?

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️周末闲谈】 周末闲谈 ✨第一周 二进制VS三进制 文章目录周末闲谈前言一、背景环境二、文心一言&#xff1f;(_)?三、文心一言的优势&#xff1f;&#x1f617;&#x1f617;&#x1f617;四、文心一…

使用 arm 架构实例搭建 Harbor

使用 arm 架构实例搭建 Harbor事情准备&#xff08;使用甲骨文云上实例时的准备事项&#xff09;第1步&#xff0c;准备自签名证书第2步&#xff0c;安装Docker-ce第3步&#xff0c;构建arm镜像第4步&#xff0c;安装Harbor第5步&#xff0c;访问Harbor第6步&#xff0c;上传镜…

TensorFlow 深度学习第二版:1~5

原文&#xff1a;Deep Learning with TensorFlow Second Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只…

2023年【第十四届蓝桥杯】省赛java b组填空题

第一题 令 S 1! 2! 3! ... 202320232023!&#xff0c;求 S 的末尾 9 位数字。 提示&#xff1a;答案首位不为 0。 考试时的想法以及题解&#xff1a; 如果我们直接按照题目描述直接来求每个阶乘和的话恐怕没有什么数据类型能够胜任&#xff0c;在考试时我一开始使用了…

Linux中的read/write和recv/send的区别,并使用recv/send实现简单的聊天功能

Linux中的read/write和recv/send的区别read/writeread/writeread/write的用法recv/sendrecv/sendrecv/send的用法LinuxLinuxLinux中的read/writeread/writeread/write和recv/sendrecv/sendrecv/send的区别下面是一个使用read/write进行文件读写操作的例子&#xff1a;下面是一个…

【云原生】Kubernetes(k8s)部署 MySQL+Dubbo+Nacos服务

一、说明二、部署 MySQL三、部署 Nacos四、部署 Dubbo 服务4.1. 创建镜像仓库的密钥4.2. 部署 provider 服务4.3. 部署 consumer 服务五、测试一、说明 本文介绍基于 Kubernetes(k8s) 环境集成阿里云 私有镜像仓库 来部署一套 Dubbo Nacos 的微服务系统&#xff0c;并使用 Ku…

VUE前端项目环境搭建

背景&#xff1a; 想要使用vue搭建一个前端项目&#xff0c;写个小网站练练手&#xff0c;因为没有前端经验&#xff0c;所以从网上找了一个vue得开源模板使用&#xff0c;经过一番挑选选中了字节公司花裤衩大佬开源得项目&#xff0c;地址如下&#xff1a; 开源项目地址&…

第三代api自动化测试框架使用教程(pytest+allure+sql+yaml)

使用教程一、配置1、环境配置2、框架配置3、启动入口二、用例编写1、用例模板2、参数依赖写法2、函数&#xff08;方法插件&#xff09;写法3、接口上传文件和表单参数4、接口上传json参数5、接口无数据填写6、code断言7、body断言7、json断言8、sql断言9、完整断言写法&#x…