2015. 4.21.
石立 喬

OpenCVとVisual C++による画像処理と認識(16)

----- ブースティングで、簡単な真顔と偽顔の図形を識別する -----

 サポートベクターマシと並んで多く用いられる識別アルゴリズムに、ブースティングがある。ブースティングは、広義では、独立したアルゴリズムではなく、サポートベクターマシンを含む、他の識別アルゴリズムを一層強化する仕組みである。一方、狭義では、学習によって強化される、決定木(decision tree)を弱識別器とする分類木または回帰木である。
 ここでは、きわめて簡単な模型的な使い方で、ブースティングを体験してみた。

ブースト(boost)
 ブーストとは、強化する意味で、判断能力の低い弱識別器を集めて、能力の高い強識別器を作ることを意味する。弱識別器は、それぞれ投票権を持ち、学習過程で、比較的優れた弱識別器には多い投票権を、劣った弱識別器には、投票権を下げたり、除外したりして、全体としての識別能力を高めるアルゴリズムである。このように、適応力を持たせる方法を、AdaBoost(Adaptive Boost)と言い、ブーストと言えば、これを指すと考えても良い。
 Adaboostの長所は、計算が簡単であること、高速であり、チューニングが要らないことであり、短所は、ノイズやかけ離れた値に弱く、SVMのような非線形の識別ができないことである。
 OpenCVに用意されているクラスを使用するには、決定木理論の理解が有用である。

いろいろなBoost
 当初考えられたAdaBoostは、弱識別器が-1または+1の値(または0と1の二値)を出力する二値のDiscrete AdaBoostであったが、それが、分類結果の信頼度として0〜1の実数を出力するReal AdaBoostに一般化された。
 訓練に反映させる誤りの度合いを求める損失関数(loss function)の種類によって、LogitBoostやGentle AdaBoostがあり、これらは弱識別器が数値データを出力する回帰木に属する(分類カテゴリーを出力する決定木ではなく)。
 マルチクラス化の研究も進み、AdaBoost.M1やAdaBoost.M2が発表された。その後、AdaBoost.MHやAdaBoost.MRが現れ、これらはAdaBoost.M1やAdaBoost.M2を包含する関係にある。
 OpenCVでは、現在は、マルチクラスに対応しておらず、パラメータのboost_typeによって、Discrete AdaBoost、Real AdaBoost、LogitBoost、Gentle AdaBoostを選ぶことができる。デフォルトはReal AdaBoostである。

基本的なAdaBoostのアルゴリズム
1)どの学習サンプルの重要度も、最初は同じに設定する。
2)あてずっぽうよりましな程度の弱識別器を多数用意する。
3)学習サンプルを与えて、どの弱識別器が良くあてるかを調べる。ただし、学習サンプルには重要度があるので、重要度の高いサンプルを間違えると、減点が大きくなり、ダメな弱識別器のレッテルが貼られる。
4)最もよく当たった(間違いによる減点が少なかった)弱識別器を探し出し、学習サンプルと識別結果を比較し、間違った学習サンプルの重要度を高める。つまり、各弱識別器に対して、このサンプルに対する訓練を強化する。
5)優秀な弱識別器と、ダメなものとが次第に明確になるので、最終的に、優秀な弱識別器には重みを増し、そうでないものには、重みを減らしたり、削除したりして、全体的に強力な識別器を構成する。
 訓練途中における学習サンプルの「重み」と、最終的に与える弱識別器の「重み」とを混同し易いので注意する。

ブーストを使って、顔と非顔を判別する
 プログラムは、下記から成っている。
 1)複数回使用する顔データ描画メソッドdrawFacesを用意する(図1)。
    引数は、描画先画像、位置、顔データ、顔データ番号である。
 2)訓練用顔データtraining_dataを準備する(図2)。
    各9部位から成る、真顔10個、偽顔10個である。
 3)訓練用顔データを表示する(プログラムは図3、結果は図6)。
 4)訓練用ラベルtraining_labelsを準備する(図3)。
    真顔を1、偽顔を0とする。
 5)Boostを訓練する(図4)。
    パラメータは特に指定しないで、デフォルト条件で使用する。
 6)訓練結果確認のためのテスト用データtest_dataを用意する(図4)。
    訓練に使用した顔データからの抜粋を10個、新しいデータ10個を切り替える。
 7)テスト用データtest_dataをtest_imageとして表示する(プログラムは図5、結果は図7、8)。
 8)Boostのテストを実行する(プログラムは図5、結果は図7、8)。
    テスト用顔データtest_dataから顔データを一つずつ取り出して、配列testとし、boost.predictを用いる。
    結果responseにより、"True"または"False"を、test_image上に表示する。

使用したOpenCVクラス、構造体の説明
 以下は、頭のCvを付けなくても使用できる(typedef設定あり)。CvBoostはCvStatModelを継承し、CvBoostParamsはCvDTreeParamsを継承しているので、さらに詳しく知るには、それらの資料が参考になる。
