python-3.x - 如何计算相对于模型输入的误差梯度?
问题描述
给定一个简单的 2 层神经网络,传统的想法是计算权重/模型参数的梯度。对于一个实验,我想计算输入误差的梯度。是否有现有的 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)
在训练时,我像往常一样更新权重。现在,鉴于我有权重值,我应该能够使用它们来计算输入的梯度。我无法弄清楚如何。
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)
解决方案
有可能,只需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
es,如果没有看到你的整个代码并知道确切的目的,这很难说。
推荐阅读
- c++ - 为什么给定的代码不适用于所有测试用例?为什么当输入为 7786 时它不起作用?
- vue.js - vue.js 中的数组依赖
- r - 如何在ggplot2 R中为另一个比例的变量添加辅助y轴?
- php - ¿如何用逗号而不是换行符分隔?
- javascript - CakePHP 未正确显示数据库中的某些值
- c++ - 当我设置截止时间时,gRPC C++ 客户端阻塞
- azure-timeseries-insights - Azure 时间序列洞察力预览 API 失败,未找到具有 id 的环境
- javascript - JSON.parse 将数字键保存为字符串
- angular - 如何为 Angular 项目正确创建和搭建多个入口点
- mongodb - 如何获取投影的所有文档或仅获取一个?