2016-07-31 63 views
12

在caffe中,convolution图层取一个底部斑点,并使用学习滤波器(使用权重类型 - “Xavier”,“MSRA”等初始化)卷积它。但是,我的问题是,我们是否可以简单地将两个底层斑点进行卷积并产生顶层斑点。这样做最优雅的方式是什么?这样做的目的是:底部blob之一将是data,另一个将是由以前的图层(我试图实现dynamic convolution)生成的动态筛选器(取决于data)。如何在caffe中卷积两个斑点

我尝试:

的一种方法,其来到了我的脑海里是修改filler.hpp并分配一个底部BLOB作为filler矩阵本身(而不是“泽维尔”,“MSRA”等)。然后我认为卷积层会从那里接收。我们可以设置lr = 0来表明我们的自定义填充程序初始化的权重不应该改变。但是,在查看源代码之后,我仍然不知道该怎么做。另一方面,我不想打破caffe的工作流程。如果我希望它们能够正常工作,我仍然希望conv图层正常工作。

很显然,一个更繁琐的方法是使用Slice,tile和/或Scale层的组合来字面地实现卷积。我认为它会起作用,但它会变得混乱。任何其他想法?

编辑1:

我通过修改CAFFE的卷积层写一个新层。特别是,在src/caffe/layers/conv_layer.cpp的第27行中,它采用由filler定义的权重,并将其与底部斑点进行卷积。因此,我不是从filler填充那个blob,而是修改了这个图层,使它现在需要两个底部。底部的一个直接被分配给填充物。现在,我不得不做一些其他更改,如:

  1. weight blob具有相同的值为所有样品。这里对不同的样品会有不同的值。因此,我改变行32:
this->forward_cpu_gemm(
    bottom_data + n * this->bottom_dim_, 
    weight, 
    top_data + n * this->top_dim_); 

到:

this->forward_cpu_gemm(
    bottom_data + n * bottom[1]->count(1), 
    bottom[0]->cpu_data() + n * bottom[0]->count(1), 
    top_data + n * this->top_dim_); 

为了方便起见,我认为不涉及偏差项,步幅始终为1,填充可以始终为0 ,group总是1等。然而,当我测试正向传递时,它给了我一些奇怪的答案(简单的卷积核= np.ones((1,1,3,3))。这个内核的学习速率被设置为0,所以它不会改变。但是,我不能得到正确的答案。任何建议将不胜感激。

请不要提出使用现有层的解决方案,例如Slice, Eltwise, Crop。我已经实施 - 它的工作 - 但它是令人难以置信的复杂和内存效率低下。

+2

我读过“如何说服咖啡里的两个金发女郎”:\ – Elazar

+0

@Elazar所以这就是为什么你倒票? (只是开个玩笑):P –

回答

7

我觉得你整体上是对的。

对于“怪异”的卷积的结果,我想这个错误最可能是:

考虑二维卷积

,并假设bottom[1]的形状为(num, channels, height, width)

因为caffe卷积执行作为2矩阵的乘法,weight(表示卷积核)和col_buffer(从要被卷积的数据重组),并且weightnum_out行和channels/this->group_ * kernel_h * kernel_w列,col_bufferchannels/this->group_ * kernel_h * kernel_w行和height_out * width_out列,所以作为weight斑点动态卷积层,bottom[0]的形状最好是(num, num_out, channels/group, kernel_h, kernel_w)满足

bottom[0]->count(1) == num_out * channels/this->group_ * kernel_h * kernel_w 

,其中num_out是动态卷积的数量图层的输出功能地图。

这意味着,为了使卷积功能

this->forward_cpu_gemm(bottom_data + n * bottom[1]->count(1) 
        , bottom[0]->cpu_data() + n * bottom[0]->count(1) 
        , top_data + n * this->top_dim_); 

正常工作,您必须确保

bottom[0]->shape(0) == bottom[1]->shape(0) == num 
bottom[0]->count(1) == num_out * channels/this->group_ * kernel_h * kernel_w 

所以最有可能你使用的4维np.ones((1,1,3,3))的简单卷积内核可能不满足上述条件并导致错误的卷积结果

希望它是明确的,并会帮助你。

##########更新1,二零一六年十月十日,北京时间##########

我添加一个动态卷积层here但没有单元测试呢。这一层不会破坏caffe的工作流程,只会改变一些BaseConvolution类的私有成员来保护。

涉及的文件有:

include/caffe/layers/dyn_conv_layer.hpp,base_conv_layer.hpp 
src/caffe/layers/dyn_conv_layer.cpp(cu) 

它生长几乎与caffe卷积层相同,差异主要有:

  1. 覆盖功能LayerSetUp()初始化this->kernel_dim_this->weight_offset_等正确地进行卷积并且忽略卷积层常规使用的初始化this->blobs_以包含重量和偏差;
  2. 重写函数Reshape()以检查bottom[1]作为内核容器是否具有适合卷积的形状。

因为我没有时间测试它,所以可能会有错误,我会很高兴看到您的反馈。

##########更新2,2016年10月12日,北京时间##########

我更新测试用例dynamic convolution刚才。涉及的文件是src/caffe/test/test_dyn_convolution_layer.cpp。它似乎工作正常,但可能需要更彻底的测试。

您可以通过​​,cmake -DBUILD_only_tests="dyn_convolution_layer" ..make runtest来检查它。

+0

我会在接下来的3-4天内尝试这个,并让你知道结果。谢谢! –

+1

您应该非常注意函数BaseConvolutionLayer :: LayerSetUp(),因为forward_cpu_gemm()中使用的许多变量都在那里初始化。 @ ParagS.Chandakkar – Dale

+0

我想当你有两个底部斑点时,你可以忽略卷积参数设置内核大小和过滤器数量。这些值应该从“权重”块中推导出来。你也可以考虑第三个输入blob的偏差项... – Shai