Detectronがobject detectionモデルを訓練する際のクラス間のアンバランス問題を重み付けで解決する

5779 ワード

参照リンク:http://www.yueye.org/2018/weighted-object-detection-using-detectron.html
 
深さ学習を用いて分類問題を解決する場合,クラス間の不均衡はよく見られる問題であり,この問題を解決するための多くの一般的な方法もある.例えば、カテゴリの少ないサンプルをaugmentしたり、再サンプリングしたりします.カテゴリの多いサンプルをダウンサンプリングする.異なるカテゴリのサンプル数に基づいて損失関数を重み付けする.あるいは、少ないサンプルをデータセット内で簡単に乱暴にコピーする.などなど.
しかし、これらの方法では、データの深さ学習に対する重要性を考慮して、一般的にデータをサンプリングする方法は使用されない.augment、再サンプリング、レプリケーションデータは、データを直接操作する必要があります.損失関数を修正して重み付けする方法ほど簡単ではありません.損失関数を重み付けする方法は、次のとおりです.
Loss = class_of_less_samples_loss * weights + class_of_more_samples_loss
しかし、この方法は簡単で優雅であり、分類問題の処理も簡単で便利であるが、目標検出問題であれば、より多くのことを考慮する必要がある可能性がある.Detectronのように厳密に包装されたフレームワークを使用すると、処理が難しくなる可能性があります.本稿では、DetectronのFaster-CNNでこの問題を詳しく説明し、いくつかの経験的参考を提供することを期待しています.
 