◎CvBoostクラス
 ブースティングの基本クラスで、次の二つのメソッドを使用する。詳細設定は、コンストラクタでも可能であるが、trainメソッドで行うのが容易である。
 trainメソッド ------ 訓練を実行する。引数は下記の通り。

     train(訓練データ、形式フラグ、訓練用識別結果、Mat(), Mat(), Mat(), Mat(),パラメータ = CvBoostParams()、更新フラグ = false);

 訓練用データは、CV_32FC1のMat型で、一つのrowに一つのデータベクトルを入れておく。rowの数がデータの数で、フラグには、CV_ROW_SAMPLE = 1を入れる(訓練用データの並びに合わせる)。訓練用識別結果の型は、CV_32FC1のMat型で、responsesと呼ばれる。訓練用のデータのそれぞれが、どの結果(レスポンス)に対応するかを教えるためのもので、一つのrowのみに、直列的に順次入れておく。
 Mat()が4個並んでいるのは、すべてデフォルト値で、意味は省略するが、一般的にはこのままで良い。
 パラメータには、後述するCvBoostParams構造体のオブジェクトを入れる。これを省略すると、パラメータの設定が無効になる。更新フラグは、弱識別器を追加する際に、単なるupdateで行うか、作りなおすかを指定する。デフォルトのfalseで良く、省略できる。
 predictメソッド ---- 入力データを与えて、float型の分類結果responseを返す。

     response = predict(入力データ);

 入力データ以外にも、引数が存在するが、一般的には、デフォルトのままで良い。
◎CvBoostParams構造体
 パラメータには次のものがあるが、一般にはデフォルト条件で十分である。
 boost_type -------- CvBoost::DISCRETE、CvBoost::REAL、CvBoost::LOGIT、CvBoost::GENTELEがあるが、デフォルトはREAL
 weak_count ------- 弱識別器の数、デフォルトは100
 weight_trim_rate ---- 計算時間短縮のため、訓練の繰返しごとに重みの小さい訓練用サンプルを削除する割合、デフォルトは0.95
 max_depth -------- 決定木の深さ(段数)、デフォルトは1
 use_surrogates ---- 入力データ不足の際に、代理分岐をするかどうか、デフォルトはtrue
 priors ----------- 事前確率配列を与えて、結果を誘導する場合に使用する。デフォルトはNULLまたは0
 以上は、コンストラクタで一度に設定しても良いし、個別に設定しても良い。


図1 顔データを描画するメソッドを用意する



図2 真顔10個、偽顔10個の訓練用顔データを準備する



図3 訓練用顔データを表示し、訓練用の真偽ラベルを準備する



図4 Boostを訓練し、テスト用データtest_dataを用意する



図5 テスト用データの表示とともに、Boostの判定結果を表示する



図6 真顔と偽顔に分けて、訓練用データを表示する



図7 訓練に使った顔データの一部でテストした結果、完全に正しく判定できた



図8 訓練に使っていない新しい顔データでテストした結果、なんとなく納得できた


前章(「・・・による画像処理と認識(15)」)で用いたデータで、ブースティングを試してみる
 
二次元座標データをバイナリ分類する前章のデータとラベルを使って、AdaBoostでどのような結果が出るかを試した。図9は、プログラムの一部で、Boostパラメータは、タイプのみを色々な種類にし、他はデフォルトのままにした。
 分類容易なデータで得られた結果を、図10に示す。いずれのタイプでも同様に良好な結果が得られた。
 同一領域が二分されている分類困難な場合では、図11〜12のように、いずれのタイプも十分ではなかった。
 このAdaBoostでは、マルチクラス分類はできない。


図9 二次元座標値をバイナリ分類する訓練と結果を求めるプログラム



図10 どのブースト・タイプでも良好に分類できた



図11 領域が二分されているデータは、デフォルトのREALも、その他も正しく分類できない



図12 GENTLEでは、さらに不可解な分類をする


結 論
 AdaBoostによる顔検出、すなわち、真顔と偽顔(非顔)の識別は、一般に数1000規模のサンプルを使用し、Haar-like特徴などに変換してからAdaBoostを訓練する。検出時にも、この特徴量に変換してから、AdaBoostで判定する。
 ここでは、このような手続きを省略し、顔に見立てた図形の9個の部位の有無を、直接AdaBoostに与えて訓練し、結果も同様にしてテストした。訓練のためのサンプル数も、合計20個の、きわめて小規模であった。
 すべてデフォルトの条件(Real AdaBoostがデフォルト)であったが、訓練に使用した顔データは、すべて正確に識別でき、訓練に使用していない顔データでも、納得できる識別結果が得られた。
 参考に試みた、「・・・による画像処理と認識(15)」と同じデータを用いたバイナリ分類では、二分類容易な単純な場合しか正しく分類できなかった。これは、SVMのように、カーネルによる写像を行っていないためと思われる。

参考文献
 Y.Freund and R.Schapire,"Experiments with a New Boosting Algorithm"(1996)
 http://www.cis.upenn.edu/~mkearns/teaching/COLT/boostingexperiments.pdf

 Y.Freund and R.Schapire,"A Decision-Theoretic Generalization of On-Line Learning and an Application to Bosting"(1997)
 http://face-rec.org/algorithms/Boosting-Ensemble/decision-theoretic_generalization.pdf

 R.Shapire and Singer,"Improved Boosting Algorithms Using Confidence-Rated Predictions"(1999)
 http://www.cs.iastate.edu/~honavar/singer99improved.pdf

 R.Schapire,"The Boosting Approach to Machine Learning: An Overview"(2003)
 http://www.cs.princeton.edu/courses/archive/spring07/cos424/papers/boosting-survey.pdf

 I.Mukherjee and R.Shapire, "A Theory of Multiclass Boosting"(2013)
 https://www.cs.princeton.edu/~imukherj/nips10.pdf




「Visual C++の勉強部屋」(目次)へ