caffe accuracy层以及blob的梳理

原创 2016年12月31日 22:21:37

基础概念

blob的reshape

reshape接收的是一个vector的参数,目的是要给这个blob分配相应的内存空间。这个vector参数,表示了不同的维度,一般就是N*C*H*W,如[0]表示N,[1]表示C,等。
直观的解析就是:有N张图,每张图有C个channel,每张图的大小是H*W,如果每个像素都是float类型,那么,
计算总共有多少像素(元素)的公式就是:N*C*H*W,就是blob的count的值。
计算用来存储这批数据的blob所需的内存的大小为:N*C*H*W*sizeof(float)。
相关源码:

template <typename Dtype>
void Blob<Dtype>::Reshape(const int num, const int channels, const int height,
    const int width) {
  vector<int> shape(4);
  shape[0] = num;
  shape[1] = channels;
  shape[2] = height;
  shape[3] = width;
  Reshape(shape);
}

template <typename Dtype>
void Blob<Dtype>::Reshape(const vector<int>& shape) {
  CHECK_LE(shape.size(), kMaxBlobAxes);
  count_ = 1;
  shape_.resize(shape.size());
  if (!shape_data_ || shape_data_->size() < shape.size() * sizeof(int)) {
    shape_data_.reset(new SyncedMemory(shape.size() * sizeof(int)));
  }
  int* shape_data = static_cast<int*>(shape_data_->mutable_cpu_data());
  for (int i = 0; i < shape.size(); ++i) {
    CHECK_GE(shape[i], 0);
    if (count_ != 0) {
      CHECK_LE(shape[i], INT_MAX / count_) << "blob size exceeds INT_MAX";
    }
    count_ *= shape[i];  //累计count的数量,记住是N*C*H*W这样计算总共有多少元素
    shape_[i] = shape[i]; //同时记住各维度的大小
    shape_data[i] = shape[i];
  }
  if (count_ > capacity_) {
    capacity_ = count_;
    data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype))); //如果reshape的大小比以前的大,要重新分配空间
    diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
  }
}

blob的count函数

caffe中表示数据都是以N*C*H*W这4个维度来表示的,count函数用来计算某些范围的大小。

/**
   * @brief Compute the volume of a slice; i.e., the product of dimensions
   *        among a range of axes.
   *
   * @param start_axis The first axis to include in the slice.
   *
   * @param end_axis The first axis to exclude from the slice.
   */
  inline int count(int start_axis, int end_axis) const {
    CHECK_LE(start_axis, end_axis);
    CHECK_GE(start_axis, 0);
    CHECK_GE(end_axis, 0);
    CHECK_LE(start_axis, num_axes());
    CHECK_LE(end_axis, num_axes());
    int count = 1;
    for (int i = start_axis; i < end_axis; ++i) {
      count *= shape(i);
    }
    return count;
  }

caffe源码中的accuracy_layer.cpp的相关梳理

首先明确accuracy层的功能。
accuracy层是通过对比预测的结果与输入的label,通过统计预测正确的数量与总共要预测的数量的比值得到的。
accuracy层需要两个输入源,一个是经过网络预测的数值,另一个是最开始输入的label至,分别对应了bottom[0]和bottom[1].
对于一批输入N*C*H*W来说,图像表示为:
这里写图片描述

AccuracyLayer的Reshape函数分析

template <typename Dtype>
void AccuracyLayer<Dtype>::Reshape(
  const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  CHECK_LE(top_k_, bottom[0]->count() / bottom[1]->count())
      << "top_k must be less than or equal to the number of classes.";
  label_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.accuracy_param().axis()); //label_axis默认是1(查看caffe.probo文件)
  outer_num_ = bottom[0]->count(0, label_axis_); //结合上图,该outer_num是N
  inner_num_ = bottom[0]->count(label_axis_ + 1); //结合上图,该inner_num是H*W
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if label axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";                      
//上面的check表示的意思为:
//先结合上图理解outer_num与inner_num的数量,以及bottom[1]的结构。
//如果C表示的是预测的种类的数量(就是label有多少种),那么label的数量有多少?
//就是N*H*W,一个输入是H*W大,对于H*W的每个元素都有一个label值,所以,一个输入就会有H*W个label,
//N个输入(一批),就会有N*H*W个label数量。
//很多网络最后一层都是全连接层,即一张h*w的图片进去,到最后就成为了一列单个的元素,N张图进去就是变成N列(计算上来说),
//所以一般输入给accuracy层的bottom[0]都是N*C*1*1.
//对于分类来说,这个特别好理解,每张图片对应一个label,那么就会有N个label
  vector<int> top_shape(0);  // Accuracy is a scalar; 0 axes.
  top[0]->Reshape(top_shape);
  if (top.size() > 1) {
    // Per-class accuracy is a vector; 1 axes.
    vector<int> top_shape_per_class(1);
    top_shape_per_class[0] = bottom[0]->shape(label_axis_);
    top[1]->Reshape(top_shape_per_class);
    nums_buffer_.Reshape(top_shape_per_class);
  }
}

AccuracyLayer的Forward_cpu函数分析

