1.关于.grad理解直接见测试代码和注释:
import torch
x = torch.tensor([1, 2], dtype=torch.float32, requires_grad=True)
a = torch.tensor([3, 4], dtype=torch.float32, requires_grad=False)
w = torch.tensor([1, 2], dtype=torch.float32, requires_grad=True)
y = x * 4 + a * w #a * w得到[3., 8.],对应元素相乘类似矩阵点乘
print("**y is***",y)
y.requires_grad_(True)
z = torch.mean(y)
z.backward()
print(x.grad, x.requires_grad)#x.grad就是相当于求执行backward()的那个变量对于a的梯度,这里就是dz/dx
print(a.grad, a.requires_grad)
print(y.grad, y.requires_grad) #使用y.retain_grad()才能把非叶子结点的梯度保存下来
print(z.grad, z.requires_grad)
print("***w*****",w.grad, w.requires_grad)
#**y is*** tensor([ 7., 16.], grad_fn=)
#tensor([2., 2.]) True
#None False
#None True
#None True
#***w***** tensor([1.5000, 2.0000]) True
2.变量进行了torch.mean操作和reshape操作后对应的梯度
x进行reshape操作后得到x1,虽然这里x1的梯度为None,但是笔者测试了下,如果设置x1.requires_grad_(False)程序还是会报错,说明求x的梯度时还是需要依赖x1的梯度。
import torch
x = torch.tensor([1, 2], dtype=torch.float32, requires_grad=True)
x1 = torch.reshape(x,(2,))#reshape成一维,数据实质没变,这里就是为了看变量x进行reshape后的梯度,答案是没有梯度
print("**x1 is**",x1)
z = torch.mean(x1)
print("**z is***",z)
z.backward()#进行backward的z必须为标量即一个数字,不能是向量。如果z是向量就得在括号里加一些东西了才能保证不报错
print("x1.grad",x1.grad, x1.requires_grad)
print("x.grad",x.grad, x.requires_grad)
#**x1 is** tensor([1., 2.], grad_fn=)
#**z is*** tensor(1.5000, grad_fn=)
#x1.grad None True
#x.grad tensor([0.5000, 0.5000]) True
3.关于requires_grad_(True)的理解:
1)requires_grad=True 的作用是让 backward 可以追踪这个参数并且计算它的梯度。最开始定义你的输入是 requires_grad=True ,那么后续对应的输出也自动具有 requires_grad=True ,如代码中的 y 和 z 。
2)因为在 z 对 x 求导的过程中需要依赖 z 对 y 求导的结果,而如果设置 y.requires_grad=False ,则会报错。就是因为只有 requires_grad=True 的参数才会参与求导,而在求导路径的中间设置相关参数不可求导,那么它就会报错。
3)首先求梯度遵循链式求导法则,这里测试代码中虽然a被设置为了 requires_grad=False,但是求z关于w的梯度时不会用到z关于a的梯度,所以可以得到w.grad的结果,并不会报错。
4.关于detach()的应用:
下面两个代码块唯一区别就是第二个代码块进行了q的detach(),通过对比可以看出两个代码块里x的梯度的结果是不同的。这是因为如果q进行了detach(),也就是意味着阻断了q梯度的反向传播,则q里面x的梯度也无法求得。但x不止存在于q里面,其他地方也会含有x,所以对q进行了detach()后,最后在求最终的x的梯度时,q里面的x的梯度就会被忽略掉,使得q里面的x的梯度不会对最终x的梯度造成影响。
import torch
x = torch.tensor([1, 2], dtype=torch.float32, requires_grad=True)
q=2*x
#q=q.detach()
z =torch.mean(3*x+q)
print("z is equal to:",z)
z.backward()
print(x.grad, x.requires_grad)#x.grad就是相当于求执行backward()的那个变量对于a的梯度,这里就是dz/dx
print(q.grad, q.requires_grad)
#输出
#z is equal to: tensor(7.5000, grad_fn=)
#tensor([2.5000, 2.5000]) True
#None True
import torch
x = torch.tensor([1, 2], dtype=torch.float32, requires_grad=True)
q=2*x
q=q.detach()
z =torch.mean(3*x+q)
print("z is equal to:",z)
z.backward()
print(x.grad, x.requires_grad)#x.grad就是相当于求执行backward()的那个变量对于a的梯度,这里就是dz/dx
print(q.grad, q.requires_grad)
#输出
#z is equal to: tensor(7.5000, grad_fn=)
#tensor([1.5000, 1.5000]) True
#None False