IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> pytorch autograd.grad -> 正文阅读

[人工智能]pytorch autograd.grad

pytorch是动态图,即计算图的搭建和运算是同时的,随时可以输出结果;而tensorflow是静态图。

在pytorch的计算图里只有两种元素:数据(tensor)和运算(operation)

运算包括:加减乘除、开方、幂指对、三角函数等可求导运算。

数据可分为:叶子节点和非叶子节点;叶子节点是用户创建的节点,不依赖其他节点;叶子节点和非叶子节点的区别在于反向传播结束后,非叶子节点的梯度会被释放掉,只保留叶子节点的梯度,这样就节省了内存。如果想要保留非叶子节点的梯度,可以使用retain_grad()方法。

torch.tensor具有以下属性:

  • 查看是否可以求导:requires_grad
  • 查看运算名称:grad_fn
  • 查看是否为叶子节点:is_leaf
  • 查看导数值:grad

对于requires_grad属性,自己定义的叶子节点默认为False,而非叶子节点默认为True,神经网络中的权重默认为True。判断哪些节点是True/False的一个原则就是从我们需要求导的叶子节点到loss节点之间是一条可求导的通路。

当我们想要对某个Tensor变量求梯度时,需要先指定requires_grad属性为True,指定方式主要有以下两种:

x=torch.tensor(1.).requires_grad_()

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

pytorch提供两种求梯度的方法:backward()torch.autograd.grad(),这两种方法的区别在于前者是给叶子节点填充.grad字段,而后者是直接返回梯度。需要知道的一点是y.backward()其实等同于torch.autograd.backward(y)

一个简单的求导例子是 y = ( x + 1 ) × ( x + 2 ) y=(x+1)\times(x+2) y=(x+1)×(x+2),计算 ? y ? x \frac{\partial y}{\partial x} ?x?y?,假定 x = 2 x=2 x=2,先画出计算图:

在这里插入图片描述
整个链式求导过程为:

? y ? x = ? y ? a ? a ? x + ? y ? b ? b ? x = ( x + 2 ) × 1 + ( x + 1 ) × 1 → 7 \frac{\partial y}{\partial x}=\frac{\partial y}{\partial a}\frac{\partial a}{\partial x}+\frac{\partial y}{\partial b}\frac{\partial b}{\partial x}=(x+2)\times1+(x+1)\times1\to7 ?x?y?=?a?y??x?a?+?b?y??x?b?=(x+2)×1+(x+1)×17

使用backward():

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

a = torch.add(x, 1)
b = torch.add(x, 2)
y = torch.mul(a, b)

y.backward()
print(x.grad)
>>>tensor(7.)

观察下这几个tensor的属性:

print("requires_grad: ", x.requires_grad, a.requires_grad, b.requires_grad, y.requires_grad)
print("is_leaf: ", x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)
print("grad: ", x.grad, a.grad, b.grad, y.grad)

>>>requires_grad:  True True True True
>>>is_leaf:  True False False False
>>>grad:  tensor(7.) None None None

使用backward()函数反向传播计算tensor的梯度时,并不计算所有tensor的梯度,而是只计算满足这几个条件的tensor的梯度:1.类型为叶子节点、2.requires_grad=True、3.依赖该tensor的所有tensor的requires_grad=True。所有满足条件的变量梯度会自动保存到对应的grad属性里。

使用autograd.grad()

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

a = torch.add(x, 1)
b = torch.add(x, 2)
y = torch.mul(a, b)

grad = torch.autograd.grad(outputs=y, inputs=x)
print(grad)

# (tensor(7.),)

因为指定了输出y,输入x,所以返回值就是 ? y ? x \frac{\partial y}{\partial x} ?x?y?这一梯度,完整的返回值其实是一个元素,我们仅需要元组的第一个元素。

再举另外一个复杂一点且高阶求导的例子: z = x 2 y z=x^2y z=x2y,计算 ? z ? x , ? z ? y , ? 2 z ? 2 x \frac{\partial z}{\partial x},\frac{\partial z}{\partial y},\frac{\partial^2 z}{\partial^2 x} ?x?z?,?y?z?,?2x?2z?,假设给定 x = 2 , y = 3 x=2,y=3 x=2,y=3

手算可以得到:

? z ? x = 2 x y → 12 , ? z ? y = x 2 → 4 , ? 2 z ? 2 x = 2 y → 6 \frac{\partial z}{\partial x}=2xy\to12,\frac{\partial z}{\partial y}=x^2\to4,\frac{\partial^2 z}{\partial^2 x}=2y\to6 ?x?z?=2xy12,?y?z?=x24,?2x?2z?=2y6

求一阶导可以用backward()

x = torch.tensor(2., requires_grad=True)
y = torch.tensor(3., requires_grad=True)

z = x * x * y

z.backward()
print(x.grad, y.grad)
>>>tensor(12.) tensor(4.)

我们也可以使用autograd.grad()

x = torch.tensor(2.).requires_grad_()
y = torch.tensor(3.).requires_grad_()

z = x * x * y

grad_x = torch.autograd.grad(outputs=z, inputs=x)
print(grad_x[0])
>>>tensor(12.)

为什么不在这里面同时也求对y的导数呢?因为无论是backward还是autograd.grad在计算一次梯度后图就被释放了,如果想要保留,需要添加retain_graph=True

x = torch.tensor(2.).requires_grad_()
y = torch.tensor(3.).requires_grad_()

z = x * x * y

grad_x = torch.autograd.grad(outputs=z, inputs=x, retain_graph=True)
grad_y = torch.autograd.grad(outputs=z, inputs=y)

print(grad_x[0], grad_y[0])
>>>tensor(12.) tensor(4.) 

接下来看如何求高阶导,理论上其实是上面的grad_x再对x求梯度:

x = torch.tensor(2.).requires_grad_()
y = torch.tensor(3.).requires_grad_()

z = x * x * y

grad_x = torch.autograd.grad(outputs=z, inputs=x, retain_graph=True)
grad_xx = torch.autograd.grad(outputs=grad_x, inputs=x)

print(grad_xx[0])
>>>RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

这里出现了报错,虽然retain_graph=True保留了计算图和中间变量梯度,但没有保存grad_x的运算方式,需要使用create_graph=True在保留原图的基础上再建立额外的求导计算图,也就是会把 ? z ? x = 2 x y \frac{\partial z}{\partial x}=2xy ?x?z?=2xy这样的运算存下来:

# autograd.grad() + autograd.grad()
x = torch.tensor(2.).requires_grad_()
y = torch.tensor(3.).requires_grad_()

z = x * x * y

grad_x = torch.autograd.grad(outputs=z, inputs=x, create_graph=True)
grad_xx = torch.autograd.grad(outputs=grad_x, inputs=x)

print(grad_xx[0])
>>>tensor(6.)
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:31:54  更:2022-03-15 22:32:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 16:08:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码