给定一个简单的2层神经网络,传统思想是计算梯度w.r.t。权重/模型参数。为了进行实验,我想计算输入误差的梯度。是否有现有的Pytorch方法可以使我做到这一点?
更具体地,考虑以下神经网络:
import torch.nn as nn
import torch.nn.functional as F
class NeuralNet(nn.Module):
def __init__(self, n_features, n_hidden, n_classes, dropout):
super(NeuralNet, self).__init__()
self.fc1 = nn.Linear(n_features, n_hidden)
self.sigmoid = nn.Sigmoid()
self.fc2 = nn.Linear(n_hidden, n_classes)
self.dropout = dropout
def forward(self, x):
x = self.sigmoid(self.fc1(x))
x = F.dropout(x, self.dropout, training=self.training)
x = self.fc2(x)
return F.log_softmax(x, dim=1)
我实例化权重的模型和优化器,如下所示:
import torch.optim as optim
model = NeuralNet(n_features=args.n_features,
n_hidden=args.n_hidden,
n_classes=args.n_classes,
dropout=args.dropout)
optimizer_w = optim.SGD(model.parameters(), lr=0.001)
训练时,我照常更新体重。现在,假设我有权重值,那么我应该能够使用它们来计算梯度w.r.t。输入。我不知道怎么办。
def train(epoch):
t = time.time()
model.train()
optimizer.zero_grad()
output = model(features)
loss_train = F.nll_loss(output[idx_train], labels[idx_train])
acc_train = accuracy(output[idx_train], labels[idx_train])
loss_train.backward()
optimizer_w.step()
# grad_features = loss_train.backward() w.r.t to features
# features -= 0.001 * grad_features
for epoch in range(args.epochs):
train(epoch)
答案 0 :(得分:2)
可能的是,只需为要输入的每个输入批次设置input.requires_grad = True
,然后在loss.backward()
之后,您应该看到input.grad
拥有预期的梯度。换句话说,如果您输入模型的代码(在代码中称为features
)是某个M x N x ...
张量,则features.grad
将是一个具有相同形状的张量,其中每个元素grad
保持相对于features
的相应元素的渐变。在下面的评论中,我将i
用作广义索引-如果您的parameters
具有3个维度,则将其替换为features.grad[i, j, k]
,等等。
关于您遇到的错误:PyTorch操作会构建一棵树,代表它们描述的数学操作,然后将其用于微分。例如,c = a + b
将创建一棵树,其中a
和b
是叶节点,而c
不是叶节点(因为它是由其他表达式产生的)。您的模型是表达式,其输入以及参数是叶子,而所有中间和最终输出都不是叶子。您可以将叶子视为“常量”或“参数”,并将所有其他变量视为其功能。此消息告诉您,您只能设置requires_grad
的叶子变量。
您的问题是,features
在第一次迭代时是随机的(或者您初始化),因此是有效的叶子。第一次迭代后,features
不再是叶子,因为它变成了根据先前的叶子计算出的表达式。用伪代码,您有
f_1 = initial_value # valid leaf
f_2 = f_1 + your_grad_stuff # not a leaf: f_2 is a function of f_1
要解决这个问题,您需要使用detach
,这会断开树中的链接,并使autograd不管其如何创建都将张量视为恒定的张量。特别是,不会通过detach
向后传播梯度计算。所以你需要像
features = features.detach() - 0.01 * features.grad
注意:也许您需要在这里四处撒一些detach
,这很难在不看完整的代码和不知道确切目的的情况下说。