import numpy as my notetaking as a machine learning engineer

Caffe SSD 程式碼 深度剖析

前言

最近因緣際會, 在使用SSD做object detection training時, 遇到兩個需求

  • 在output log中顯示Test Loss
    • 主要目的: 了解model是否overfit or underfit
    • 雖然看detection_eval(預設顯示)多少也可以判斷, 但還是希望看到Train Loss與Test Loss之間的差距
  • 直接在dataset中添加negative background images
    • 主要目的: 降低model的false positive rate
    • SSD default不支援添加negative background, 連annotate bounding box時使用background label都會跳error. 然而, 由於測試環境較封閉且複雜. 在考量資料蒐集與標記的成本下, 讓SSD支援輸入negative background images這一選項, 變得十分吸引人

因Wei Liu的Caffe SSD code不支援以上兩種功能, 在github搜issue找大神時也得不到完整的solution, 自己動手修改成了唯一解.
為了確保coding上的調整沒有問題, 就花了幾天的時間將Caffe SSD仔細掃過一輪, 並在此分享心得
最後, 也感謝Viscovery小夥伴們的支持, 其中Ryan與Isis都給了不錯的建議

背景知識

本文撰寫時, 預設讀者已具備以下知識

  • 熟悉image classification訓練細節 (layers like softmax, regression, and etc.)
  • 理解基本ConvNN計算細節 (kernel, stride, pad, and etc.)
  • 大致理解一些Caffe術語 (blob, forward_cpu, backward_cpu, and etc.)
  • 大致理解SSD運作原理 (multi-scale anchor box with softmax and L2 regression head)

如不熟悉, 相信用括號內的關鍵字可以google到不少資訊

SSD 架構概述

稍微複習一下, 從R-CNN這類two-stage object detector演進而來的one-stage detectors(e.g. YOLO, SSD, RetinaNet等)
精神上很像是Faster R-CNN中RPN(region proposal network)的延續.

Faster R-CNN中的RPN

RPN想做的事情很單純, 就是在一張image中, 找出可能有物體的位置, 並將他用框框(bounding box; bbox)匡出來

  • input: 一張image
  • output: a list of bboxes (x, y, w, h)
    若已經熟悉image classification, 一個最簡單的做法就是
    1. 把一張大圖切成無數塊小區域
    2. 將每個小區域送進一個classifier
    3. 由這個classifier判斷吐出 “是object” 與 “不是object” 的結果

雖然這樣的做法可行, 但實際執行起來太慢 (步驟1切圖+步驟2一張一張送進去)
因此rgb大神們就想出了一個平行化的概念, 將原本

  • [大圖 -> 切碎成多個 -> 一個一個送入classifier得到ouput]
    轉換為
  • [大圖 -> 送進一個classifier集合體 -> 一次同時吐出一堆output結果]
    然而,
  • 這個classifier集合體, 到底應該由”幾個”classifer集合而成呢?
  • 每個classifier到底 負責 哪一塊 切圖區域?
    為了明確定義, Faster R-CNN就導入了anchor box的概念 (見下圖)
    每個anchor box可以近乎視為一個切圖的概念(雖然不是完全相等),
    並在network後端接出一個classification loss(cls layer)

reg layer TBD

SSD Code Tracing

coding 架構

MultiBoxLossLayer
  |
  |- GetGroundTruth: Parse Dataset Ground Truth BBoxes 資料
  |
  |- GetPriorBoxes: Parse Network 預設的 Prior Boxes
  |
  |- GetLocPredictions: Parse Network output 的 Predicted Boxes
  |
  |- FindMatches: 以ground truth bboxes為基準, 比較並找出positive matched的 predicted boxes / prior boxes
  |
  |- MineHardExamples: 根據設定而定, mine hard negative examples (MAX_NEGATIVE) 或 mine hard (positive+negative) examples (HARD_EXAMPLES)
  |
  |- EncodeLocPrediction: 最終 encode localization 結果 (localization loss 用此做計算)
  |
  -- EncodeConfPrediction: 最終 encode confidence 結果 (confidence loss 用此做計算)

重要variable格式說明

  • vector<map<int, vector<int> > >* all_match_indices
    • 簡介: 儲存每張圖, 每個position是否有match到ground truth的資訊
    • 大小: 等同於batch size. all_match_indices[0]代表第一張image的matching資訊, 以此類推
    • 內容:
      • map<int, vector<int>> match_indices
        • int
          • 內容: mapping到的ground truth class (e.g. 0是background, 1是person, 2是bicycle…etc)
        • vector<int>
          • 大小: 等同於所有可能的position size (=num_prior; 8732 by default)
          • 內容
            • mapping到ground truth bbox的index (e.g. 若這個position與第九個gt重疊, 則數值為8; 以此類推)
            • -1: 沒有與任何一個 ground truth bbox 重疊
            • -2: predict出來的bbox超出圖片界線, 不考慮 (ignore_cross_boundary_bbox = True時)

parameters 說明

  • loc_loss_type: localization regression loss; 可選用P.MultiBoxLoss.SMOOTH_L1P.MultiBoxLoss.L2
  • conf_loss_type: confidence classification loss; 可選用P.MultiBoxLoss.SOFTMAXP.MultiBoxLoss.LOGISTIC
  • loc_weight: localization 與 confidence 之間的平衡比例 weight; 其實就是paper中eq X 的 /alpha
  • num_classes: total classification的class數量 (須包含background class)
  • share_location: 預設為True. 若設為False, 則per prior box localization的結果會由4個參數(x, y, w, h)擴增為4*num_classes個參數(代表每個class都用不同的localization參數)
  • match_type: 預設為P.MultiBoxLoss.PER_PREDICTION, 同paper描述, 若任一predicted bbox/prior bbox跟ground truth(gt) bbox IoU大於overlap_threshold時, 就判斷成matched bbox(positive bbox) 若設定成P.MultiBoxLoss.BIPARTITE, 則ground truth bbox只能有一個相對應的matched bbox(挑IoU最高的那個)
  • overlap_threshold: 應用場景見match_type, 預設為0.5 (IoU)
  • use_prior_for_matching: 預設為True, 則matching的方式是用 prior bboxes 跟 gt bboxes 做比對 (若相符, 則該bboxes被添加到matched_indices中); 若設成False, 則matching方式是用 predicted bboxes 跟 gt bboxes 做比對
  • background_label_id: 背景 class id
  • use_difficult_gt: dataset 有個difficult的tag可以進行標記. 此param預設為True, 即就算困難的ground truth sample也丟進去訓練
  • mining_type: MineHardExamples裡使用, 有以下三種模式
    • P.MultiBoxLoss.MAX_NEGATIVE (default)
    • P.MultiBoxLoss.HARD_EXAMPLE
    • P.MultiBoxLoss.NONE
  • neg_pos_ratio
  • neg_overlap
  • code_type
  • ignore_cross_boundary_bbox