1.Faster-CNNのloss
Faster-CNNには、前のRPNのclassification lossとregression loss、および後のclassification lossとregression lossの4つのlossがあります.しかし,RPN部分は前景,背景の分類を除き,一般に具体的なカテゴリ別に区別されないため,この部分を重み付けすることはできない.また,この部分はregion proposalのみを行うため,具体的なカテゴリとはあまり関係がないため,重み付けを行うことも意味がない.後のFast-CNN部分については、枠線を回帰するregression lossも同様に意味がないので、重み付けを行います.主な重み付け部分は後のFast-CNN部分のclassification lossです.
もちろん、異なるカテゴリの分類を重み付けする以外に、分類ミスの損失の影響が大きい場合もあるが、検出される限り、検出された物体の枠が特に正確であるとは限らないため、通常は具体的な問題に対して、この場所を修正し、両者の重みの割合を変える.
2.Detectronのcaffe 2
Caffe 2はFacebookが発売した主な製品配置などのシーン向けの深い学習フレームワークであり、研究などの方向に対してFacebookは簡単で使いやすいPyTorchを発売している.従ってcaffe 2は性能に注目しすぎて使いやすさが悪い.したがって,caffe 2ベースのDetectronは訓練速度は良好であるが,それを修正しようとするのは容易ではない.
caffeと同様に、caffe 2もBlobを使用してデータを管理しています.したがってcaffe 2では,伝達されるパラメータは通常1つの名前しかなく,多くの人が頭がつかめず,デバッグが非常に困難である.
caffe 2では、新しいBlobを作成するには、次のコードを使用します.
  • import numpy as np
  • from caffe2.python import core, workspace
  •  
  • labels_array = np.array(...)
  • labels = workspace.FeedBlob('labels', labels_array)

  • これでlabelsというBlobを新規作成しました.
    その後、他の場所で使用することができます.使用するときは、直接データfetchを出せばいいです.
  • from caffe2.python import core, workspace
  •  
  • labels = workspace.FetchBlob('labels')
  • # labels = workspace.FetchBlob(core.ScopedName('labels'))

  • labelsがグローバル名である場合、fetchを直接行うことができます.scopeで定義されたBlobの場合は、まず名前を処理する必要があります.そうしないと、対応するBlobが見つからないことを示す可能性があります.
    Detectronでは、Blobを使用する例がたくさんあります.これと、これです.
     
    注意:ここに与えられたリンクはすべて古いバージョンのリンクで、githubで検索して、相応のファイルを見つける必要があります
     
    3.DetectronのFaster-CNNのloss_を修正するclsとloss_bboxの割合
    Faster-CNNで、この2つのlossを確立したのはfast_です.rcnn_heads.pyのadd_fast_rcnn_model.net.SoftmaxWithLossとmodel.net.SmoothL 1 Lossをそれぞれ用いて対応するloss値を得たlosses関数.SoftmaxWithLossという関数のパラメータscale=model.GetLossScale()は、スケールを制御する場所です.関数の中で、この割合はGPUを使う数量によって調節して、私達は最小でもとの内容を修正するために、直接この関数の後で修正の割合をプラスして、例えば、それを修正します:scale=model.GetLossScale()*2、間もなくloss_clsの比重は従来の2倍に拡大した.同時にSmoothL 1 Lossのscaleを調整しない場合、classificationのlossウェイトをregression lossの2倍に上げることに相当します.
    4.異なるカテゴリのObjectに基づいて、lossでの重みを変更する
    まず3のloss_を見てみましょうcls、このlossはmodel.net.SoftmaxWithLossを使用して生成されます.この関数のドキュメントを参照すると、logits、labelsのほかに、weightsとしてBlobを入力することもできます.これが私たちが修正しなければならない場所です.
    minibatch.pyでのget_minibatch関数では、RPNのBlobを読み取るのはroi_data.rpn.add_rpn_blobsで完了し、Fast-CNNのデータを読み込むとroi_data.fast_rcnn.add_fast_rcnn_blobsが完成しました.従って,上記の解析では,重み付けを行う操作を修正する必要があり,後述する関数で行う必要がある.
    fast_でrcnn.pyのadd_fast_rcnn_blobs関数では、データの読み出し操作が行われており、具体的には、読み出し操作は関数における_sample_rois(entry,im_scales[im_i],im_i)で完成しました.
    ジャンプしてsample_roisという関数では,labelsが生成する場所を見つけ,labelsに基づいて必要なweightsを生成すればよい.
     
    バックグラウンドの後にウェイト値を追加するには
        # Label is the class each RoI has max overlap with
        sampled_labels = roidb['max_classes'][keep_inds]
        sampled_labels[fg_rois_per_this_image:] = 0  # Label bg RoIs with class 0
        #add weights,refer to the web blog
        weights=(np.where(sampled_labels==9,20,1)).astype(np.float32)

     
    ここではlabelが9のカテゴリの重みを20に設定し,他のカテゴリは変わらない.そして、次に戻るblob_dictにこのweightsを追加すれば、以下のようになります.
  • blob_dict = dict(
  • labels_int32=sampled_labels.astype(np.int32, copy=False),
  • #add this line
  • weights=weights,
  • rois=sampled_rois,
  • bbox_targets=bbox_targets,
  • bbox_inside_weights=bbox_inside_weights,
  • bbox_outside_weights=bbox_outside_weights
  • )

  • ただし、その前にweightsというBlobを追加する必要があります.
    fast_でrcnn.pyのget_fast_rcnn_blob_names関数では、以下のように直接追加できます.
  • # Add weights
  • if is_training:
  • blob_names += ['weights']

  • これにより、指定されたカテゴリのObjectを重み付けし、object detection時の重要性を際立たせて特殊に扱うことができる.
     
     
    5.一部の画像を重み付けする
    時々、私たちはこれらのカテゴリを重み付けしたいだけでなく、このカテゴリが現れた画像を重み付けしたいと思っています.この場合、このように処理すべきですか?
    これは比較的簡単で、データroidbを最初に読むときに直接処理すればよい.train.pyにあるcombined_roidb_for_training関数は,訓練のためにデータroidbを確立する.この関数はroidb.pyファイルに定義されています.この関数には、roidbのデータをフィルタする関数が表示されます.この関数は、「Remove roidb entries that have no usable RoIs based on config settings」に使用されます.この関数を模倣してaugmentを構築することができますroidb_for_training関数.次のようになります.
  • def augment_for_training(roidb):
  • """Augment roidb entries that have some RoIs.
  • """
  • num = len(roidb)
  • auged_roidb = []
  • for db in roidb:
  • if np.sum(db['gt_classes']==2)>=1:
  • auged_roidb.append(db)
  • auged_roidb.append(db)
  • else:
  • auged_roidb.append(db)
  • num_after = len(auged_roidb)
  • logger.info('Augment {} roidb entries: {} -> {}'.
  • format(num_after - num, num, num_after))
  • return auged_roidb

  • そしてcombined_roidb_for_training(dataset_names,proposal_files)関数で、この関数を呼び出します.
        roidb = filter_for_training(roidb)     roidb = augment_for_training(roidb)
    これにより,labelが2のピクチャを2部にコピーし,重み付けが完了したことに相当する.