如何做自己的电影网站,如何确定网站建设 栏目,软件工程师中级职称,大量情侣网名网站1、requires_grad
requires_gradTrue # 要求计算梯度#xff1b;
requires_gradFalse # 不要求计算梯度#xff1b;在pytorch中#xff0c;tensor有一个 requires_grad参数#xff0c;如果设置为True#xff0c;那么它会追踪对于该张量的所有操作。在完成计算时可以通过调…1、requires_grad
requires_gradTrue # 要求计算梯度
requires_gradFalse # 不要求计算梯度在pytorch中tensor有一个 requires_grad参数如果设置为True那么它会追踪对于该张量的所有操作。在完成计算时可以通过调用backward()自动计算所有的梯度并且该张量的所有梯度会自动累加到张量的.grad属性反之如果设置为False,则不会记录这些操作过程自然而然就不会进行计算梯度的工作 。 tensor的requires_grad的属性默认为False.
x torch.tensor([1.0, 2.0])
x.requires_grad
结果
False我们可以先看一下requires_grad参数设置分别为True和False时的情况。
# 设置好requires_grad的值为True
import torchx torch.tensor([1.0, 2.0], requires_gradTrue)
y torch.tensor([3.0, 4.0], requires_gradFalse)
y1 2.0 * x 2.0 * yprint(x, x.requires_grad)
print(y, y.requires_grad)
print(y1, y1.requires_grad)y1.backward(torch.tensor([1.0, 1.0]))
print(x.grad)
print(y.grad)
结果
tensor([1., 2.], requires_gradTrue) True
tensor([3., 4.]) False
tensor([ 8., 12.], grad_fnAddBackward0) True
tensor([2., 2.])
None在上面的实验中发现在计算中如果存在tensor张量x的requires_grad为True的情况那么计算之后的结果y1的requires_grad也为True且计算梯度时仅会计算x的梯度因为前面设置了y张量的requires_grad为False所以最后y张量的grad属性值为None。
关于张量tensor的梯度计算可以参考另一篇博客Tensor及其梯度
所以在深度学习训练时要冻结部分权值参数不进行参数更新的话可以在优化器初始化之前将参数组进行筛选将不想进行训练的参数的requires_grad设置为False。代码示例参考如下
cnn CNN() #构建网络for n,p in cnn.named_parameters():print(n,p.requires_grad)if nconv1.0.weight:p.requires_grad Falseoptimizer torch.optim.Adam(filter(lambda p: p.requires_grad,cnn.parameters()), lrlearning_rate)
也可以把requires_grad属性置为 False这个操作放在optimizer之后参数都不会进行更新。但是区别在于先进行requires_grad属性置为False的操作再optimizer初始化不会将该层的参数放进优化器中更新而先进行optimizer初始化再进行requires_grad属性置为False的操作会将所有的参数放进优化器中但不更新该指定层参数只更新剩下的参数。对比看来optimizer中的参数量会相比前者会更大一点。
所以一般最好是将requires_grad属性置为 False这个操作放在optimizer之前。
注意事项
1、requires_grad属性置为 False或者默认时不能在对该tensor计算梯度否则会进行报错。因为并没有追踪到任何计算历史所以就不存在梯度的计算了。
import torchx torch.tensor([1.0, 2.0], requires_gradTrue)
y torch.tensor([3.0, 4.0], requires_gradFalse)
y1 2.0 * x 2.0 * y
# y1.backward(torch.tensor([1.0, 1.0]))
# print(x.grad)
y.backward(torch.tensor([1.0, 1.0]))
结果
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn2、整数型的tensor并没有requires_grad这个属性只有浮点类型的tensor可以计算梯度
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
d:\test.ipynb Cell 9 in cell line: 2()1 a torch.tensor([1,2])
---- 2 b torch.tensor([3,4], requires_gradTrue)3 c ab4 print(a.requires_grad)RuntimeError: Only Tensors of floating point and complex dtype can require gradients2、detach
detach方法就是返回了一个新的张量该张量与当前计算图完全分离且该张量的计算将不会记录到梯度当中。
import torchx torch.tensor([1.0, 2.0], requires_gradTrue)
y torch.tensor([3.0, 4.0], requires_gradTrue)
z torch.tensor([3.0, 2.0], requires_gradTrue)
x x * 2
z1 z.detach()
x1 x.detach()
y1 2.0 * x1 2.0 * y 3 * z1
y1.backward(torch.tensor([1.0, 1.0]))
print(x.requires_grad)
print(x.grad)
print(y.requires_grad)
print(y.grad)
print(z.requires_grad)
print(z.grad)
print(z1.requires_grad)
print(z1.grad)
结果
True
None
True
tensor([2., 2.])
True
None
False
None
C:\Users\26973\AppData\Local\Temp\ipykernel_37516\3652236761.py:12: UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute wont be populated during autograd.backward(). If you indeed want the gradient for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations.print(x.grad)从上面实验可以看到使用detach()方法后可以截断反向传播的梯度流其作用有点类似于将requires_grad属性置为False的情况。
与requires_grad_()将requires_grad属性置为False不同的是 detach()函数会返回一个新的Tensor对象b 并且新Tensor是与当前的计算图分离的其requires_grad属性为False反向传播时不会计算其梯度。 b与a共享数据的存储空间二者指向同一块内存。
而requires_grad_()函数会改变Tensor的requires_grad属性并返回Tensor修改requires_grad的操作是原位操作(in place)。其默认参数为requires_gradTrue。requires_gradTrue时自动求导会记录对Tensor的操作requires_grad_()的主要用途是告诉自动求导开始记录对Tensor的操作。
关于detach()返回的张量与原张量共享数据的存储空间二者指向同一块内存可以由以下代码看出
z1[0] 5.0
print(z)
print(z1)
结果
tensor([5., 2.], requires_gradTrue)
tensor([5., 2.])当我们修改z1中的数据时z中的数据也随之修改。
**总结**当我们在计算到某一步时不需要在记录某一个张量的梯度时就可以使用detach()将其从追踪记录当中分离出来这样一来该张量对应计算产生的梯度就不会被考虑了。比较常见的就是在GAN生成模型中当训练一次生成器后再训练判别器时需要对生成器生成的fake进行损失计算但是又不希望这部分损失对生成器进行权值的更新这个时候需要冻结生成器那部分的权值因此通常将生成器生成的fake张量使用fetch()进行阶段再输入到判别器进行运算这样最后使用loss.backward()时仅会对判别器部分的梯度进行计算
import torch
import numpy as npy torch.tensor([3.0, 4.0], requires_gradTrue)
z torch.tensor([3.0, 2.0], requires_gradTrue)
z1 z.detach()
z2 z1 y
y1 torch.sum(3 * z2)
y1.backward()
print(z2, z2.requires_grad)
print(y.grad)
print(z2.grad)
print(z1.grad)
结果
tensor([6., 6.], grad_fnAddBackward0) True
tensor([3., 3.])
None
None这里假设z是生成器生成的图片z1表示的是使用detch()截断后的张量y表示的判别器内部的一些运算张量z2表示经过判别器后的结果y1假设是计算loss的损失函数我们可以看到使用y1.backward() 后不会对生成器生成的z产生任何的梯度在优化器优化时自然而然不会对其进行优化。而对于后面的步骤仍然会跟踪记录其所有的计算过程比如对于z1在判别器中进行运算仍然会记录其过程并仅会对判别器内部的参数y进行梯度计算从而进行优化。
注这里z2.grad之所以也为None是因为z2节点不是叶子节点它是由z1和y进行累加而来的所以在z2处不会有grad属性这部分可以看其给出的警告
UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute wont be populated during autograd.backward(). If you indeed want the gradient for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations.3、with_no_grad
torch.no_grad()是一个上下文管理器用来禁止梯度的计算通常用来网络推断中它可以减少计算内存的使用量。
# 设置好requires_grad的值为True
import torchx torch.tensor([1.0, 2.0], requires_gradTrue)
y1 x ** 2with torch.no_grad(): # 这里使用了no_grad()包裹不需要被追踪的计算过程y2 y1 * 2y3 x ** 5y4 y1 y2 y3print(y1, y1.requires_grad)
print(y2, y2.requires_grad)
print(y3, y3.requires_grad)
print(y4, y4.requires_grad)y4.backward(torch.ones(y4.shape)) # y1.backward() y2.backward()
print(x.grad)
结果
tensor([1., 4.], grad_fnPowBackward0) True
tensor([2., 8.]) False
tensor([ 1., 32.]) False
tensor([ 4., 44.], grad_fnAddBackward0) True
tensor([2., 4.])可以看出其实使用with torch.no_grad()这个后被其包裹的所有运算都是不计算梯度的其效果与detach()类似所以使用下列代码的运行结果是一样的
# 设置好requires_grad的值为True
import torchx torch.tensor([1.0, 2.0], requires_gradTrue)
y1 x ** 2# with torch.no_grad(): # 这里使用了no_grad()包裹不需要被追踪的计算过程
y2 y1 * 2
y3 x ** 5
y2 y2.detach()
y3 y3.detach()y4 y1 y2 y3print(y1, y1.requires_grad)
print(y2, y2.requires_grad)
print(y3, y3.requires_grad)
print(y4, y4.requires_grad)y4.backward(torch.ones(y4.shape)) # y1.backward() y2.backward()
print(x.grad)结果
tensor([1., 4.], grad_fnPowBackward0) True
tensor([2., 8.]) False
tensor([ 1., 32.]) False
tensor([ 4., 44.], grad_fnAddBackward0) True
tensor([2., 4.])detach()是考虑将单个张量从追踪记录当中脱离出来 而torch.no_grad()是一个warper可以将多个计算步骤的张量计算脱离出去本质上没啥区别。
4、总结
requires_grad在最开始创建Tensor时候可以设置的属性用于表明是否追踪当前Tensor的计算操作。后面也可以通过requires_grad_方法设置该参数但是只有叶子节点才可以设置该参数。detach()方法则是用于将某一个Tensor从计算图中分离出来。返回的是一个内存共享的Tensor一变都变。torch.no_grad()对所有包裹的计算操作进行分离。但是torch.no_grad()将会使用更少的内存因为从包裹的开始就表明不需要计算梯度了因此就不需要保存中间结果。