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 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 【Antorgrad】使用Tensor 及Antograd实现机器学习 -> 正文阅读

[人工智能]【Antorgrad】使用Tensor 及Antograd实现机器学习

使用Tensor 及Antograd实现机器学习

节选自《python深度学习:基于pytorch》
因对自动求导不太了解,所以特查看此书,并做好笔记.

重点是非标量反向传播,对应的是多元函数的方向传播问题!!!


要点:

  1. 创建叶子节点(leaf node)的Tensor,使用requires_grad参数指定是否记录对其的操作,以便之后利用backward()方法进行梯度求解.requires_grad参数的缺省值为False,如果对其求导设置为True,然后与之有依赖关系的节点会自动变为True.
  2. 可利用requires_grad_()方法修改tensor的requires_grad属性.可以调用.detach()with torch.no_grad():,姜不再计算张量的梯度,跟踪张量的历史记录.这点在评估模型、测试模型阶段中常常用到.
  3. 通过运算创建的Tensor(即非叶子节点会自动被赋予fgrad_fn的书ing.该属性表示梯度函数.叶子节点的grad_fn为None.
  4. 最后得到的Tensor执行backward()函数,此时自动计算各变量的梯度,并将累加结果保存到grad的属性中.计算完成后,非叶子节点的梯度自动释放.
  5. backward()函数接受参数,该参数和调用函数的Tensor的维度相同,或者是可以broadcast的维度.如果求导的Tensor为标量(即一个数字),则backward中的参数可以省略.
  6. 方向传播的中间缓存会被清空,如果需要进行多次方向传播,需要指点backward中的参数retarin_graph=True.多次反向传播时,梯度时累加的.
  7. 非叶子节点的梯度backward调用后即被清空.
  8. 可以通过调用torch.no_grad()包裹代码块的形式来阻止requesgrad=True的张量的历史记录.这步在测试阶段经常使用.

在整个过程中,pytorch采用计算图的形式进行组织,该计算图为动态图,且在每次钱箱传播时,将重新构建.其他深度学习框架,如Tensorflow\keras一般为静态图.接下来我们介绍计算图,用图的形式描述更直观了,该计算图为有向无环图.

计算图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面通过代码实现这个计算图.

3标量反向传播

假设x、w、b都是标量,z=wx+b, 对标量z调用backward()方法,我们无须对backward()传入参数。 以下是实现自动求导的主要步骤:
1)定义叶子节点及算子节点:

#定义输入张量x
x=torch.Tensor([2])#初始化权重参数W,偏移量b、并设置require_ grad属性为True, 为自动求导
w=torch.randn(1 ,requires_grad=True)
b=torch.randn(1,requires_grad=True)
#实现前向传播
y=torch.mul(w,x) # 等价于w* x
z=torch.add(y,b) #等价于y+b
#查看x,W, b页子节点的requite_ grad属性
print(" x,w,b的require_ grad属性分 别为: {},{},{}".format(x.requires_grad,w.requires_grad, b.requires_grad))

out:
x,w,b的require_ grad属性分 别为: False,True,True

输入变量 == 叶子节点,默认没有梯度的。
算子后的量 =》 默认有梯度
输出变量 == 根节点

2)查看叶子节点、非叶子节点的其他属性。

#查看非叶子节点的requres_ grad属 性,
print("y, z的requires_grad属 性分别为: {},{}".format(y.requires_grad, z.requires_grad))
#因与w, b有依赖关系,故y, z的requires_ grad属性也是: True,True#查看各节点是否为叶子节点
print("x,w, b, y, z的是否为叶子节点: {},{},{},{}".format(x.is_leaf, w.is_leaf, b.is_leaf , y.is_leaf, z.is_leaf))
#x,w, b, y, z的是否为叶子节点: True,True,True,False,False
#查看叶子节点的grad_fn属 性
print("x, w,b的grad_fn属性: {},{},{}".format(x.grad_fn, w.grad_fn, b.grad_fn))
#因x, w, b为用户创建的,为通过其他张量计算得到,故x, w,b的grad_fn属性 :None,None,None
#查看非叶子节点的grad_ fn属 性
print("y,z的是否为叶子节点: {},{}".format(y.grad_fn,z.grad_fn))
#y, z的是否为叶子节点: <MulBackward0 object a0x7f923e85dda0>,<AddBackward0 object at 0x7f923e85d9b0>

