Par*_*kar 13 convolution deep-learning caffe
在caffe中,该convolution图层采用一个底部blob,并将其与学习过滤器(使用权重类型初始化 - "Xavier","MSRA"等)进行卷积.但是,我的问题是我们是否可以简单地卷入两个底部blob并产生一个顶部blob.这样做最优雅的方式是什么?这样做的目的是:其中一个底部blob将是data另一个将是一个动态过滤器(根据data前所未有的变化)(我正在尝试实现动态卷积).
我的尝试:
我想到的一种方法是修改filler.hpp并将底部blob指定为filler矩阵本身(而不是"Xavier","MSRA"等).然后我认为卷积层会从那里拾取.我们可以设置lr = 0为表示不应更改由我们的自定义填充程序初始化的权重.但是,在我查看源代码后,我仍然不知道该怎么做.另一方面,我不想打破caffe的工作流程.如果我想要它们,我仍然希望转换层正常运行.
显然,一个比较繁琐的方法是使用的组合Slice,tile和/或Scale层字面上实施卷积.我认为它会起作用,但结果会很混乱.还有其他想法吗?
编辑1:
我通过修改caffe的卷积层写了一个新图层.特别地src/caffe/layers/conv_layer.cpp,在第27行,它采用由其定义的权重filler并将其与底部blob卷积.因此filler,我修改了图层,使其现在需要两个底部,而不是从中填充该blob .其中一个底部直接分配给填充符.现在我不得不做一些其他改动,例如:
weightblob对于所有样本具有相同的值.对于不同的样本,它将具有不同的值.所以我改变了第32行:this->forward_cpu_gemm(
bottom_data + n * this->bottom_dim_,
weight,
top_data + n * this->top_dim_);
Run Code Online (Sandbox Code Playgroud)
至:
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_);
Run Code Online (Sandbox Code Playgroud)
为了方便起见,我假设没有涉及偏见项,步幅总是1,填充总是0,组总是1等等.但是,当我测试前向传球时,它给了我一些奇怪的答案(带一个简单的卷积内核= np.ones((1,1,3,3)).这个内核的学习率设置为零,这样它就不会改变.但是,我无法得到正确答案.任何建议都将受到赞赏.
请不要使用现有的层来提出解决方案Slice, Eltwise, Crop.我已经实现了 - 它的工作原理 - 但它复杂且内存效率低得令人难以置信.
我认为你作为一个整体正确的方式.
对于"奇怪的"卷积结果,我猜这个bug最有可能是:
考虑2D卷积
假设bottom[1]的形状是(num, channels, height, width),
因为卷积输入caffe是作为2个矩阵的乘法weight(表示卷积核)和col_buffer(从要卷积的数据重新组织)执行的,并且weight是num_out行和channels / this->group_ * kernel_h * kernel_w列,col_buffer是channels / this->group_ * kernel_h * kernel_w行和height_out * width_out列,所以作为weight动态卷积层的块,bottom[0]' s形状应该更好(num, num_out, channels/group, kernel_h, kernel_w)地满足
bottom[0]->count(1) == num_out * channels / this->group_ * kernel_h * kernel_w
Run Code Online (Sandbox Code Playgroud)
,其中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_);
Run Code Online (Sandbox Code Playgroud)
工作正常,你必须确保
bottom[0]->shape(0) == bottom[1]->shape(0) == num
bottom[0]->count(1) == num_out * channels / this->group_ * kernel_h * kernel_w
Run Code Online (Sandbox Code Playgroud)
所以很可能np.ones((1,1,3,3))你使用的4维简单卷积核可能不满足上述条件并导致错误的卷积结果.
希望它清楚,并会帮助你.
########## 2016年10月10日更新1,北京时间##########
我在这里添加了一个动态卷积层,但还没有进行单元测试.该层不会破坏caffe的工作流程,只会更改BaseConvolution类的某些私有成员以进行保护.
涉及的文件是:
include/caffe/layers/dyn_conv_layer.hpp,base_conv_layer.hpp
src/caffe/layers/dyn_conv_layer.cpp(cu)
Run Code Online (Sandbox Code Playgroud)
它与卷积层的增长几乎相同,caffe差异主要是:
LayerSetUp()初始化this->kernel_dim_,this->weight_offset_等等适当地进行卷积并忽略初始化this->blobs_用于由卷积层通常含有重量和偏压;Reshape()以检查bottom[1]作为内核容器的卷积是否具有正确的形状.因为我没时间测试它,可能会有错误,我很高兴看到你的反馈.
########## 2016年10月12日更新时间2,北京时间##########
我刚刚更新了动态卷积的测试用例.涉及的文件是src/caffe/test/test_dyn_convolution_layer.cpp.它似乎工作正常,但可能需要更彻底的测试.
你可以建立这种朱古力通过cd $CAFFE_ROOT/build && ccmake ..,cmake -DBUILD_only_tests="dyn_convolution_layer" ..并make runtest检查它.
| 归档时间: |
|
| 查看次数: |
1227 次 |
| 最近记录: |