前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >caffe源码分析-inner_product_layer

caffe源码分析-inner_product_layer

作者头像
bear_fish
发布2019-02-25 11:51:30
6710
发布2019-02-25 11:51:30
举报

本文主要分析caffe inner_product_layer源码,主要内容如下:

  1. 结合使用以及proto定义介绍InnerProductLayer的参数;
  2. 简要分析Filler初始化,caffe中的layer参数,例如constantgaussian;
  3. InnerProductLayer的函数 核心LayerSetUp参数初始化, ReshapeForward_cpu以及矩阵的运算底层调用cublas运算;

1. 结合使用以及proto定义介绍InnerProductLayer的参数;

下面我们来看下全连接层InnerProductLayer, 成员变量定义如下:

代码语言:javascript
复制
template <typename Dtype>
class InnerProductLayer : public Layer<Dtype> {
public:
    explicit InnerProductLayer(const LayerParameter& param)
            : Layer<Dtype>(param) {}
protected:
    int M_; // batch size/输入样本个数
    int K_; // 输入特征长度
    int N_; // 输出神经元数量
    bool bias_term_; //是否添加偏置
    Blob<Dtype> bias_multiplier_; //偏置的乘子
    bool transpose_;  ///< if true, assume transposed weights
};

InnerProduct的常见使用示例如下:

代码语言:javascript
复制
layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "fc1"
  top: "fc2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 10
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}

2. Filler初始化,caffe中的layer参数,例如constantgaussian;

参数填充的proto定义如下:

代码语言:javascript
复制
/填充参数,设置一些初始化参数
message FillerParameter {
  // The filler type.
  optional string type = 1 [default = 'constant'];
  optional float value = 2 [default = 0]; // the value in constant filler
  optional float min = 3 [default = 0]; // the min value in uniform filler
  optional float max = 4 [default = 1]; // the max value in uniform filler
  optional float mean = 5 [default = 0]; // the mean value in Gaussian filler
  optional float std = 6 [default = 1]; // the std value in Gaussian filler
}

下面给出具体的定义,简单起见仅仅给出ConstantFiller的定义:

代码语言:javascript
复制
//在网络初始化时,根据layer的定义进行初始参数的填充。
template <typename Dtype>
class Filler {
public:
    explicit Filler(const FillerParameter& param) : filler_param_(param) {}
    virtual ~Filler() {}
    virtual void Fill(Blob<Dtype>* blob) = 0;
protected:
    FillerParameter filler_param_;
};  // class Filler

template <typename Dtype>
class ConstantFiller : public Filler<Dtype> {
public:
    explicit ConstantFiller(const FillerParameter& param)
            : Filler<Dtype>(param) {}
    virtual void Fill(Blob<Dtype>* blob) {
        Dtype* data = blob->mutable_cpu_data();
        const int count = blob->count();
        const Dtype value = this->filler_param_.value();

        for (int i = 0; i < count; ++i) {
            data[i] = value;
        }
};

根据类型获取不同的filter指针:

代码语言:javascript
复制
template <typename Dtype>
Filler<Dtype>* GetFiller(const FillerParameter& param) {
    const std::string& type = param.type();
    if (type == "constant") {
        return new ConstantFiller<Dtype>(param);
    } else if (type == "gaussian") {
        return new GaussianFiller<Dtype>(param);
    } else if (type == "uniform") {
        return new UniformFiller<Dtype>(param);
    } else if (type == "xavier") {
        return new XavierFiller<Dtype>(param);
    } else {
        CHECK(false) << "Unknown filler name: " << param.type();
    }
    return (Filler<Dtype>*)(NULL);
}

3. InnerProductLayer的函数

LayerSetUp初始化参数(读取配置初始化N, 对权重weight以及bias填充):

代码语言:javascript
复制
template<typename Dtype>
void InnerProductLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype> *> &bottom, const vector<Blob<Dtype> *> &top) {
    const int num_output = this->layer_param_.inner_product_param().num_output();
    // whether to have bias terms
    bias_term_ = this->layer_param_.inner_product_param().bias_term();
    N_ = num_output;
    //For examples, shape is (N, C, H, W),and axis == 1, K_ = C*H*W
    K_ = bottom[0]->count(axis);

    if (this->blobs_.size() > 0) {// Check if we need to set up the weights
        LOG(INFO) << "Skipping parameter initialization";
    } else {
        if (bias_term_) {this->blobs_.resize(2);} 
        else { this->blobs_.resize(1); }
        vector<int> weight_shape(2);// 权值初始化, shape size is 2 not 4
        this->blobs_[0].reset(new Blob<Dtype>(weight_shape));

        // get filter type and then fill weights
        shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>(
                this->layer_param_.inner_product_param().weight_filler()));
        weight_filler->Fill(this->blobs_[0].get());// fill the weights

        if (bias_term_) {// If necessary, intiialize and fill the bias term
            vector<int> bias_shape(1, N_);
            this->blobs_[1].reset(new Blob<Dtype>(bias_shape));
            shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>(
                    this->layer_param_.inner_product_param().bias_filler()));
            bias_filler->Fill(this->blobs_[1].get());
        }
    } // end of parameter initialization
}

Reshape函数在layer的初始化,以及修改网络的输入个数(如batch size)。

