pytorch3 自动求导

pytorch3 自动求导

为什么写本博客

前人种树,后人乘凉。希望自己的学习笔记可以帮助到需要的人。

本博客定位

​ 帮助那些了解原理(指深度学习原理知道),想要实现自己想法的朋友。

目录结构

文章目录

    • pytorch3 自动求导
      • 1. 概述:
      • 2. 自动求导:
        • 2.1 基本方法:
        • 2.2 深入研究1:
        • 2.3 深入研究2:
      • 3. 控制求导:
      • 4. 清空累计值:
      • 5. 其它注意点:

1. 概述:

​ 自动求导是pytorch的核心功能,也是我们实现我们的神经网络算法的核心。其主要应用是用来处理反向传播算法

2. 自动求导:

2.1 基本方法:

​ 下面,我们通过一个例子来演示:

构建 y = x + b,然后对y求导

​ 那么,实现方法如下:

import torch
b = torch.randn((3,4),requires_grad=True)	# requires_grad = True 必须声明
x = torch.randn((3,4),requires_grad=True)
# 定义一个函数
t = x + b
y = t.sum()		# 这一步是因为只有标量才可以求导(pytorch所规定)
# 求导
y.backward()
# b的梯度
print(b.grad)
# x的梯度
print(x.grad)

​ 运行结果如下:

tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
# 正确结果,因为为线性函数嘛

不难从上面看出,想要自动求导需要的步骤为:

# 1. 定义数据和函数
xxxx = torch.tensor(xxx,requires_grad=True)
fx = xxxx
# 2. 对目标求导:fx要为标量
fx.backward()
# 3. 计算想要的参数的梯度
print(xx.grad)

2.2 深入研究1:

​ 想要探究一下:是否所有变量都要声明requires_grad=True?

所有变量都声明

​ 这个就是上面的例子,显然是可以正常运行的。

只有一个变量声明

代码一:

import torch
b = torch.randn((3,4),requires_grad=True)
x = torch.randn((3,4))
# 定义一个函数
t = x + b
y = t.sum()
# 求导
y.backward()
# b的梯度
print(b.grad)
# x的梯度
print(x.grad)

​ 结果为:

tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
None

代码二:

import torch
b = torch.randn((3,4))
x = torch.randn((3,4),requires_grad=True)
# 定义一个函数
t = x + b
y = t.sum()
# 求导
y.backward()
# b的梯度
print(b.grad)
# x的梯度
print(x.grad)

​ 结果为:

None
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])

一个也不声明

​ 显然,这样结果肯定报错。

总结

​ 通过上面的测试,可以看出:如果你想求解梯度的变量是最基层(底层,不由其它变量构成)的变量,那么你必须为它声明requires_grad=True,但是如果你对它不感兴趣,可以不用设置。

2.3 深入研究2:

​ 另外一个问题:是否所有变量都声明了requires_grad=True,函数才可以调用backward方法?

​ 这个答案,其实上面的案例已经告诉我们了——不是。那么,是不是声明一个变量,那么由这个变量构成的函数就可以使用backward方法呢?

​ 看代码:

import torch
b = torch.randn((3,4))
x = torch.randn((3,4),requires_grad=True)
# 定义一个函数
t1 = x + b      # 由x构成的函数
y1 = t1.sum()
t2 = b*3        # 不由x构成的函数
y2 = t2.sum()
# 查看是否可以
print(y1.requires_grad)	#  返回变量requires_grad是否为True
print(y2.requires_grad)

​ 结果为:

True
False

综上,得出结论:只要有一个变量声明了requires_grad=True,那么由它构成的函数requires_grad也为True,可以正常使用backward方法。

3. 控制求导:

有时候,我们的一些量不需要参与梯度计算。此时,就需要这个方法:

import torch
x = torch.randn((3,4),requires_grad=True)
with torch.no_grad():	# 这样y不受x的requires_grad=True影响
	y = x ** 2
print(y.requires_grad)	#false

4. 清空累计值:

​ 梯度计算默认会累加,但是一般情况下我们并不需要累加:

import torch
x = torch.tensor([10,20,30,40],requires_grad=True,dtype=torch.float32)
for i in range(5):
    y = x**2 +10
    # 转为标量
    y1 = y.mean()
    # 自动求导
    y1.backward()
    print(x.grad)

​ 运行结果:

tensor([ 5., 10., 15., 20.])
tensor([10., 20., 30., 40.])
tensor([15., 30., 45., 60.])
tensor([20., 40., 60., 80.])
tensor([ 25., 50., 75., 100.])

​ 因此,需要进行清除累加值:

import torch
x = torch.tensor([10,20,30,40],requires_grad=True,dtype=torch.float32)
for i in range(5):
    y = x**2 +10
    # 转为标量
    y1 = y.mean()
    # 清楚累加
    if x.grad is not None:
	    x.grad.data.zero_()
    # 自动求导
    y1.backward()
    print(x.grad)

5. 其它注意点:

1. 只有浮点型和复数型可以进行自动梯度求导
2. 自动求导默认累加,需要自己清空
3. 只有标量可以自动求导,因此需要手动转换,比如上面中t.sum()
4. 当一个张量设置了requires_grad=True后,不可以直接转为numpy对象,需要先使用detach方法生成一个新张量,然后进行转换。

​ 关于第四点这里举一个例子:

import torch
x = torch.randn((3,4),requires_grad=True)
c = x.numpy()

​ 上面代码直接运行会报错,需要修改为:

import torch
x = torch.randn((3,4),requires_grad=True)
new_x = x.detach()
c = new_x.numpy()
print(type(c))	# 

你可能感兴趣的:(pytorch学习笔记,深度学习,python,pytorch)