import torch

requires_grad,它被用于说明当前量是否需要在计算中保留对应的梯度信息,以上文所述的线性回归为例,容易知道参数www为需要训练的对象,为了得到最合适的参数值,我们需要设置一个相关的损失函数,根据梯度回传的思路进行训练。
If there’s a single input to an operation that requires gradient, its output will also require gradient.
requires_grad会自动设置为False。既然没有了相关的梯度值,自然进行反向传播时会将这部分子图从计算中剔除。Conversely, only if all inputs don’t require gradient, the output also won’t require it. Backward computation is never performed in the subgraphs, where all Tensors didn’t require gradients.
a = torch.tensor([1., 2., 3.])
print('a:', a.requires_grad)
b = torch.tensor([1., 4., 2.], requires_grad = True)
print('b:', b.requires_grad)
print('sum of a and b:', (a+b).requires_grad)
a: False
b: True
sum of a and b: True
we only retain the grad of the leaf node with requires_grad =True
requires_grad为False,故我们只会保存参数的梯度,进一步据此进行参数优化for idx, data in enumerate(train_loader):
xs, ys = data
optmizer.zero_grad()
# 计算d(l1)/d(x)
pred1 = model1(xs) #生成graph1
loss = loss_fn1(pred1, ys)
loss.backward() #释放graph1
# 计算d(l2)/d(x)
pred2 = model2(xs)#生成graph2
loss2 = loss_fn2(pred2, ys)
loss.backward() #释放graph2
# 使用d(l1)/d(x)+d(l2)/d(x)进行优化
optmizer.step()
import torch.nn.functional as F
import torch.nn as nn
class Conv_Classifier(nn.Module):
def __init__(self):
super(Conv_Classifier, self).__init__()
self.conv1 = nn.Conv2d(1, 5, 5)
self.pool1 = nn.MaxPool2d(2)
self.conv2 = nn.Conv2d(5, 16, 5)
self.pool2 = nn.MaxPool2d(2)
self.fc1 = nn.Linear(256, 20)
self.fc2 = nn.Linear(20, 10)
def forward(self, x):
x = F.relu(self.pool1((self.conv1(x))))
x = F.relu(self.pool2((self.conv2(x))))
x = F.dropout2d(x, training=self.training)
x = x.view(-1, 256)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
return x
Mnist_Classifier = Conv_Classifier()
from torchviz import make_dot
input_sample = torch.rand((1, 1, 28, 28))
make_dot(Mnist_Classifier(input_sample), params=dict(Mnist_Classifier.named_parameters()))
其对应的计算梯度所需的图(计算图)为

可以看到,所有的叶子节点对应的操作都被记录,以便之后的梯度回传。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3271/viewspace-2822214/ ,如需转载,请注明出处,否则将追究法律责任。