GoogLenet Inception module的caffe实现

简述

GoogLenet其实网络结构不是很复杂,之所以要总结这个代码实现,主要是想看一下Inception module在caffe中是怎么实现的。通过跟踪caffe代码,对Inception module也有了更深入的理解。
本文主要总结Inception module的实现,其他网络层的实现都是以前的网络差不多。

具体实现

本文以Inception(3a)为例,简述在caffe中是怎么实现的,首先Inception(3a)的输入是前一层网络max pooling的输出,在输入到Inception(3a)之前,会由一个split_layer对数据进行分流,其实就是重新构造4个指针指向原来的数据,四个指针的值存储在top[4]中,代码实现如下:

for(int i = 0; i < top.size(); ++i)
{ top[i]->SharedData(*bottom[0]); }

数据分流过后就是对每一个数据路径执行操作,这里的数据路径及其对应的操作有
- 数据路径1:convolution(1x1,64)->ReLu
- 数据路径2:convolution(1x1,96)->ReLu->convolution(3x3,128)->ReLu
- 数据路径3:convolution(1x1,16)->ReLu->convolution(5x5,32)->ReLu
- 数据路径4:max pooling(3x3,stride 1)->convolution(1x1,32)->ReLu

等到这四个路径全部计算完成之后,会有一个对4路数据进行汇集地操作,即ConcatLayer::Forward_cpu()函数。

在原来没有看代码的时候,移位这四个路径出来的数据的维度可能不一样,后来看了代码才知道Inception(3a)出来的数据全部都是28x28的,对于3x3的卷积边沿有一个像素的补充,对于5x5的卷积边沿有两个像素的补充,对于max pooling,stride设置为1,边沿有1个像素的补充。这样就能保证四路输出维度相同。

在ConcatLayer的Forward_cpu函数中,由于四路输出维度相同,所以Forward_cpu函数所做的工作只是把数据复制到top中,这时只要注意每次复制的数据量和地址偏移值即可,代码如下;

int offset_concat_axis = 0; 
//记录各个路径写入时的地址偏移值
const int top_concat_axis = top[0]->shape(concat_axis_); 
//输出层的channels,这里为256
for(int i = 0; i < bottom.size(); ++i) // 这里bottom size为4
{
    const Dtype* bottom_data = bottom[i]->cpu_data();
    const int bottom_concat_axis = bottom[i]->shape(concat_axis_); 
    // 输入层的channels
    for(int n = 0; n < num_concats_; ++n) // num_concats: batch size
    {
        // concat_input_size_:输入数据大小28*28
        caffe_copy(bottom_concat_axis * concat_input_size_,  
                   bottom_data + n * bottom_concat_axis *
                   concat_input_size_,
                   top_data + (n * top_concat_axis + offset_concat_axis)
                   * concat_input_size_);
    }
    offset_concat_axis += bottom_concat_axis;
}

到此,Inception module在caffe中得到完整实现。

你可能感兴趣的:(Deep,Learning)