Python 求Caffe-conv滤波器相对于输入的梯度
我需要找到卷积神经网络(CNN)中单个卷积滤波器相对于输入层的梯度,作为一种方法。Python 求Caffe-conv滤波器相对于输入的梯度,python,c++,neural-network,deep-learning,caffe,Python,C++,Neural Network,Deep Learning,Caffe,我需要找到卷积神经网络(CNN)中单个卷积滤波器相对于输入层的梯度,作为一种方法。 在的Python接口中给定一个经过训练的网络(如中的网络),我如何才能找到conv过滤器相对于输入层中数据的梯度 编辑: 基于,我添加了下面的代码。我的输入层的尺寸是[8,8,7,96]。我的第一个conv层,conv1,有11个大小为1x5的过滤器,导致维度[8,11,7,92] net = solver.net diffs = net.backward(diffs=['data', 'conv1']) pri
在的Python接口中给定一个经过训练的网络(如中的网络),我如何才能找到conv过滤器相对于输入层中数据的梯度 编辑: 基于,我添加了下面的代码。我的输入层的尺寸是
[8,8,7,96]
。我的第一个conv层,conv1
,有11个大小为1x5
的过滤器,导致维度[8,11,7,92]
net = solver.net
diffs = net.backward(diffs=['data', 'conv1'])
print diffs.keys() # >> ['conv1', 'data']
print diffs['data'].shape # >> (8, 8, 7, 96)
print diffs['conv1'].shape # >> (8, 11, 7, 92)
从输出中可以看到,net.backward()
返回的数组的维度等于Caffe中我的层的维度。经过一些测试,我发现这个输出是关于data
层和conv1
层的损失梯度
然而,我的问题是如何找到单个conv滤波器相对于输入层中数据的梯度,这是另一回事。如何实现这一点?在运行
backward()
过程时,可以获得任何层的梯度。调用函数时只需指定层列表。要根据数据层显示渐变,请执行以下操作:
net.forward()
diffs = net.backward(diffs=['data', 'conv1'])`
data_point = 16
plt.imshow(diffs['data'][data_point].squeeze())
在某些情况下,您可能希望强制所有层向后执行,请查看模型的force\u backward
参数
Caffe net处理两个数字“流”。第一个是数据“流”:通过网络推送的图像和标签。当这些输入通过网络时,它们被转换为高级表示,并最终转换为类别概率向量(在分类任务中)。
第二个“流”包含不同层的参数、卷积的权重、偏差等。这些数字/权重在网络的训练阶段更改和学习 尽管这两个“流”所扮演的角色根本不同,caffe仍然使用相同的数据结构,
blob
,来存储和管理它们。但是,对于每个层,有两个不同的blob向量,每个流一个 下面是一个我希望能够澄清的例子:
import caffe
solver = caffe.SGDSolver( PATH_TO_SOLVER_PROTOTXT )
net = solver.net
如果你现在看看
net.blobs
您将看到一个字典为网络中的每个层存储一个“caffe blob”对象。每个blob都有存储数据和渐变的空间
net.blobs['data'].data.shape # >> (32, 3, 224, 224)
net.blobs['data'].diff.shape # >> (32, 3, 224, 224)
对于卷积层:
net.blobs['conv1/7x7_s2'].data.shape # >> (32, 64, 112, 112)
net.blobs['conv1/7x7_s2'].diff.shape # >> (32, 64, 112, 112)
net.blobs
保存第一个数据流,它的形状与输入图像的形状匹配,直到生成的类概率向量
另一方面,您可以看到net
net.layers
这是存储不同层参数的caffe向量。查看第一层(
'data'
层):
输入层没有可存储的参数。另一方面,对于第一卷积层
len(net.layers[1].blobs) # >> 2
网络存储一个blob用于过滤器权重,另一个blob用于恒定偏差。给你
net.layers[1].blobs[0].data.shape # >> (64, 3, 7, 7)
net.layers[1].blobs[1].data.shape # >> (64,)
如您所见,该层对3通道输入图像执行7x7卷积,并有64个这样的过滤器
现在,如何获得梯度?正如你所说的
diffs = net.backward(diffs=['data','conv1/7x7_s2'])
返回数据流的渐变。我们可以通过以下方式验证这一点:
np.all( diffs['data'] == net.blobs['data'].diff ) # >> True
np.all( diffs['conv1/7x7_s2'] == net.blobs['conv1/7x7_s2'].diff ) # >> True
(TL;DR)如果需要参数的梯度,这些梯度将与参数一起存储在net.layers
中:
net.layers[1].blobs[0].diff.shape # >> (64, 3, 7, 7)
net.layers[1].blobs[1].diff.shape # >> (64,)
为了帮助您在图层名称及其索引之间映射到
net.layers
vector,您可以使用net.\u layer\u names
更新有关使用梯度可视化过滤器响应的信息:
梯度通常是为标量函数定义的。损耗是一个标量,因此可以说像素/滤波器权重相对于标量损耗的梯度。此渐变是每个像素/过滤器权重的单个数字。
如果你想获得一个特定的内部隐藏节点的最大激活结果的输入,你需要一个“辅助”网络,它的损失正好是你想要可视化的特定隐藏节点激活的度量。一旦你有了这个辅助网络,你可以从一个任意的输入开始,根据辅助损耗到输入层的梯度改变这个输入:
update = prev_in + lr * net.blobs['data'].diff
太好了,谢谢!如何获得SGD用于调整的完全相同的梯度,例如
conv1
中过滤器的参数?diffs=net.backward(diffs=['loss','conv1'])
会准确地告诉我,还是caffe会在误差面下一步之前对梯度进行某种操作?权重更新的计算方式取决于解算器。对于SGD,在这一点上,如果动量不为零,它包括先前的更新,以及学习率和权重衰减。然而,根据这里的信息:(更新参数)和这里的代码:我猜diff
中存储的值是最终的重量更新。我目前正在使用solver的循环来训练我的CNN。步骤(1)
。我想在每次迭代中找到梯度,我想我可以简单地将diffs=net.backward(diffs=['loss','conv1'])
添加到该循环中,因为解算器步骤会自动向前传递。你看到它可能会干扰训练的任何原因了吗?运行net.backward()
只计算梯度并存储它们,但不更新参数,所以这应该不是问题。虽然你要跑两次后传球。是的,所以我想训练会慢一些。你知道我如何在只进行一次向后传球的训练中提取梯度吗?我找不到任何允许这样做的选项。感谢您提供的详细答案,这让我对水滴的工作原理有了更多的了解。然而,你还没有得到关于
update = prev_in + lr * net.blobs['data'].diff