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++の勉強部屋」(目次)へ