template <typename Dtype>
void AccuracyLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  Dtype accuracy = 0;
  const Dtype* bottom_data = bottom[0]->cpu_data();
  const Dtype* bottom_label = bottom[1]->cpu_data();
  const int dim = bottom[0]->count() / outer_num_;
  const int num_labels = bottom[0]->shape(label_axis_);
  vector<Dtype> maxval(top_k_+1);
  vector<int> max_id(top_k_+1);
  if (top.size() > 1) {
    caffe_set(nums_buffer_.count(), Dtype(0), nums_buffer_.mutable_cpu_data());
    caffe_set(top[1]->count(), Dtype(0), top[1]->mutable_cpu_data());
  }
  int count = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; ++j) {
      const int label_value =
          static_cast<int>(bottom_label[i * inner_num_ + j]);
      if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }
      if (top.size() > 1) ++nums_buffer_.mutable_cpu_data()[label_value];
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, num_labels);
      // Top-k accuracy
      std::vector<std::pair<Dtype, int> > bottom_data_vector;
      for (int k = 0; k < num_labels; ++k) {
        bottom_data_vector.push_back(std::make_pair(
            bottom_data[i * dim + k * inner_num_ + j], k));
      }
      std::partial_sort(
          bottom_data_vector.begin(), bottom_data_vector.begin() + top_k_,
          bottom_data_vector.end(), std::greater<std::pair<Dtype, int> >());
      // check if true label is in top k predictions
      for (int k = 0; k < top_k_; k++) {
        if (bottom_data_vector[k].second == label_value) {
          ++accuracy;
          if (top.size() > 1) ++top[1]->mutable_cpu_data()[label_value];
          break;
        }
      }
      ++count;
    }
  }

  // LOG(INFO) << "Accuracy: " << accuracy;
  top[0]->mutable_cpu_data()[0] = accuracy / count;
  if (top.size() > 1) {
    for (int i = 0; i < top[1]->count(); ++i) {
      top[1]->mutable_cpu_data()[i] =
          nums_buffer_.cpu_data()[i] == 0 ? 0
          : top[1]->cpu_data()[i] / nums_buffer_.cpu_data()[i];
    }
  }
  // Accuracy layer should not be used as a loss function.
}
版权声明:本文为博主原创文章,欢迎转载!转载请写明原文链接出处!

caffe学习小问题(1):caffe中的Accuracy

今天才偶然发现,caffe在计算Accuravy时,利用的是最后一个全链接层的输出(不带有acitvation function),比如:alexnet的train_val.prototxt、caff...
  • tina_ttl
  • tina_ttl
  • 2016年06月01日 16:16
  • 11183

caffe accuracy 学习

首先我们先看一下accuracy (在caffe.proto里面)的类定义 message AccuracyParameter {   // When computing accuracy, coun...
  • u012235274
  • u012235274
  • 2016年04月22日 15:55
  • 4279

利用caffe中自带的工具来可视化loss 和accuracy

以前只是一股脑的训练,却很少注意到这些,今天仔细研究了下,发现caffe自带技能包.方法如下: 1训练,和以前略有不同的是,./XX.sh|& tee xx.log,保证在caffe-master目录...
  • cwt19902010
  • cwt19902010
  • 2015年12月01日 20:28
  • 4370

caffe 进行自己的imageNet训练分类:loss一直是87.3365,accuracy一直是0

caffe 进行自己的imageNet训练分类:loss一直是87.3365,accuracy 一直是0,可能的原因是: 标签的问题: imagelist中,图像分类的标签label一定要从0开...
  • hyqsong
  • hyqsong
  • 2016年07月17日 17:11
  • 6811

梳理caffe代码layer(五)

caffe中的layer层代码比较多,各种抽象。layer这个类可以说是里面最终的一个基本类了,深度网络呢就是一层一层的layer,相互之间通过blob传输数据连接起来。 我们先看一张图: 首先l...
  • langb2014
  • langb2014
  • 2016年03月27日 12:20
  • 16672

caffe各层参数详解(读文档记录)

前言:利用caffe工具来完成自己的模型搭建与训练,层级参数还是需要好好理解的,以便进行配置文件prototxt 的编写。 数据层 数据层是每一个模型的底层,我们需要通过它完成blobs格式数据的上传...
  • yiyisunshine
  • yiyisunshine
  • 2017年03月13日 14:20
  • 1102

caffe 绘制训练集和测试集的loss和accuracy对比曲线

  • 2017年04月20日 18:47
  • 122KB
  • 下载

Caffe傻瓜系列(4):其它常用层及参数

本文讲解一些其它的常用层,包括:softmax_loss层,Inner Product层,accuracy层,reshape层和dropout层及其它们的参数配置。 1、softmax-loss so...
  • langb2014
  • langb2014
  • 2016年01月04日 18:31
  • 2532

ubuntu14.04+caffe训练测试自己的图片数据

本文根据此博客遇到的问题所做出的更改:http://www.cnblogs.com/denny402/p/5083300.html create_filelist.sh中代码内容更改如下: #!/us...
  • Tramac
  • Tramac
  • 2016年11月04日 15:15
  • 1635

caffe训练时出错:Unknown bottom blob 'data' (layer 'conv1',bottom index 0)

大多数深度学习的训练是包含训练集的,也有一些不包含验证集的例子中,caffe的配置文件也会存在异同。 下面是包含验证集的示例: 而在一些无验证集的例子中,则要去掉“TEST”这一层,如下: 但...
  • qq_28618765
  • qq_28618765
  • 2017年12月28日 22:26
  • 88
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:caffe accuracy层以及blob的梳理
举报原因:
原因补充:

(最多只允许输入30个字)