其他分享
首页 > 其他分享> > Caffe实战(十五):数据层及参数设置

Caffe实战(十五):数据层及参数设置

作者:互联网

数据层是每个模型的最底层,是模型的入口,不仅提供数据的输入,也提供数据从Blobs转换成别的格式进行保存输出。通常数据的预处理(如减去均值, 放大缩小, 裁剪和镜像等),也在这一层设置参数实现。   caffe的各种数据层在caffe.proto文件中定义,通过对定义的caffe.proto文件进行编译,产生支持各种层操作的C++代码。 caffe支持的数据来源主要有:

不同层的共有属性

所有的数据层的都具有的公用参数
layer {
  name: "cifar"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mean_file: "examples/cifar10/mean.binaryproto"
  }
  data_param {
    source: "examples/cifar10/cifar10_train_lmdb"
    batch_size: 100
    backend: LMDB
  }
}
  绝大部分数据层在设置时,都可以先对数据进行一定的预处理,包括归一化scale,去中心化(减去平均值),水平镜像mirror,随机裁剪/中心裁剪crop等四种预处理方式。该预处理方式可以通过Layer的transform_params属性(HDF5 Layer没有该属性)来设定,如下所示:
transform_param {
    # 实际上就是1/255, 即将输入数据由0-255归一化到0-1之间
    scale: 0.00390625
    # randomly horizontally mirror the image
    # 1表示开启镜像,0表示关闭,也可用ture和false来表示
    mirror: 1
    # corp a 'crop_size'x 'corp_size'patch:
    # -at random during training
    # -from the center during testing
    # 剪裁一个 227*227的图块,在训练阶段随机剪裁,在测试阶段从中间裁剪
    crop_size: 227
    # substract mean value(RGB three channel) 用一个配置文件来进行均值操作
    mean_file: "examples/cifar10/mean.binaryproto"
    # mean_value: 104
    # mean_value: 117
    # mean_value: 123
  }

 

源码“data_transformer.cpp”可知,执行顺序是mean(file)、mean(value)、crop、mirror、scale。如有其它特殊的预处理可在此添加代码。 此外由  const bool do_mirror = param_.mirror() && Rand(2); 可知每次batch是随机的做mirror(水平翻转)的。  

数据层参数shuffle介绍

训练网络的时候一般需要随机打乱训练样本数据,因为是采用min-batch SGD 方法进行优化的,随机打乱一定程度上可以防止陷入局部最优,有利于网络收敛。   而caffe读取数据时是一个batch一个batch顺序读取的,不同的数据形式实现shuffle的机制不同:

 

数据来自于数据库(如LevelDB和LMDB)

  层类型(layer type):Data   必须设置的参数:   可选的参数: LMDB(Lightning MemoryMapped Databases),由于caffe的文件读取方式使得该格式的额数据输入最适合用于1-k分类问题。
layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}

 

在caffe代码中,Net初始化时是从bottom到top逐层初始化各层的;在初始化data层时,调用DataLayer构造函数
template <typename Dtype>
DataLayer<Dtype>::DataLayer(const LayerParameter& param)
  : BasePrefetchingDataLayer<Dtype>(param),
    reader_(param) {
}

 

其中reader_是DataReader类,用于读取lmdb或leveldb格式的数据;caffe实现了多线程读取数据,在DataReader类中,InternalThreadEntry()函数实现了多线程并行读取lmdb/leveldb数据的,具体的对lmdb/leveldb读取操作的实现在db.cpp,db_lmdb.cpp和db_leveldb.cpp文件中。
void DataReader::Body::InternalThreadEntry() {
  shared_ptr<db::DB>  db(db::GetDB(param_.data_param().backend()));
  db->Open(param_.data_param().source(), db::READ);
  shared_ptr<db::Cursor> cursor(db->NewCursor());
  vector<shared_ptr<QueuePair> > qps;
  try {
    int solver_count = param_.phase() == TRAIN ?  Caffe::solver_count() : 1;
    // To ensure deterministic runs, only start running once  all solvers
    // are ready. But solvers need to peek on one item  during initialization,
    // so read one item, then wait for the next solver.
    for (int i = 0; i < solver_count; ++i) {
      shared_ptr<QueuePair> qp(new_queue_pairs_.pop());
      read_one(cursor.get(), qp.get());
      qps.push_back(qp);
    }
    // Main loop
    while (!must_stop()) {
      for (int i = 0; i < solver_count; ++i) {
        read_one(cursor.get(), qps[i].get());
      }
      // Check no additional readers have been created. This  can happen if
      // more than one net is trained at a time per process,  whether single
      // or multi solver. It might also happen if two data  layers have same
      // name and same source.
      CHECK_EQ(new_queue_pairs_.size(), 0);
    }
  } catch (boost::thread_interrupted&) {
    // Interrupted exception is expected on shutdown
  }
}

 

数据来自于内存

可以很快从内存中直接读取数据。使用该方法来读取数据时,可以靠调用MemoryDataLayer::Reset(from C++) or Net.set_input_arrays(from python)来制定一个具体的数据地址;如通常的存放所有输入数据的四维数组的首地址,这样就可以每次从该地址内存中读取batch_size大小的数据。   层类型:MemoryData   必须设置的参数:
layer {
  top: "data"
  top: "label"
  name: "memory_data"
  type: "MemoryData"
  memory_data_param{
    batch_size: 2
    height: 100
    width: 100
    channels: 1
  }
  transform_param {
    scale: 0.0078125
    mean_file: "mean.proto"
    mirror: false
  }
}

 

