寻找关于输入的 Caffe conv-filter 的梯度
Finding gradient of a Caffe conv-filter with regards to input
我需要找到关于卷积神经网络 (CNN) 中单个卷积滤波器的输入层的梯度,以此作为 visualize the filters。
在 Caffe such as the one in this example 的 Python 接口中给定一个经过训练的网络,我如何才能找到 conv-filter 相对于输入层中数据的梯度?
编辑:
基于,我添加了下面的代码。我的输入层的维度是 [8, 8, 7, 96]
。我的第一个转换层 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-filter 相对于输入层中数据的梯度,这是另外一回事。我怎样才能做到这一点?
当您 运行 backward()
通过时,您可以获得任何层的渐变。调用函数时只需指定图层列表。根据数据层显示梯度:
net.forward()
diffs = net.backward(diffs=['data', 'conv1'])`
data_point = 16
plt.imshow(diffs['data'][data_point].squeeze())
在某些情况下,您可能希望强制所有层向后执行,请查看模型的force_backward
参数。
https://github.com/BVLC/caffe/blob/master/src/caffe/proto/caffe.proto
Caffe 网络处理两个 "streams" 的数字。
第一个是数据 "stream":通过网络推送的图像和标签。随着这些输入通过网络进行,它们被转换为高级表示,并最终转换为 class 概率向量(在 class 化任务中)。
第二个 "stream" 包含不同层的参数、卷积的权重、偏差等。这些 numbers/weights 在网络的训练阶段被改变和学习。
尽管这两个 "streams" 发挥的作用根本不同,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
保存第一个数据流,它的形状与输入图像的形状匹配,直到生成 class 概率向量。
另一方面,您可以看到net
的另一个成员
net.layers
这是一个存储不同层参数的caffe向量。
查看第一层('data'
层):
len(net.layers[0].blobs) # >> 0
输入层没有要存储的参数。
另一方面,对于第一个卷积层
len(net.layers[1].blobs) # >> 2
网络存储一个 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'])
Returns data 流的梯度。我们可以通过
验证这一点
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
向量中,您可以使用 net._layer_names
。
更新 关于使用梯度可视化滤波器响应:
通常为 scalar 函数定义梯度。损失是一个标量,因此你可以说 pixel/filter 权重相对于标量损失的梯度。此梯度是每个 pixel/filter 权重的单个数字。
如果你想获得最大激活 特定 内部隐藏节点的输入,你需要一个 "auxiliary" 网络,其损失恰好是对特定激活的度量要可视化的隐藏节点。一旦你有了这个辅助网络,你就可以从任意输入开始,根据输入层的辅助损失的梯度改变这个输入:
update = prev_in + lr * net.blobs['data'].diff
我需要找到关于卷积神经网络 (CNN) 中单个卷积滤波器的输入层的梯度,以此作为 visualize the filters。
在 Caffe such as the one in this example 的 Python 接口中给定一个经过训练的网络,我如何才能找到 conv-filter 相对于输入层中数据的梯度?
编辑:
基于[8, 8, 7, 96]
。我的第一个转换层 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-filter 相对于输入层中数据的梯度,这是另外一回事。我怎样才能做到这一点?
当您 运行 backward()
通过时,您可以获得任何层的渐变。调用函数时只需指定图层列表。根据数据层显示梯度:
net.forward()
diffs = net.backward(diffs=['data', 'conv1'])`
data_point = 16
plt.imshow(diffs['data'][data_point].squeeze())
在某些情况下,您可能希望强制所有层向后执行,请查看模型的force_backward
参数。
https://github.com/BVLC/caffe/blob/master/src/caffe/proto/caffe.proto
Caffe 网络处理两个 "streams" 的数字。
第一个是数据 "stream":通过网络推送的图像和标签。随着这些输入通过网络进行,它们被转换为高级表示,并最终转换为 class 概率向量(在 class 化任务中)。
第二个 "stream" 包含不同层的参数、卷积的权重、偏差等。这些 numbers/weights 在网络的训练阶段被改变和学习。
尽管这两个 "streams" 发挥的作用根本不同,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
保存第一个数据流,它的形状与输入图像的形状匹配,直到生成 class 概率向量。
另一方面,您可以看到net
net.layers
这是一个存储不同层参数的caffe向量。
查看第一层('data'
层):
len(net.layers[0].blobs) # >> 0
输入层没有要存储的参数。
另一方面,对于第一个卷积层
len(net.layers[1].blobs) # >> 2
网络存储一个 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'])
Returns data 流的梯度。我们可以通过
验证这一点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
向量中,您可以使用 net._layer_names
。
更新 关于使用梯度可视化滤波器响应:
通常为 scalar 函数定义梯度。损失是一个标量,因此你可以说 pixel/filter 权重相对于标量损失的梯度。此梯度是每个 pixel/filter 权重的单个数字。
如果你想获得最大激活 特定 内部隐藏节点的输入,你需要一个 "auxiliary" 网络,其损失恰好是对特定激活的度量要可视化的隐藏节点。一旦你有了这个辅助网络,你就可以从任意输入开始,根据输入层的辅助损失的梯度改变这个输入:
update = prev_in + lr * net.blobs['data'].diff