3)自动求导,实现梯度方向传播,即梯度的反向传播。

#基于z张量进行梯度反向传播,执行backward之后计算图会自动清空,
z.backward()#如果需要多次使用backward,需要修改参数retain_graph为True,此时梯度是累加的
#z.backward(retain_ graph=True)
# 查看叶子节点的梯度,x是叶子节点但它无须求导,故其梯度为None
print("参数w,b的梯度分别为:{},{},{}".format(w.grad,b.grad,x.grad))
#参数w,b的梯度分别为:ensor(2.1),tensor([1 .),None
#非叶子节点的梯度,执行backward之后, 会自动清空
print("非叶子节点y,z的梯度分别为:{},{}".format(y.grad,z.grad))
#非叶子节点y,z的梯度分别为:None,None

4非标量 反向传播

在2.5.3节中介绍了当目标张量为标量时,可以调用backward()方法且无须传入参数。目标张量-般都是标量,如我们经常使用的损失值Loss,-般都是一个标量。但也有非标量的情况,后面将介绍的Deep Dream的目标值就是一个含多个元素的张量。那如何对非标量进行反向传播呢? PyTorch有个简单的规定,不让张量(Tensor)对张量求导,只允许标量对张量求导,因此,如果目标张量对一个非标量调用backward(),则需要传入一个gradient参数, 该参数也是张量,而且需要与调用backward()的张量形状相同。那么为什么要传入一个张量gradient呢?

传入这个参数就是为了把张量对张量的求导转换为标量对张量的求导。这有点拗口,我们举一个例子来说, 假设目标值为Ioss=(y1,y2,...,ym),传入的参数为v=(v1,v2,...,vm),那么就可把对loss的求导,转换为对 l o s s ? v T loss*v^T loss?vT标量的求导。 即把原来 ? l o s s ? x \frac{\partial loss}{\partial x} ?x?loss?得到的雅可比矩阵(Jacobian) 乘以张量 v T v^T vT,便可得到我们需要的梯度矩阵。
backward函数的格式为:
backward(gradient=None, retain_graph=None, create_graph=False)
上面说的可能有点抽象,下面来通过一 个实例进行说明 。
1)定义叶子节点及计算节点。

import torch
#定义叶子节点张量x,形状为1x2
x= torch.tensor([[2, 3]], dtype=torch.float, requires_grad=True)
# 初始化雅可比矩阵
J= torch.zeros(2 ,2)
#初始化目标张量,形状为1x2
y = torch.zeros(1,2)
#2 Xy5xZli)AGJBJ#: 
#y1=x1**2+3*x2, y2=x2**2+2*x1
y[0, 0]=x[0, 0]**2+3*x[0 ,1]
y[0, 1]=x[0, 1]**2+2*x[0, 0]

2)手工计算y对x的梯度
在这里插入图片描述
J T = [ 4 2 3 6 ] (2) J^T=\left[ \begin{matrix} 4 & 2 \\ 3 & 6 \\ \end{matrix} \right]\tag{2} JT=[43?26?](2)
3)调用backward来获取y对x的梯度

y.backward(torch.Tensor([[1, 1]]))
print(x.grad)#结果为tensor([6., 9.])

这个结果与我们手工运算的不符,显然这个结果是错误的,那错在哪里呢?这个结果的计算过程是:

由此可见,错在v的取值, 通过这种方式得到的并不是y对x的梯度。这里我们可以分成两步计算。首先让v=(1,0)得到y1对x的梯度,然后使v=(0,1), 得到y2对x的梯度。这里因需要重复使用backward(),需要使参数retain_ graph=True, 具体代码如下:

#生成y1对x的梯度
y.backward(torch.Tensor([[1,0]]),retain_graph=True)
J[0]=x.grad#梯度 是累加的,故需要对x的梯度清零
x.grad = torch.zeros_like(x.grad)
# 生成y2对x的梯度
y.backward(torch. Tensor([[0, 1]]))
J[1]=x.grad#显示jacobian矩阵的值
print(J)

out:
tensor([[4., 3.], [2., 6.]])
这个结果于手工运行的式(2-5)结果一致.

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

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 4:23:53-

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