数据来自于HDF5

不太适合图像,因为HDF5格式数据采用FP2格式的数据,而图像采用uint8,因此若将文件转换为该格式则会很大。与其它层不同,该层没有transform_params属性。   层类型:HDF5Data   必须设置的参数:   可选设置:
layer {
  name: "data"
  type: "HDF5Data"
  top: "data"
  top: "label"
  hdf5_data_param {
    source: "examples/hdf5_classification/data/train.txt"
    batch_size: 10
  }
}

 

数据来自于图片

直接从文本文件读入所有要处理的图像文件的路径与标签label。   层类型:ImageData   必须设置的参数:   可选参数:
layer {
  name: "data"
  type: "ImageData"
  top: "data"
  top: "label"
  transform_param {
    mirror: false
    crop_size: 227
    mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  image_data_param {
    source: "examples/_temp/file_list.txt"
    batch_size: 50
    new_height: 256
    new_width: 256
  }
}

 

图像和标签文件来源txt文本,文本内容如下所示,最后一列为图像的标签
/path/to/images/img3423.jpg 2
/path/to/images/img3424.jpg 13
/path/to/images/img3425.jpg 8
...

 

ImageNet数据集使用过程,ImageNet数据集给出的是图像格式文件,在一个txt文件中包含要训练的图片名称以及标签,如同上面介绍的。由于ImageNet图像的分辨率不统一,则通过image_data_param参数中的new_height和new_width对输入源数据进行分辨率统一,然后在进行预处理操作,transform_param中的crop获得模型需要的227*227大小的图片格式。  

数据来源于原始图片的窗口(Windows)

最适合目标检测任务,因为目标检测的训练样本都是标注好的窗口,而不是整张图像。训练时是针对每一个窗口进行训练,而不是一个图像。   层类型:WindowData   必须设置的参数:
layer {
  name: "data"
  type: "WindowData"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  window_data_param {
    source: "examples/finetune_pascal_detection/window_file_2007_trainval.txt"
    batch_size: 128
    fg_threshold: 0.5
    bg_threshold: 0.5
    fg_fraction: 0.25
    context_pad: 16
    crop_mode: "warp"
  }
}
  其中windows_file_2007_trainval.txt文件如下:
1. # 0  
2. /home/xxx/0001.jpg  
3. 641  
4. 7  
5. 1 1.0 353 356 393 396  
6. 1 0.5 338 344 379 384  
7. 2 0.7 339 336 379 376  
8. 5 0 334 330 374 370  
9. 4 1.0 330 324 370 364  
10. 4 1.0 335 319 375 359  
11. 4 1.0 341 313 381 353  
12. # 1  
13. /home/xxx/0002.jpg  
14. 600  
15. 3  
16. 2 1.0 353 356 393 396  
17. 2 0.5 338 344 379 384  
18. 3 0.7 339 336 379 376  
  其中第一行是图片的index, 从0开始, 接下来三行依此是图片的路径, height, width。再接下来的每一行都是一个bounding box, 第一个数字表示label, 第二个数字表示与真实goundtruth 的overlap, 接下来的四个数字表示x1, y1, x2, y2。负样本的标签可以随意指定。   该层必须要设置的参数:   可选参数:   如下图所示,最外围的一圈即为context填充,此时context_pad为1:  

其它数据层

Input type:常用来测试网络的前向和后向传递时间;用在deploy文件测试模型效果,需要代码中手动指定网络输入数据,唯一的参数BlobShape设定输入数据的维度。   deploy文件是测试模型效果,而一般的train_test等文件是为了训练模型。deploy文件是在train_test文件的基础上获得的,二者之间的区别如下:
layer {
    name:"data"    #设定当前layer名称为data
    type:"Input"   #设置当前layer类型为Input
    top:"data"     #设置当前layer输出blob名称为data
    #定义输入数据维度为 batchsize =1 channel=1 height=42 dim=42
    input_param {shape: {dim: 1 dim: 1 dim: 42 dim:42}}
}
    “DummyData”type:常用来debug,也可以用来测试网络传递时间
layer {  
  name: "data"  
  type: "DummyData"  
  top: "data"  
  include {  
    phase: TRAIN  
  }  
  dummy_data_param {  
    data_filler {  
      type: "constant"  
      value: 0.01  
    }  
    shape {  
      dim: 32  
      dim: 3  
      dim: 227  
      dim: 227  
    }  
  }  
}  
layer {  
  name: "data"  
  type: "DummyData"  
  top: "label"  
  include {  
    phase: TRAIN  
  }  
  dummy_data_param {  
    data_filler {  
      type: "constant"  
    }  
    shape {  
      dim: 32  
    }  
  }  
}  

 

在这个例子中,有两个数据层,一个blob一个层,data一个,label一个。在HDF5,Data数据库,ImageData,都是data和label放在一个层里。这样方便调试。  

参考:

   

标签:数据,top,param,Caffe,层及,mean,data,参数设置,size
来源: https://www.cnblogs.com/aiguilai/p/15211692.html