pytorch-求导机制,反向传播

pytorch中的求导机制,用于反向传播

在神经网络中是通过对梯度进行反向传播来对网络参数进行更新,在现有的深度学习框架,包括pytorch、tensorflow、keras、caffe等都集成了整个反向传播,通过调用函数可直接实现求梯度反向传播,省掉了许多麻烦。

pytorch的反向传播主要由三种方法:
1.通过调用backward的方法,求得的梯度将存放在求导变量张量的grad属性下。
2.通过调用torch.autograd.grad函数
3.通过SGD等优化器进行迭代优化,求得最小值

一、调用backward的方法

1.通过backward方法对标量进行反向传播

import torch

#使用y.backward对标量进行反向传播
x1 = torch.tensor(0.0, requires_grad=True) #设定x1为求导对象
a1 = torch.tensor(1.0)
b1 = torch.tensor(-2.0)
c1 = torch.tensor(1.0)
y1 = a1*torch.pow(x1, 2) + b1*x1 + c1 #函数 y=a*x^2+bx+c
#y1 = a1*x1**2 + b1*x1 + c1 #也可这么写函数
y1.backward() #反向传播
dy1_dx1 = x1.grad #对x1求导
print(dy1_dx1)
tensor(-2.)

2.通过backward对非标量进行反向传播

#使用使用y.backward对非标量进行反向传播
x2 = torch.tensor([[0.0, 0.0], [1.0, 2.0]], requires_grad=True) #设定x2为求导对象
a2 = torch.tensor(1.0)
b2 = torch.tensor(-2.0)
c2 = torch.tensor(1.0)
y2 = a2*torch.pow(x2, 2) + b2*x2 + c2 #函数 y=a*x^2+bx+c

gradient = torch.tensor([[1.0,1.0],[1.0,1.0]]) #设定一个与x2同形状的gradient参数张量,与调用张量作向量点乘,得到的标量结果再反向传播

y2.backward(gradient=gradient) #反向传播
dy2_dx2 = x2.grad #对x2求导
print("x2:\n", x2)
print("y2:\n", y2)
print("dy2_dx2:\n", dy2_dx2)
x2:
 tensor([[0., 0.],
        [1., 2.]], requires_grad=True)
y2:
 tensor([[1., 1.],
        [0., 1.]], grad_fn=<AddBackward0>)
dy2_dx2:
 tensor([[-2., -2.],
        [ 0.,  2.]])

3.backward方法中非标量的反向传播可以转化为标量的反向传播来进行

#非标量的反向传播通过标量的反向传播进行实现
x3 = torch.tensor([[0.0,0.0],[1.0,2.0]],requires_grad = True) #x需要被求导
a3 = torch.tensor(1.0)
b3 = torch.tensor(-2.0)
c3 = torch.tensor(1.0)
y3 = a3*torch.pow(x3,2) + b3*x3 + c3

gradient = torch.tensor([[1.0,1.0],[1.0,1.0]])#设定一个与x2同形状的gradient参数张量,与调用张量作向量点乘,得到的标量结果再反向传播
z = torch.sum(y3*gradient) #先求标量z

print("x3:\n",x3)
print("y3:\n",y3)
z.backward() #再对z进行反向传播
dy3_dx3 = x3.grad
print("dy3_dx3:\n",dy3_dx3)
x3:
 tensor([[0., 0.],
        [1., 2.]], requires_grad=True)
y3:
 tensor([[1., 1.],
        [0., 1.]], grad_fn=<AddBackward0>)
dy3_dx3:
 tensor([[-2., -2.],
        [ 0.,  2.]])

二、调用torch.autograd.grad函数

在这里调用torch.autograd.grad函数对一个自变量求导时,返回值中打印dy4_dx4.data输出才是正常的tensor,直接print(dy4_dx4)返回的不是一个正常tensor,而同时对多个自变量求导时,又不需要带.data后缀,详情可看下面代码输出。具体原因我也没弄明白,有哪位大牛了解,欢迎评论解惑。

1.对单变量求导

x4 = torch.tensor(0.0,requires_grad = True) # x4需要被求导
a4 = torch.tensor(1.0)
b4 = torch.tensor(-2.0)
c4 = torch.tensor(1.0)
y4 = a4*torch.pow(x4,2) + b4*x4 + c4

# create_graph 设置为 True 将允许创建更高阶的导数
dy4_dx4 = torch.autograd.grad(y4,x4,create_graph=True)[0] #求一阶导
print(dy4_dx4) #奇奇怪怪,两个print输出居然还有差别,没弄明白
print(dy4_dx4.data) #将dy4_dx4以 .data的形式输出或保存

dy42_dx42 = torch.autograd.grad(dy4_dx4,x4)[0]# 求二阶导数
print(dy42_dx42.data)

2.同时对多变量求导

x5 = torch.tensor(1.0,requires_grad = True) # x5需要被求导
x6 = torch.tensor(2.0,requires_grad = True)
y5 = x5 * x6
y6 = x5 + x6
# 允许同时对多个自变量求导数
(dy5_dx5,dy5_dx6) = torch.autograd.grad(outputs=y5,inputs = [x5,x6],retain_graph = True)
print(dy5_dx5,dy5_dx6)
# 如果有多个因变量,相当于把多个因变量的梯度结果求和
(dy52_dx5,dy62_dx6) = torch.autograd.grad(outputs=[y5,y6],inputs = [x5,x6])
print(dy52_dx5,dy62_dx6)
tensor(2.) tensor(1.)
tensor(3.) tensor(2.)

三、利用SGD优化器迭代进行求解最优值

这种方法也是在神经网络过程中经常使用的一个方法,使用随机梯度下降法来求解全局最优解或者局部最优解。

x7 = torch.tensor(0.0, requires_grad=True)  # x7需要被求导
a7 = torch.tensor(1.0)
b7 = torch.tensor(-2.0)
c7 = torch.tensor(1.0)

optimizer = torch.optim.SGD(params=[x7], lr=0.01) #使用SGD优化器,优化参数x7

def f(x): #定义函数表达式,即loss
    result = a7 * torch.pow(x7, 2) + b7 * x7 + c7
    return (result)
for i in range(500): #开始循环学习,500次
    optimizer.zero_grad()
    y = f(x7) #optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0
    y.backward() #反向传播
    optimizer.step() #只有用了optimizer.step(),模型才会更新
print("y=", f(x7).data, ";", "x=", x7.data)
y= tensor(0.) ; x= tensor(1.0000)

更多技术欢迎加入交流:320297153

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值