这其实不算caffe的,是caffe-ssd的代码,因为最近要用到,所以提前看了......
<span style="font-size: 18px;">#ifndef CAFFE_DATA_LAYER_HPP_
#define CAFFE_DATA_LAYER_HPP_
#include <string>
#include <vector>
#include "caffe/blob.hpp"
#include "caffe/data_reader.hpp"
#include "caffe/data_transformer.hpp"
#include "caffe/internal_thread.hpp"
#include "caffe/layer.hpp"
#include "caffe/layers/base_data_layer.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/db.hpp"
namespace caffe {
template <typename Dtype>
class AnnotatedDataLayer : public BasePrefetchingDataLayer<Dtype> {
public:
//显示构造函数
explicit AnnotatedDataLayer(const LayerParameter& param);
//虚析构函数
virtual ~AnnotatedDataLayer();
//数据输入层的参数设置
virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
//AnnotatedDataLayer uses DataReader instead for sharing for parallelism
virtual inline bool ShareInParallel() const { return false; }
//返回该层类型
virtual inline const char* type() const { return "AnnotatedData"; }
//Bottom的Blob的确切数目</span><span style="font-size: 18px;">
virtual inline int ExactNumBottomBlobs() const { return 0; }</span><pre name="code" class="python">//Top的Blob的最小数目
virtual inline int MinTopBlobs() const { return 1; } protected:
// virtual void load_batch(Batch<Dtype>* batch);//声明一些变量 DataReader<AnnotatedDatum> reader_; bool has_anno_type_; // AnnotatedDatum_AnnotationType anno_type_; // vector<BatchSampler> batch_samplers_; //数据增广用的... string label_map_file_; //数据标签文件};} // namespace caffe#endif // CAFFE_DATA_LAYER_HPP_
#ifdef USE_OPENCV
#include <opencv2/core/core.hpp>
#endif // USE_OPENCV
#include <stdint.h>
#include <algorithm>
#include <map>
#include <vector>
#include "caffe/data_transformer.hpp"
#include "caffe/layers/annotated_data_layer.hpp"
#include "caffe/util/benchmark.hpp"
#include "caffe/util/sampler.hpp"
namespace caffe {
template <typename Dtype>
//构造函数
AnnotatedDataLayer<Dtype>::AnnotatedDataLayer(const LayerParameter& param)
: BasePrefetchingDataLayer<Dtype>(param),
reader_(param) {
}
//析构函数
template <typename Dtype>
AnnotatedDataLayer<Dtype>::~AnnotatedDataLayer() {
this->StopInternalThread();
}
//AnnotatedDataLayer类的函数DataLayerSetUp
//该层的参数设置
template <typename Dtype>
void AnnotatedDataLayer<Dtype>::DataLayerSetUp(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
//设置batch_size,一般默认是32,在网络结构的代码中修改
const int batch_size = this->layer_param_.data_param().batch_size();
//为数据的增广而设置的采样batch
const AnnotatedDataParameter& anno_data_param =
this->layer_param_.annotated_data_param();
//依次使用第i种采样方式获取图片的样本数据,存入batch_samplers中
for (int i = 0; i < anno_data_param.batch_sampler_size(); ++i) {
batch_samplers_.push_back(anno_data_param.batch_sampler(i));
}
//这是写有每一类的物体分类标签的文件
label_map_file_ = anno_data_param.label_map_file();
// Read a data point, and use it to initialize the top blob.
AnnotatedDatum& anno_datum = *(reader_.full().peek()); //额,这个不懂...
// Use data_transformer to infer the expected blob shape from anno_datum.
//利用transform_param确定top shape
vector<int> top_shape =
this->data_transformer_->InferBlobShape(anno_datum.datum());
//这样transformed_data_的形状就可以确定了
this->transformed_data_.Reshape(top_shape);
// Reshape top[0] and prefetch_data according to the batch_size.
//blob的第0维的大小等于batch_size
top_shape[0] = batch_size;
//根据刚才确定的值设定top的大小
top[0]->Reshape(top_shape);
//根据top shape把相应大小的batch提前拿出
for (int i = 0; i < this->PREFETCH_COUNT; ++i) {//
this->prefetch_[i].data_.Reshape(top_shape);
}
//打印输出数据的大小
LOG(INFO) << "output data size: " << top[0]->num() << ","
<< top[0]->channels() << "," << top[0]->height() << ","
<< top[0]->width();
//label以及他的存储格式,这一段不是特别懂...
if (this->output_labels_) {
has_anno_type_ = anno_datum.has_type();
vector<int> label_shape(4, 1);
if (has_anno_type_) {
anno_type_ = anno_datum.type();
// Infer the label shape from anno_datum.AnnotationGroup().
int num_bboxes = 0;
if (anno_type_ == AnnotatedDatum_AnnotationType_BBOX) {
// Since the number of bboxes can be different for each image,
// we store the bbox information in a specific format. In specific:
// All bboxes are stored in one spatial plane (num and channels are 1)
// And each row contains one and only one box in the following format:
// [item_id, group_label, instance_id, xmin, ymin, xmax, ymax, diff]
// Note: Refer to caffe.proto for details about group_label and
// instance_id.
for (int g = 0; g < anno_datum.annotation_group_size(); ++g) {
num_bboxes += anno_datum.annotation_group(g).annotation_size();
}
label_shape[0] = 1;
label_shape[1] = 1;
// BasePrefetchingDataLayer<Dtype>::LayerSetUp() requires to call
// cpu_data and gpu_data for consistent prefetch thread. Thus we make
// sure there is at least one bbox.
label_shape[2] = std::max(num_bboxes, 1);
label_shape[3] = 8;
} else {
LOG(FATAL) << "Unknown annotation type.";
}
} else {
label_shape[0] = batch_size;
}
top[1]->Reshape(label_shape);
for (int i = 0; i < this->PREFETCH_COUNT; ++i) {
this->prefetch_[i].label_.Reshape(label_shape);
}
}
}
// This function is called on prefetch thread
//提前从内存取出数据时调用的函数
template<typename Dtype>
void AnnotatedDataLayer<Dtype>::load_batch(Batch<Dtype>* batch) {
CPUTimer batch_timer;
batch_timer.Start();
double read_time = 0;
double trans_time = 0;
CPUTimer timer;
CHECK(batch->data_.count());
CHECK(this->transformed_data_.count());
// Reshape according to the first anno_datum of each batch
// on single input batches allows for inputs of varying dimension.
const int batch_size = this->layer_param_.data_param().batch_size();
AnnotatedDatum& anno_datum = *(reader_.full().peek());
// Use data_transformer to infer the expected blob shape from anno_datum.
vector<int> top_shape =
this->data_transformer_->InferBlobShape(anno_datum.datum());
this->transformed_data_.Reshape(top_shape);
// Reshape batch according to the batch_size.
top_shape[0] = batch_size;
batch->data_.Reshape(top_shape);
Dtype* top_data = batch->data_.mutable_cpu_data();
Dtype* top_label = NULL; // suppress warnings about uninitialized variables
if (this->output_labels_ && !has_anno_type_) {
top_label = batch->label_.mutable_cpu_data();
}
// Store transformed annotation.
map<int, vector<AnnotationGroup> > all_anno;
int num_bboxes = 0;
for (int item_id = 0; item_id < batch_size; ++item_id) {
timer.Start();
// get a anno_datum
AnnotatedDatum& anno_datum = *(reader_.full().pop("Waiting for data"));
read_time += timer.MicroSeconds();
timer.Start();
AnnotatedDatum sampled_datum;
if (batch_samplers_.size() > 0) {
// Generate sampled bboxes from anno_datum.
vector<NormalizedBBox> sampled_bboxes;
GenerateBatchSamples(anno_datum, batch_samplers_, &sampled_bboxes);
if (sampled_bboxes.size() > 0) {
// Randomly pick a sampled bbox and crop the anno_datum.
int rand_idx = caffe_rng_rand() % sampled_bboxes.size();
this->data_transformer_->CropImage(anno_datum, sampled_bboxes[rand_idx],
&sampled_datum);
} else {
sampled_datum.CopyFrom(anno_datum);
}
} else {
sampled_datum.CopyFrom(anno_datum);
}
// Apply data transformations (mirror, scale, crop...)
int offset = batch->data_.offset(item_id);
this->transformed_data_.set_cpu_data(top_data + offset);
vector<AnnotationGroup> transformed_anno_vec;
if (this->output_labels_) {
if (has_anno_type_) {
// Make sure all data have same annotation type.
CHECK(sampled_datum.has_type()) << "Some datum misses AnnotationType.";
CHECK_EQ(anno_type_, sampled_datum.type()) <<
"Different AnnotationType.";
// Transform datum and annotation_group at the same time
transformed_anno_vec.clear();
this->data_transformer_->Transform(sampled_datum,
&(this->transformed_data_),
&transformed_anno_vec);
if (anno_type_ == AnnotatedDatum_AnnotationType_BBOX) {
// Count the number of bboxes.
for (int g = 0; g < transformed_anno_vec.size(); ++g) {
num_bboxes += transformed_anno_vec[g].annotation_size();
}
} else {
LOG(FATAL) << "Unknown annotation type.";
}
all_anno[item_id] = transformed_anno_vec;
} else {
this->data_transformer_->Transform(sampled_datum.datum(),
&(this->transformed_data_));
// Otherwise, store the label from datum.
CHECK(sampled_datum.datum().has_label()) << "Cannot find any label.";
top_label[item_id] = sampled_datum.datum().label();
}
} else {
this->data_transformer_->Transform(sampled_datum.datum(),
&(this->transformed_data_));
}
trans_time += timer.MicroSeconds();
reader_.free().push(const_cast<AnnotatedDatum*>(&anno_datum));
}
// Store "rich" annotation if needed.
if (this->output_labels_ && has_anno_type_) {
vector<int> label_shape(4);
if (anno_type_ == AnnotatedDatum_AnnotationType_BBOX) {
label_shape[0] = 1;
label_shape[1] = 1;
label_shape[3] = 8;
if (num_bboxes == 0) {
// Store all -1 in the label.
label_shape[2] = 1;
batch->label_.Reshape(label_shape);
caffe_set<Dtype>(8, -1, batch->label_.mutable_cpu_data());
} else {
// Reshape the label and store the annotation.
label_shape[2] = num_bboxes;
batch->label_.Reshape(label_shape);
top_label = batch->label_.mutable_cpu_data();
int idx = 0;
for (int item_id = 0; item_id < batch_size; ++item_id) {
const vector<AnnotationGroup>& anno_vec = all_anno[item_id];
for (int g = 0; g < anno_vec.size(); ++g) {
const AnnotationGroup& anno_group = anno_vec[g];
for (int a = 0; a < anno_group.annotation_size(); ++a) {
const Annotation& anno = anno_group.annotation(a);
const NormalizedBBox& bbox = anno.bbox();
top_label[idx++] = item_id;
top_label[idx++] = anno_group.group_label();
top_label[idx++] = anno.instance_id();
top_label[idx++] = bbox.xmin();
top_label[idx++] = bbox.ymin();
top_label[idx++] = bbox.xmax();
top_label[idx++] = bbox.ymax();
top_label[idx++] = bbox.difficult();
}
}
}
}
} else {
LOG(FATAL) << "Unknown annotation type.";
}
}
timer.Stop();
batch_timer.Stop();
DLOG(INFO) << "Prefetch batch: " << batch_timer.MilliSeconds() << " ms.";
DLOG(INFO) << " Read time: " << read_time / 1000 << " ms.";
DLOG(INFO) << "Transform time: " << trans_time / 1000 << " ms.";
}
INSTANTIATE_CLASS(AnnotatedDataLayer);
REGISTER_LAYER_CLASS(AnnotatedData);
} // namespace caffe