1. 程式人生 > >caffe多工、多標籤

caffe多工、多標籤

解決的目標問題:多分類問題,比如車輛的外形和顏色,蘋果的大小和顏色;多工:車牌角點的定位和車牌的顏色。定位在技術上屬於迴歸,車牌顏色判斷則屬於分類。

技術點

caffe預設是單輸入任務單標籤的,也就是一個樣本,其任務只有一個,標籤只有一個,比如圖片是什麼顏色,圖片是什麼物體。

# ${caffe_src_root}/tools/convert_imageset.cpp 第121行
status = ReadImageToDatum(root_folder + lines[line_id].first,
        lines[line_id].second, resize_height, resize_width, is_color,
        enc, &datum);

## 其中 ReadImageToDatum的定義如下 ${caffe_src_root}/include/caffe/util/io.hpp

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, const bool is_color,
    const std::string & encoding, Datum* datum);

##  ${caffe_src_root}/src/caffe/util/io.cpp 中的該函式實現,涉及到Datum的定義,需要把Datum定義修改成也要支援多標籤

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, const bool is_color,
    const std::string & encoding, Datum* datum) {
  cv::Mat cv_img = ReadImageToCVMat(filename, height, width, is_color);
  if (cv_img.data) {
    if (encoding.size()) {
      if ( (cv_img.channels() == 3) == is_color && !height && !width &&
          matchExt(filename, encoding) )
        return ReadFileToDatum(filename, label, datum);
      std::vector<uchar> buf;
      cv::imencode("."+encoding, cv_img, buf);
      datum->set_data(std::string(reinterpret_cast<char*>(&buf[0]),
                      buf.size()));
      datum->set_label(label);
      datum->set_encoded(true);
      return true;
    }
    CVMatToDatum(cv_img, datum);
    datum->set_label(label);
    return true;
  } else {
    return false;
  }
}

為了支援多工,多標籤,首先要解決輸入問題。比如一個樣本 定義如下:

vehicle/1.jpg  0 1

 

修改原始碼支援多標籤

其中第一個屬性是車輛外形,0代表sedian,第二個屬性是車身顏色,1代表白色。假如圖片是60x60的RGB影象,    如果是單任務多屬性輸入,一個簡單的更改方案是把ReadImageToDatum函式修改成如下定義,並修改相關的實現函式和convert_imageset.cpp

bool ReadImageToDatum(const string& filename, const vector<int> & labels,
    const int height, const int width, const bool is_color,
    const std::string & encoding, Datum* datum);

faster rcnn採用自定義的python輸入層作用訓練輸入,輸入有多個labels,檢測目標的roi,其中bbox_targets, bbox_inside_weights, bbox_outside_weights是作為SmoothL1Loss損失函式的輸入。自定義python輸入層的原始碼參考 py-faster-rcnn/lib/roi_data_layer

name: "VGG_ILSVRC_16_layers"
layer {
  name: 'data'
  type: 'Python'
  top: 'data'
  top: 'rois'
  top: 'labels'
  top: 'bbox_targets'
  top: 'bbox_inside_weights'
  top: 'bbox_outside_weights'
  python_param {
    module: 'roi_data_layer.layer'
    layer: 'RoIDataLayer'
    param_str: "'num_classes': 21"
  }
}

 

從https://github.com/HolidayXue/CodeSnap/blob/master/convert_multilabel.cpp原始碼修改,儲存到${caffe_root}/tools/convert_multi_label_imageset.cpp,重新編譯caffe工程,在${caffe_root}目錄下執行該工具,

.build_release/tools/convert_multi_label_imageset.bin -resize_width=256 -resize_height=256  ~/my\ workspace/bounding-box-tool/mlds/train.list /train-data/vehicle-type-color-dataset/

 

 

多資料來源輸入支援多標籤

假設對於HxW的RGB影象,轉換成caffe的blob定義上1x3xHxW,對於一個任務的有n個標籤,則其blob定義是1xnx1x1,每個任務對應一個blob,???那麼可以在在第二維度對兩個blob進行拼接???

拼接之後再從第二維度對blob進行切分操作,切分出多個blob,作為每個屬性訓練任務的輸入

 

拼接之後進行常規的卷積操作,只是在最後的每個任務的損失函式之前的fc層再切分,如下圖

 訓練

參考faster-rcnn的模型,可以看到損失函式是相互獨立的,但多了一個weight引數,猜測是caffe在訓練時,按下面的公式計算總的損失

Lt = w1*L1 + w2 * L2

faster-rcnn中經過一系列卷積層後,連線了一個ROIPooling層,再接上FC6、FC7層,從最後一個FC7層一分為2,分別接一個cls_score的FC層和名為loss_cls的SoftMaxWithLoss,接bbox_pred的FC層和名為loss_bbox的SmoothL1Loss的迴歸層

參考:

https://arxiv.org/abs/1604.02878v1

https://kpzhang93.github.io/MTCNN_face_detection_alignment/index.html?from=timeline&isappinstalled=1

https://kpzhang93.github.io/MTCNN_face_detection_alignment/paper/spl.pdf

https://github.com/happynear/MTCNN_face_detection_alignment

https://github.com/naritapandhe/Gender-Age-Classification-CNN

https://github.com/cunjian/multitask_CNN

https://zhuanlan.zhihu.com/p/22190532

https://github.com/rbgirshick/py-faster-rcnn/blob/master/models/pascal_voc/VGG16/fast_rcnn/train.prototxt

${caffe_source_root}/examples/pascal-multilabel-with-datalayer.ipynb

http://www.cnblogs.com/yymn/articles/7741741.html

https://yq.aliyun.com/ziliao/572047

https://blog.csdn.net/u013010889/article/details/53098346

caffe網路線上視覺化工具: http://ethereon.github.io/netscope/#/editor