如何在caffe

时间:2016-07-31 02:50:18

标签: deep-learning caffe convolution

在caffe中,convolution图层采用一个底部blob,并将其与学习过滤器(使用权重类型初始化 - “Xavier”,“MSRA”等)进行卷积。但是,我的问题是我们是否可以简单地卷积两个底部blob并产生一个顶部blob。这样做最优雅的方式是什么?这样做的目的是:底部blob中的一个将是data,另一个将是先前图层生成的动态过滤器(根据data而变化)(我正在尝试实现{{ 3}})。

我的尝试:

我想到的一种方法是修改filler.hpp并将底部blob指定为filler矩阵本身(而不是“Xavier”,“MSRA”等)。然后我认为卷积层会从那里拾取。我们可以设置lr = 0以指示不应更改由我们的自定义填充程序初始化的权重。但是,在我查看源代码后,我仍然不知道该怎么做。另一方面,我不想打破caffe的工作流程。如果我想要它们,我仍然希望转换层正常运行。

显然,一种更乏味的方法是使用Slicetile和/或Scale图层的组合来逐字实现卷积。我认为它会起作用,但结果会很混乱。还有其他想法吗?

修改1:

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

  1. weight blob对所有样本都具有相同的值。对于不同的样本,它将具有不同的值。所以我改变了第32行:
  2. 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,组总是1等。但是,当我测试前进传球时,它给了我一些奇怪的回答(使用简单的卷积内核= np.ones((1,1,3,3))。对于这个内核,学习率设置为零,这样它就不会改变。但是,我无法得到正确答案。任何建议都将受到赞赏。< / p>

    请不要使用Slice, Eltwise, Crop等现有图层提出解决方案。我已经实现了 - 它的工作原理 - 但它复杂且内存效率低得令人难以置信。

1 个答案:

答案 0 :(得分:8)

我认为你的整体方式是正确的。

对于&#34;奇怪的&#34;卷积结果,我猜这个错误很可能是:

考虑2D卷积

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

因为caffe中的卷积是作为2矩阵的乘法执行的,weight(代表卷积内核)和col_buffer(从要卷积的数据重新组织),{{1} }是weight行和num_out列,channels / this->group_ * kernel_h * kernel_wcol_buffer行和channels / this->group_ * kernel_h * kernel_w列,因此是height_out * width_out动态卷积的blob图层,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_);

因此,您使用的4维bottom[0]->shape(0) == bottom[1]->shape(0) == num bottom[0]->count(1) == num_out * channels / this->group_ * kernel_h * kernel_w 的简单卷积内核可能无法满足上述条件并导致错误的卷积结果

希望它清楚并且会帮助你。

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

我添加了动态卷积层here但尚未进行单元测试。该层不会破坏caffe的工作流程,只会更改BaseConvolution类的某些私有成员以进行保护。

涉及的文件是:

np.ones((1,1,3,3))

include/caffe/layers/dyn_conv_layer.hpp,base_conv_layer.hpp src/caffe/layers/dyn_conv_layer.cpp(cu) 中的卷积层几乎相同,差别主要在于:

  1. 覆盖函数caffe以正确初始化LayerSetUp()this->kernel_dim_等以进行卷积,并忽略初始化卷积层常用的this->weight_offset_以包含权重和偏差;
  2. 重写函数this->blobs_以检查作为内核容器的Reshape()是否具有正确的卷积形状。
  3. 因为我没时间测试它,可能会有错误,我很高兴看到你的反馈。

    ########## Update 2,Oct 12th,2016,Beijing time ##########

    我刚刚更新了dynamic convolution的测试用例。涉及的文件是bottom[1]。它似乎工作正常,但可能需要更彻底的测试。

    您可以src/caffe/test/test_dyn_convolution_layer.cppcd $CAFFE_ROOT/build && ccmake ..cmake -DBUILD_only_tests="dyn_convolution_layer" ..来构建此咖啡馆。