python - Pytorch中神经网络的前向雅可比行列很慢
问题描述
我正在计算 pytorch 中 2 层前馈神经网络的前向雅可比(输出相对于输入的导数),我的结果是正确的但相对较慢。考虑到计算的性质,我希望它大约与通过网络的前向传递一样快(或者可能是 2-3 倍),但是在这个例程上运行优化步骤需要大约 12 倍的时间(在我的测试示例我只想要所有点的 jacobian=1)与标准均方误差,所以我假设我正在以非最佳方式做某事。我只是想知道是否有人知道更快的编码方法。我的测试网络有 2 个输入节点,然后是 2 个隐藏层(每个节点 5 个节点)和一个输出层(2 个节点),并在隐藏层上使用 tanh 激活函数和线性输出层。
Jacobian 计算基于论文The Limitations of Deep Learning in Adversarial Settings,该论文给出了前向导数的基本递归定义(基本上,您最终将激活函数的导数与权重和每层的先前偏导数相乘)。这与前向传播非常相似,这就是为什么我希望它比现在更快。那么最后 2x2 jacobian 的行列式非常简单。
下面是网络和雅可比的代码
class Network(torch.nn.Module):
def __init__(self):
super(Network, self).__init__()
self.h_1_1 = torch.nn.Linear(input_1, hidden_1)
self.h_1_2 = torch.nn.Linear(hidden_1, hidden_2)
self.out = torch.nn.Linear(hidden_2, out_1)
def forward(self, x):
x = F.tanh(self.h_1_1(x))
x = F.tanh(self.h_1_2(x))
x = (self.out(x))
return x
def jacobian(self, x):
a = self.h_1_1.weight
x = F.tanh(self.h_1_1(x))
tanh_deriv_tensor = 1 - (x ** 2)
expanded_deriv = tanh_deriv_tensor.unsqueeze(-1).expand(-1, -1, input_1)
partials = expanded_deriv * a.expand_as(expanded_deriv)
a = torch.matmul(self.h_1_2.weight, partials)
x = F.tanh(self.h_1_2(x))
tanh_deriv_tensor = 1 - (x ** 2)
expanded_deriv = tanh_deriv_tensor.unsqueeze(-1).expand(-1, -1, out_1)
partials = expanded_deriv*a
partials = torch.matmul(self.out.weight, partials)
determinant = partials[:, 0, 0] * partials[:, 1, 1] - partials[:, 0, 1] * partials[:, 1, 0]
return determinant
这是正在比较的两个误差函数。请注意,第一个函数需要通过网络进行额外的前向调用,以获取输出值(标记为操作),而第二个函数不需要,因为它适用于输入值。
def actor_loss_fcn1(action, target):
loss = ((action-target)**2).mean()
return loss
def actor_loss_fcn2(input): # 12x slower
jacob = model.jacobian(input)
loss = ((jacob-1)**2).mean()
return loss
对此的任何见解将不胜感激
解决方案
'a' 的第二次计算在我的机器 (cpu) 上花费的时间最多。
# Here you increase the size of the matrix with a factor of "input_1"
expanded_deriv = tanh_deriv_tensor.unsqueeze(-1).expand(-1, -1, input_1)
partials = expanded_deriv * a.expand_as(expanded_deriv)
# Here your torch.matmul() needs to handle "input_1" times more computations than in a normal forward call
a = torch.matmul(self.h_1_2.weight, partials)
在我的机器上计算雅可比的时间大致是火炬计算的时间
a = torch.rand(hidden_1, hidden_2)
b = torch.rand(n_inputs, hidden_1, input_1)
%timeit torch.matmul(a,b)
从计算上讲,我认为不可能加快速度。除非你可以从 CPU 转移到 GPU,因为 GPU 在大型矩阵上会变得更好。
推荐阅读
- dataset - 如何在 kitti 数据集中获得用于深度预测的密集地面实况图像?
- arm - cortex-M4中的时钟指令使用哪个时钟源
- java - 如何修复hashmap中arraylist的重复词?
- javascript - Socket.io 无法访问事件处理程序中的握手查询参数
- excel - VBA 帮助:设置具有动态范围的自动运行 VBA
- python - 有没有办法将python脚本中定义的数据调用和存储到julia?
- oracle - 规范化后创建表的问题
- video - ffmpeg -to 标志在处理相同文件和不同时间范围时并不总是正确识别
- json - 将 1 对多 json 转换为 csv
- python-3.x - 如何为不使用熊猫的个人账户创建具有平均每月、每季度提款金额的新列?