代码语言:javascript
复制
template <typename Dtype>
void InnerProductLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
                                       const vector<Blob<Dtype>*>& top) {
    const int new_K = bottom[0]->count(axis);
    CHECK_EQ(K_, new_K)
        << "Input size incompatible with inner product parameters.";
    M_ = bottom[0]->count(0, axis);  // M_就是batch size N/输入的样本个数
    vector<int> top_shape = bottom[0]->shape();  // top_shape:[N,C,H,W]

    top_shape.resize(axis + 1);// top_shape:[N,C]
    top_shape[axis] = N_;  // top_shape:[N,N_]
    top[0]->Reshape(top_shape);// 设置top的形状大小

    if (bias_term_) {// Set up the bias multiplier
        vector<int> bias_shape(1, M_);
        bias_multiplier_.Reshape(bias_shape);
        caffe_set(M_, Dtype(1), bias_multiplier_.mutable_cpu_data());
    }
}

接下来就是前向传播Forward_cpu:

代码语言:javascript
复制
template<typename Dtype>
void InnerProductLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype> *> &bottom, const vector<Blob<Dtype> *> &top) {

    const Dtype* bottom_data = bottom[0]->cpu_data();
    Dtype* top_data = top[0]->mutable_cpu_data();
    const Dtype* weight = this->blobs_[0]->cpu_data();

    // top = bottom * weight + bias (option)
    caffe_cpu_gemm<Dtype>(CblasNoTrans, transpose_ ? CblasNoTrans : CblasTrans,
                          M_, N_, K_, (Dtype)1.,
                          bottom_data, weight, (Dtype)0., top_data);
    if (bias_term_) {
        caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype)1.,
                              bias_multiplier_.cpu_data(),
                              this->blobs_[1]->cpu_data(), (Dtype)1., top_data);
    }

}

矩阵的运算底层调用的是cublas运算。

代码语言:javascript
复制
//C=alpha*A*B+beta*C
template<>
void caffe_cpu_gemm<float>(const CBLAS_TRANSPOSE TransA,
                           const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K,
                           const float alpha, const float* A, const float* B, const float beta,
                           float* C) {
    int lda = (TransA == CblasNoTrans) ? K : M;
    int ldb = (TransB == CblasNoTrans) ? N : K;
    cblas_sgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B,
                ldb, beta, C, N);
}

caffe系列源码分析介绍

本系列深度学习框架caffe 源码分析主要内容如下:

1. caffe源码分析-cmake 工程构建:

caffe源码分析-cmake 工程构建主要内容:

自己从头构建一遍工程,这样能让我更好的了解大型的项目的构建。当然原始的caffe的构建感觉还是比较复杂(主要是cmake),我这里仅仅使用cmake构建,而且简化点,当然最重要的是支持CLion直接运行调试(如果需要这个工程可以评论留下你的邮箱,我给你发送过去)。

2. caffe的数据内存分配类SyncedMemory, 以及类Blob数据传输的媒介.

主要内容:

caffe源码分析-SyncedMemory

caffe源码分析-Blob

其中Blob分析给出了其直接与opencv的图片相互转化以及操作,可以使得我们更好的理解Blob.

3. caffe layer的源码分析,包括从整体上说明了layer类别以及其proto定义与核心函数.

内容如下:

caffe源码分析-layer

caffe源码分析-ReLULayer

caffe源码分析-inner_product_layer

caffe源码分析-layer_factory

首先分析了最简单的layer Relu,然后在是inner_product_layer全连接层, 最后是layer_factorycaffe中 以此工厂模式create各种Layer.

4. 数据输入层,主要是多线程+BlockingQueue的方式读取数据训练:

内容如下:

caffe源码分析-BlockingQueue

caffe源码分析-InternalThread

caffe源码分析-DataReader

5. IO处理例如读取proto文件转化为网络,以及网络参数的序列化

内容如下:

caffe源码分析-DataTransformer

caffe源码分析-db, io

6. 最后给出了使用纯C++结合多层感知机网络训练mnist的示例

内容如下:

caffe c++示例(mnist 多层感知机c++训练,测试)

类似与caffe一样按照layer、solver、loss、net等模块构建的神经网络实现可以见下面这篇blog,相信看懂了这个python的代码理解caffe框架会更简单点.

神经网络python实现


最后如果需要**cmake** + CLion**直接运行调试**caffe**的代码工程,可以评论留下你的邮箱,我给你发送过去.**

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年10月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 结合使用以及proto定义介绍InnerProductLayer的参数;
  • 2. Filler初始化,caffe中的layer参数,例如constant, gaussian;
  • 3. InnerProductLayer的函数
  • caffe系列源码分析介绍
    • 1. caffe源码分析-cmake 工程构建:
      • 2. caffe的数据内存分配类SyncedMemory, 以及类Blob数据传输的媒介.
        • 3. caffe layer的源码分析,包括从整体上说明了layer类别以及其proto定义与核心函数.
          • 4. 数据输入层,主要是多线程+BlockingQueue的方式读取数据训练:
            • 5. IO处理例如读取proto文件转化为网络,以及网络参数的序列化
              • 6. 最后给出了使用纯C++结合多层感知机网络训练mnist的示例
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档