如何在Caffe中增加一层新的Layer呢?主要分为四步:

(1)在./src/caffe/proto/caffe.proto 中增加对应layer的paramter message;

(2)在./include/caffe/***layers.hpp中增加该layer的类的声明,***表示有common_layers.hpp,

data_layers.hpp, neuron_layers.hpp, vision_layers.hpp 和loss_layers.hpp等;

(3)在./src/caffe/layers/目录下新建.cpp和.cu(GPU)文件,进行类实现。

(4)在./src/caffe/gtest/中增加layer的测试代码,对所写的layer前传和反传进行测试,测试还包括速度。(可省略,但建议加上)

这位博主添加了一个计算梯度的网络层,简介明了:

http://blog.csdn.net/shuzfan/article/details/51322976

这几位博主增加了自定义的loss层,可供参考:

http://blog.csdn.net/langb2014/article/details/50489305

http://blog.csdn.net/tangwei2014/article/details/46815231

我以添加precision_recall_loss层来学习代码,主要是precision_recall_loss_layer.cpp的实现

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <vector>
#include <opencv2/opencv.hpp> #include "caffe/layer.hpp"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/vision_layers.hpp" namespace caffe { //初始化,调用父类进行相应的初始化
template <typename Dtype>
void PrecisionRecallLossLayer<Dtype>::LayerSetUp(
const vector<Blob<Dtype>*> &bottom, const vector<Blob<Dtype>*> &top) {
LossLayer<Dtype>::LayerSetUp(bottom, top);
}
//进行维度变换
template <typename Dtype>
void PrecisionRecallLossLayer<Dtype>::Reshape(
const vector<Blob<Dtype>*> &bottom,
const vector<Blob<Dtype>*> &top) {
//同样先调用父类的Reshape,通过成员变量loss_来改变输入维度
LossLayer<Dtype>::Reshape(bottom, top);
loss_.Reshape(bottom[]->num(), bottom[]->channels(),
bottom[]->height(), bottom[]->width()); // Check the shapes of data and label 检查两个输入的维度是否想等
CHECK_EQ(bottom[]->num(), bottom[]->num())
<< "The number of num of data and label should be same.";
CHECK_EQ(bottom[]->channels(), bottom[]->channels())
<< "The number of channels of data and label should be same.";
CHECK_EQ(bottom[]->height(), bottom[]->height())
<< "The heights of data and label should be same.";
CHECK_EQ(bottom[]->width(), bottom[]->width())
<< "The width of data and label should be same.";
}
//前向传导
template <typename Dtype>
void PrecisionRecallLossLayer<Dtype>::Forward_cpu(
const vector<Blob<Dtype>*> &bottom, const vector<Blob<Dtype>*> &top) {
const Dtype *data = bottom[]->cpu_data();
const Dtype *label = bottom[]->cpu_data();
const int num = bottom[]->num(); //num和count什么区别
const int dim = bottom[]->count() / num;
const int channels = bottom[]->channels();
const int spatial_dim = bottom[]->height() * bottom[]->width();
//存疑?
const int pnum =
this->layer_param_.precision_recall_loss_param().point_num();
top[]->mutable_cpu_data()[] = ;
//对于每个通道
for (int c = ; c < channels; ++c) {
Dtype breakeven = 0.0;
Dtype prec_diff = 1.0;
for (int p = ; p <= pnum; ++p) {
int true_positive = ; //统计每类的个数
int false_positive = ;
int false_negative = ;
int true_negative = ;

for (int i = ; i < num; ++i) {
const Dtype thresh = 1.0 / pnum * p; //计算阈值?
for (int j = ; j < spatial_dim; ++j) {
//取得相应的值和标签
const Dtype data_value = data[i * dim + c * spatial_dim + j];
const int label_value = (int)label[i * dim + c * spatial_dim + j];
//统计
if (label_value == && data_value >= thresh) {
++true_positive;
}
if (label_value == && data_value >= thresh) {
++false_positive;
}
if (label_value == && data_value < thresh) {
++false_negative;
}
if (label_value == && data_value < thresh) {
++true_negative;
}
}
}
//计算precision和recall
Dtype precision = 0.0;
Dtype recall = 0.0;
if (true_positive + false_positive > ) {
precision =
(Dtype)true_positive / (Dtype)(true_positive + false_positive);
} else if (true_positive == ) { //都是负类?
precision = 1.0;
}
if (true_positive + false_negative > ) {
recall =
(Dtype)true_positive / (Dtype)(true_positive + false_negative);
} else if (true_positive == ) {
recall = 1.0;
}
if (prec_diff > fabs(precision - recall) //如果二c者相差小
&& precision > && precision <
&& recall > && recall < ) {
breakeven = precision; //保留
prec_diff = fabs(precision - recall);
}
}
top[]->mutable_cpu_data()[] += 1.0 - breakeven; //计算误差
}
top[]->mutable_cpu_data()[] /= channels; //???
}
//反向
template <typename Dtype>
void PrecisionRecallLossLayer<Dtype>::Backward_cpu(
const vector<Blob<Dtype>*> &top,
const vector<bool> &propagate_down,
const vector<Blob<Dtype>*> &bottom) {
for (int i = ; i < propagate_down.size(); ++i) {
if (propagate_down[i]) { NOT_IMPLEMENTED; }
}
}
#ifdef CPU_ONLY
STUB_GPU(PrecisionRecallLossLayer);
#endif //注册该层
INSTANTIATE_CLASS(PrecisionRecallLossLayer);
REGISTER_LAYER_CLASS(PrecisionRecallLoss); } // namespace caffe
  1. template <typename Dtype>
  2. void PrecisionRecallLossLayer<Dtype>::Forward_cpu(
  3. const vector<Blob<Dtype>*> &bottom, const vector<Blob<Dtype>*> &top) {
  4. const Dtype *data = bottom[0]->cpu_data();
  5. const Dtype *label = bottom[1]->cpu_data();
  6. const int num = bottom[0]->num();
  7. const int dim = bottom[0]->count() / num;
  8. const int channels = bottom[0]->channels();
  9. const int spatial_dim = bottom[0]->height() * bottom[0]->width();
  10. const int pnum =
  11. this->layer_param_.precision_recall_loss_param().point_num();
  12. top[0]->mutable_cpu_data()[0] = 0;
  13. for (int c = 0; c < channels; ++c) {
  14. Dtype breakeven = 0.0;
  15. Dtype prec_diff = 1.0;
  16. for (int p = 0; p <= pnum; ++p) {
  17. int true_positive = 0;
  18. int false_positive = 0;
  19. int false_negative = 0;
  20. int true_negative = 0;
  21. for (int i = 0; i < num; ++i) {
  22. const Dtype thresh = 1.0 / pnum * p;
  23. for (int j = 0; j < spatial_dim; ++j) {
  24. const Dtype data_value = data[i * dim + c * spatial_dim + j];
  25. const int label_value = (int)label[i * dim + c * spatial_dim + j];
  26. if (label_value == 1 && data_value >= thresh) {
  27. ++true_positive;
  28. }
  29. if (label_value == 0 && data_value >= thresh) {
  30. ++false_positive;
  31. }
  32. if (label_value == 1 && data_value < thresh) {
  33. ++false_negative;
  34. }
  35. if (label_value == 0 && data_value < thresh) {
  36. ++true_negative;
  37. }
  38. }
  39. }
  40. Dtype precision = 0.0;

Caffe学习系列(15):添加新层的更多相关文章

  1. Caffe学习系列(3):视觉层(Vision Layers)及参数

    所有的层都具有的参数,如name, type, bottom, top和transform_param请参看我的前一篇文章:Caffe学习系列(2):数据层及参数 本文只讲解视觉层(Vision La ...

  2. 转 Caffe学习系列(3):视觉层(Vision Layers)及参数

    所有的层都具有的参数,如name, type, bottom, top和transform_param请参看我的前一篇文章:Caffe学习系列(2):数据层及参数 本文只讲解视觉层(Vision La ...

  3. Caffe学习系列(2):数据层及参数

    要运行caffe,需要先创建一个模型(model),如比较常用的Lenet,Alex等, 而一个模型由多个屋(layer)构成,每一屋又由许多参数组成.所有的参数都定义在caffe.proto这个文件 ...

  4. 转 Caffe学习系列(2):数据层及参数

    http://www.cnblogs.com/denny402/p/5070928.html 要运行caffe,需要先创建一个模型(model),如比较常用的Lenet,Alex等, 而一个模型由多个 ...

  5. Caffe学习系列(15):计算图片数据的均值

    图片减去均值后,再进行训练和测试,会提高速度和精度.因此,一般在各种模型中都会有这个操作. 那么这个均值怎么来的呢,实际上就是计算所有训练样本的平均值,计算出来后,保存为一个均值文件,在以后的测试中, ...

  6. Caffe学习系列(4):激活层(Activiation Layers)及参数

    在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的.从bottom得到一个blob数据输入,运算后,从top输入一个blob数据.在运算过程中,没有改变数据的大小,即输入 ...

  7. 转 Caffe学习系列(4):激活层(Activiation Layers)及参数

    在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的.从bottom得到一个blob数据输入,运算后,从top输入一个blob数据.在运算过程中,没有改变数据的大小,即输入 ...

  8. Caffe 学习系列

    学习列表: Google protocol buffer在windows下的编译 caffe windows 学习第一步:编译和安装(vs2012+win 64) caffe windows学习:第一 ...

  9. Caffe学习系列(23):如何将别人训练好的model用到自己的数据上

    caffe团队用imagenet图片进行训练,迭代30多万次,训练出来一个model.这个model将图片分为1000类,应该是目前为止最好的图片分类model了. 假设我现在有一些自己的图片想进行分 ...

随机推荐

  1. python实现软件的注册功能(机器码+注册码机制)

    http://www.cnblogs.com/cquptzzq/p/5940583.html 一.前言: 目的:完成已有python图像处理工具的注册功能 功能:用户运行程序后,通过文件自动检测认证状 ...

  2. Linux下Memcache 安装和使用

    Memcached是一种高性能的分布式内存对象缓存系统(memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能,其“分布式”由客户端函数库完成,成熟算法的为一致性Hash),用 ...

  3. Spot光照资料

    http://forums.autodesk.com/t5/FBX-SDK/EmissiveFactor-AmbientFactor-DiffuseFactor/td-p/4230572http:// ...

  4. cdn提供商

    七牛,又拍 http://www.qiniu.com/ https://www.upyun.com/index.html

  5. Docker学习笔记 — 配置国内免费registry mirror

    Docker学习笔记 — 配置国内免费registry mirror Docker学习笔记 — 配置国内免费registry mirror

  6. Python之路【第四篇】:模块

    什么是模块: 模块就是一个功能的集合. 模块就和乐高积木差不多,你用这些模块组合出一个模型,然后也可以用这个模块加上其他的模块组合成一个新的模型 模块的种类: 1.内置模块(python自带的比如os ...

  7. Yii2提交表单提示无法验证

    yii2使用gii生成的搜索视图里的表单使用的是get方式,我改为post就提示无法验证,以为是控制器默认访问是get,实际默认是get和post都可以 public function behavio ...

  8. Java数据结构 遍历 排序 查找 算法实现

    请查看:http://blog.csdn.net/zhanghao_hulk/article/details/35372571#t13

  9. 调整Linux磁盘分区的大小的方法

      昨天数据入库时,一直报错,说磁盘满了,,df -h    一看,发现/目录下只有50G空间,已使用49G:我的程序和dbss都安装在/目录下,ftp到的数据放在/data下的一个子目录下,分解完的 ...

  10. 10个基础的linux网络和监控命令

    配置zookeeper集群时,需要查看本机ip,输入命令 hostname -i   就会只显示主机ip, 下边搜了一篇常用的    命令,闲的时候多敲敲命令,以便用的时候再找! 我下面列出来的10个 ...