一、include/caffe/layer.hpp 点击此处返回总目录
二、src/caffe/layer.cpp
一、layer.hpp
Layer头文件位于include/caffe/layer.hpp中。内容如下:
#ifndef CAFFE_LAYER_H_
#define CAFFE_LAYER_H_
#include <algorithm>
#include <string>
#include <vector>
#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/layer_factory.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/math_functions.hpp"
/**
Forward declare boost::thread instead of including boost/thread.hpp
to avoid a boost/NVCC issues (#1009, #1010) on OSX.
*/
之前有一个boost/NVCC的问题,这个是GitHub上的1009和1010号问题。这个问题通过声明boost::thread代替boost/thread.hpp来解决了。有兴趣可以自己看一下。
namespace boost { class mutex; } //在boost里面定义了一个类,但是什么也没做。这个可能是跟上面的问题有关,我们不做研究。
namespace caffe {
/**
* @brief An interface for the units of computation which can be composed into a
* Net.
*
* Layer%s must implement a Forward function, in which they take their input
* (bottom) Blob%s (if any) and compute their output Blob%s (if any).
* They may also implement a Backward function, in which they compute the error
* gradients with respect to their input Blob%s, given the error gradients with
* their output Blob%s.
*/
计算单元可以连接成网络,Layer就是这些计算单元的接口。
Layer类的子类必须实现Forward函数,Forward函数接受输入Blob,计算输出Blob。
Layrer类的子类也可能实现反向传播函数,从输入的Blob计算梯度误差,然后把梯度误差给输出的Blob。也可能不需要实现反向传播函数。
template <typename Dtype> //Dtype就是区分double和float的。
class Layer {
public:
/**
* You should not implement your own constructor. Any set up code should go
* to SetUp(), where the dimensions of the bottom blobs are provided to the
* layer.
*/
explicit Layer(const LayerParameter& param) //这里声明了一下构造函数,不能被隐式地调用。显示构造函数。作用是:从LayerParameter对象中加载配置。
: layer_param_(param), is_shared_(false) { //初始化列表
// Set phase and copy blobs (if there are any). //第一件事就是从参数里面设置phase,并且如果有blob的话就拷贝blob
phase_ = param.phase(); //设置当前阶段(train/test)
if (layer_param_.blobs_size() > 0) { //把上面一层和下面一层的blob都拷贝进来。
blobs_.resize(layer_param_.blobs_size()); //按layer_param_设置本身Blob对象个数,并依次将每个Blob对象尺寸调整为与layer_param_中的Blob尺寸一致
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
blobs_[i].reset(new Blob<Dtype>());
blobs_[i]->FromProto(layer_param_.blobs(i));
}
}
}
virtual ~Layer() {} //虚析构函数。析构函数也是需要你在子类中实现的。
/**
* @brief Implements common layer setup functionality.
*
* @param bottom the preshaped input blobs
* @param top
* the allocated but unshaped output blobs, to be shaped by Reshape
*
* Checks that the number of bottom and top blobs is correct.
* Calls LayerSetUp to do special layer setup for individual layer types,
* followed by Reshape to set up sizes of top blobs and internal buffers.
* Sets up the loss weight multiplier blobs for any non-zero loss weights.
* This method may not be overridden.
*/
配置函数,实现常用层的配置功能。参数bottom是已经预分配形状的blobs,就是说形状已经定义好了。参数top是已经分配但是还没有没有确定形状的blobs。也就是说,输入的形状是固定的,输出的形状是不固定的。输出是要根据输入和这一层的一些参数来决定的,比如卷积层要根据卷积核长度,有没有padding等来确定。
第一步,检查上一层和下一层的blobs数目对不对。
第二步,调用LayerSetup()函数对不同类型的层使用不同的setup方法。
第三步,根据我们算的形状把top的blob的大小设置好,还有一些内部的缓存空间也设置好。
第四步,设置损失权值因子blobs。
SetUp这个函数就不要重写它了。我们严格来遵守这个原则,如果想实现就实现里面的具体的函数,但是这个总的大纲就不要动。
void SetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
InitMutex();
CheckBlobCounts(bottom, top); //第一步,检查Blob
LayerSetUp(bottom, top); //第二步,与层相关的配置过程
Reshape(bottom, top); //第三步,对top blob变形
SetLossWeights(top); //第四步,设置损失权值因子Blob
}
/**
* @brief Does layer-specific setup: your layer should implement this function
* as well as Reshape.
*
* @param bottom
* the preshaped input blobs, whose data fields store the input data for
* this layer
* @param top
* the allocated but unshaped output blobs
*
* This method should do one-time layer specific setup. This includes reading
* and processing relevent parameters from the <code>layer_param_</code>.
* Setting up the shapes of top blobs and internal buffers should be done in
* <code>Reshape</code>, which will be called before the forward pass to
* adjust the top blob sizes.
*/
LayerSetUp()函数做了特定类型层相关的设置。自己的层应该实现这个函数和下面的Reshape()函数。
这里就定义了一个虚函数,就一个声明,什么也没干,就是要让你继承并实现它。这里声明了,就必须要实现它。
参数bottom是输入的blob。
参数top是输出的blob。没有分配形状。