dlibのSimple_Object_detectorを用いたPythonでの物体検出器の学習
- はじめに -
これはこの記事の続きで、dlibを使って物体検出をしようというものである。
まあ正確には、dlibには「顔検出器の学習」ってのは無くて「物体検出器の学習」の機能を使って、顔検出器の再学習がしたいという記事です。
dlibを使う際の参考になればよいです。
- dlibのObjectDetectorについて -
dlibに物体検出の学習が入ったのは2014年の時。
内部にはHoG+SVMを使っていて、OpenCVで学習する場合に比べて、遥かに少ない学習データで、かなりの精度を出す事ができる。
リリース時の本家記事 : dlib C++ Library: Dlib 18.6 released: Make your own object detector!
本記事では、Pythonのdlib apiを使って、物体検出器の学習を行っていく。
Python用のドキュメント : Classes — dlib documentation
dlib.simple_object_detectorを使う。
一応、こちらに公式の学習サンプルがある。
http://dlib.net/train_object_detector.py.html
大体の事は書いてあるけど、パラメータ等が全部書いてある訳ではないので、日本語訳してごにょごにょしたものをリポジトリに置いておいたので見て頂ければ。
- 学習形式とサンプル -
ディレクトリ内の画像と矩形情報が入ったテキストファイルを元に学習するスクリプトは以下。
#! /usr/bin/python # -*- coding: utf-8 -*- u"""rect.txtと画像データを用いてdlibを追加学習するスクリプト.""" import dlib import os from skimage import io input_folder = "./test/" rect_file = "./true_rect.txt" output_svm = "detector.svm" def get_rect(rect_file): u"""矩形ファイルを読み込みリスト化.""" rect_list = [] for line in open(rect_file, 'r'): rect_list.append(line) return rect_list def make_train_data(rect_list): u"""矩形リストから学習用データを生成する.""" boxes = [] images = [] for i, x in enumerate(rect_list): # 改行と空白を除去してリスト化 x = x.replace('\n', '') x = x.replace('\r', '') one_data = x.split(' ') # 矩形の数k k = len(one_data) / 4 # 矩形をdlib.rectangle形式でリスト化 img_rect = [] for j in range(k): left = int(one_data[j*4]) top = int(one_data[j*4+1]) right = int(one_data[j*4+2]) bottom = int(one_data[j*4+3]) img_rect.append(dlib.rectangle(left, top, right, bottom)) # boxesに矩形リストをtupleにして追加 # imagesにファイル情報を追加 f_path = input_folder + one_data[k*4] + '.jpg' if os.path.exists(f_path): boxes.append(tuple(img_rect)) images.append(io.imread(f_path)) return boxes, images def training(boxes, images): u"""学習するマン.""" # simple_object_detectorの訓練用オプションを取ってくる options = dlib.simple_object_detector_training_options() # 左右対照に学習データを増やすならtrueで訓練(メモリを使う) options.add_left_right_image_flips = True # SVMを使ってるのでC値を設定する必要がある options.C = 5 # スレッド数指定 options.num_threads = 16 # 学習途中の出力をするかどうか options.be_verbose = True # 学習許容範囲 options.epsilon = 0.001 # サンプルを増やす最大数(大きすぎるとメモリを使う) options.upsample_limit = 8 # 矩形検出の最小窓サイズ(80*80=6400となる) options.detection_window_size = 6400 # 学習してsvmファイルを保存 print('train...') detector = dlib.train_simple_object_detector(images, boxes, options) detector.save(output_svm) if __name__ == '__main__': rect_list = get_rect(rect_file) boxes, images = make_train_data(rect_list) training(boxes, images)
simple_object_detector_training内部でデータの増量を行っており、optionのupsample_limitとadd_left_right_image_flipsで調整できる。
データの増量では、基本的なData Augmentationが行われているため、学習用のデータは最小で良い。
実際、公式のサンプルコードでは、22枚のサンプル画像と矩形情報を学習用データセットとして、高い精度の顔検出器を作っている。
あまり画像を入れるとMemoryErrorの原因となる。
大体こんな感じで止まったら、Optionのパラメータ調整しなおすか、画像を減らすか、メモリを増やす必要がある。
Traceback (most recent call last): File "detector.py", line 104, in <module> boxes, images = make_train_data(rect_list) File "detector.py", line 70, in make_train_data images.append(io.imread(f_path)) File "C:\Python27\lib\site-packages\skimage\io\_io.py", line 61, in imread img = call_plugin('imread', fname, plugin=plugin, **plugin_args) File "C:\Python27\lib\site-packages\skimage\io\manage_plugins.py", line 211, in call_plugin return func(*args, **kwargs) File "C:\Python27\lib\site-packages\skimage\io\_plugins\pil_plugin.py", line 37, in imread return pil_to_ndarray(im, dtype=dtype, img_num=img_num) File "C:\Python27\lib\site-packages\skimage\io\_plugins\pil_plugin.py", line 111, in pil_to_ndarray frame = np.array(frame, dtype=dtype) MemoryError
dlibの公式Q&Aで「MemoryErrorって出るんだけど…」という質問に対して、作者が「Buy Memory!」と応えているくらいなので仕方ない。
感覚としては、32Gメモリ積んだマシンでも、100*100サイズの画像1000枚を、add_left_right_image_flips=true、upsample_limit=4とかで学習させたら落ちる。
CPUもフルに使うので最悪PCフリーズが有り得る。
学習データを減らすのが手っ取り早いが、対応できる環境が少なくなる。
マシンかパラメータでなんとかこうとかするのが良い。
(こういう点から、dlibの物体検出器学習クラスは背景や周りの環境が固定な場合超強いって感じする。)
64Gメモリ、16コアのCPUでも100*100の画像2000枚くらいが限界っぽい。
それ以上はパラメータ調整云々でもなんともならなかった。
学習用の矩形情報と画像情報はPythonコードで言うと以下のような形式で入力する。
boxes[n]とimages[n]が共通の情報となれば良い。
boxes_img1 = ([dlib.rectangle(left=329, top=78, right=437, bottom=186), dlib.rectangle(left=224, top=95, right=314, bottom=185), dlib.rectangle(left=125, top=65, right=214, bottom=155)]) boxes_img2 = ([dlib.rectangle(left=154, top=46, right=228, bottom=121), dlib.rectangle(left=266, top=280, right=328, bottom=342)]) boxes = [boxes_img1, boxes_img2] images = [io.imread(dir_path + '/xxxxxx.jpg'), io.imread(dir_path + '/yyyyyy.jpg')]
学習に使うrect.txtは
x1 y1 x2 y2 file_name x1 y1 x2 y2 file_name2
のような空白CSVっぽくなってる前提。
矩形が複数ある場合の1行は
x1 y1 x2 y2 x3 y3 x4 y4 file_name
といった形式で保存してあるものをパースしている。
いつかxmlにもする。
学習データ作って、xmlで学習させてる人は居たのでリンク貼っとく。
- 学習結果のsvmを使う -
前回の記事のdetector.runする部分を修正する。
- detector = dlib.get_frontal_face_detector() + detector = dlib.simple_object_detector("detector.svm") - dets, scores, idx = detector.run(img_rgb, 0) + dets = detector(img_rgb, 0)
自前で学習した学習器はスコアや第二候補を返さないっぽい。
- テスト -
前回の記事やGoogle Cloud Vision APIの記事で出したデータを元に学習させる。
例によって河村友歌ちゃんの顔画像でテストする。
はい、かわいい。
いつも顔検出ばかりやっていては仕方ないので、それっぽく猫の画像を学習させ適応する。
学習データは手動で矩形を出して、たった20枚作っただけ。
はい、かわいい。
- 考察 -
dlibの物体検出は内部でサンプリングもしてくれるので、正データとなる画像と矩形だけ集めれば良いし、精度も良いので結構良い。
パラメータも少なく物体検出できる方だと思う。
メモリとCPUはバカ食いするけど愛嬌がある。
v19.01現在で、追加学習のようなクラスはないため、既存のfrontal_faceのsvmファイルをsaveしてさらに学習とかはできない。
あと、メモリ少ないから学習データ小分けにして食わせようとかもできないのでつらい。
SVMなので仕方ない感じではあるが。
文中にも書いたけど、固定的な環境(監視カメラとか背景が固定とか)だと、手軽にかなり高い精度を実現できる。
それ以外ならOpenCVとかの検出器と組み合わせるか、CNNに突っ込んだ方が吉。
- おわりに -
dlib、Deep Learningとか強化学習とか新しい手法をガンガン積んでいってるし、期待したい。
まだまだかゆい所に手が届かないので「コントリビュータにさせてくれよ!」と思ったけどGithubリポジトリなかったのでつらい。
まあでも、やり取りするより1からオレオレで書いた方が早いなと思った。
ほんとそれなわかるアカデミア。
もろもろのコードはGithubのリポジトリに入れといたんでよしなに。
github.com
- 追記 -
--09/04--
dlibのGithubレポジトリは多分https://t.co/4tcFIopv8s だと思います
— きばんちゃん (@kivantium) 2016年9月4日
トップページに思いっきり書いてあるのにgithubレポジトリがないって言われたから、俺なんか変なこと言ってるのかもしれないと一瞬不安になった pic.twitter.com/6Leycy82zb
— きばんちゃん (@kivantium) 2016年9月4日
がんばります。
dlibを用いた顔検出器と物体検出器とその学習
- はじめに -
dlibのSimple_Object_Detectorクラスを使った物体検出用カスケードの学習をする記事。
dlibは機械学習ライブラリとして2006年から始まったプロジェクトで、基本的なSVMや線形アルゴリズム、Bayesian Network等に加えて、機械学習関係で用いるような画像処理ツールやグラフツールが付属している。
dlibは画像からの物体検出として顔検出を代表としたオブジェクト検出用のクラスが用意されている。
中身はHoG+SVMとシンプルな構成だが、矩形情報と正例画像を与えるだけで、学習用サンプルを生成し、HoGフィルターのパラメータ調整や学習を行ってくれるAPIがある。
C++とPythonをサポートしており、以下からはUbuntu 14.04デフォルトのPython 2.7とdlib v19.0を用いる。
- dlibのインストール -
Ubuntu環境へのインストールならこの記事が分かりやすいらしい。
一応コマンドだけ貼っておくので上から実行してけばUbuntu 14.04ならワンパン。
sudo apt-get update sudo apt-get upgrade sudo apt-get install python-setuptools sudo apt-get install python-pip sudo pip install numpy sudo apt-get install liblapack-dev libatlas-base-dev gfortran g++ sudo pip install scipy sudo pip install matplotlib sudo wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/3.0.0/opencv-3.0.0.zip sudo apt-get install unzip sudo unzip opencv-3.0.0.zip sudo rm opencv-3.0.0.zip sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff5-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen3-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev default-jdk ant libvtk5-qt4-dev sudo apt-get install cmake cd opencv-3.0.0 sudo cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_FFMPEG=OFF -D BUILD_opencv_python2=ON . // ここでの16はコア数。自分のコア数はnprocコマンド辺りで確認 sudo make -j16 sudo make install cd .. sudo cp opencv-3.0.0/lib/cv2.so /usr/local/lib/python2.7/site-packages/ //----------- 下記シンボリックリンクを貼らないとopencvをimportする時エラーが出る libdc1394 error: Failed to initialize libdc1394 http://stackoverflow.com/questions/29274638/opencv-libdc1394-error-failed-to-initialize-libdc1394 カメラとかのハードウェア用ドライバが邪魔するせいらしく、dlibやopencv使用自体に問題はない。 環境次第で再起動毎にシンボリックリンク貼り直す必要がある。具体的な解決策はまだないっぽい。 //----------- sudo ln /dev/null /dev/raw1394 //----------- python import cv2 でチェック //----------- sudo apt-get install git sudo pip install cython sudo pip install scikit-image sudo apt-get install python-dev python-numpy sudo apt-get install libboost-dev sudo apt-get install libboost-python-dev sudo apt-get install libboost-system-dev sudo pip install dlib //----------- python import dlib でチェック //-----------
多分これでdlibのインストールは出来ると思う。Permission deniedとかはよしなに。
- 最もシンプルな顔検出機能を使う -
dlibは標準で顔検出用にfrontal_face_detector()を提供している。
こののブログの他記事でも述べているが、OpenCVの標準の顔検出カスケードよりは遥かに性能が良いと思う。
シンプルに顔検出器を使ってテストしたい場合は下のようなスクリプトで簡単にできる。
#! /usr/bin/python # -*- coding: utf-8 -*- u"""dlibによる顔画像検出.""" import cv2 import dlib # 画像ファイルパスを指定 sample_img_path = 'sample.jpg' def facedetector_dlib(img, image_path): try: detector = dlib.get_frontal_face_detector() # RGB変換 (opencv形式からskimage形式に変換) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # frontal_face_detectorクラスは矩形, スコア, サブ検出器の結果を返す dets, scores, idx = detector.run(img_rgb, 0) # 矩形の色 color = (0, 0, 255) s = '' if len(dets) > 0: # 顔画像ありと判断された場合 for i, rect in enumerate(dets): # detsが矩形, scoreはスコア、idxはサブ検出器の結果(0.0がメインで数が大きい程弱い) # print rect, scores[i], idx[i] cv2.rectangle(img, (rect.left(), rect.top()), (rect.right(), rect.bottom()), color, thickness=10) s += (str(rect.left()) + ' ' + str(rect.top()) + ' ' + str(rect.right()) + ' ' + str(rect.bottom()) + ' ') s += image_path # 矩形が書き込まれた画像とs = 'x1 y1 x2 y2 x1 y1 x2 y2 file_name' # 顔が無ければ s='' が返る return img, s except: # メモリエラーの時など return img, "" if __name__ == '__main__': img = cv2.imread(sample_img_path) img, s = facedetector_dlib(img, sample_img_path) cv2.imwrite('output_' + sample_img_path, img) f = open('./rect.txt', 'w') f.write(s) f.close()
引数には画像とupsample_numの値を与えてやる。upsample_numは多分selective searchで見る枚数か回転拡大縮小で見る枚数を増やしているんだと思う。精度は向上するが、その分探索時間とメモリをめっちゃ使う。
返り値としては顔の矩形位置座標と各スコア、サブ検出器の結果が返ってくる。スコアは割と信用できるので使い勝手は良い。
Google APIの時と同じく例によって、画像をまとめてdlibの顔検出に投げるスクリプトを下記Gitリポジトリにまとめておいた。
いつかGoogleの方とまとめるかも。
https://github.com/vaaaaanquish/dlib_detection_python_script
- 一応検証 -
例のごとく適当にテスト
入力画像は最近コミケでのコスプレが可愛かった河村友歌ちゃん。
なんかもう顔検出系のデモをやる時は毎回お世話になってるナイスフリー素材。
入力
出力
はいかわいい。
- なんかおわりに -
なんかコード貼ったら長くなったので、Simple_Object_Detectorの学習に関する内容は次の記事に書いときます。
なんかごめん。
追記:書きました。
vaaaaaanquish.hatenablog.com
PythonでGoogle Cloud Visionを使った顔検出
- はじめに -
前回の記事でGoogle Cloud VisionのAPIキーを発行しました。
そのAPIキーを使って、Pythonを使った顔検出(Face Detector)をやります。
顔認識じゃないです。顔検出です。
- Google APIのFACE_DETECTIONになげるやつ -
以下Pythonコードです。
変数を変更します。
api_keyに発行したAPIキーを入れます。
とりあえずこのスクリプトでSample.jpgから顔検出が出来ると思います。
#! /usr/bin/python # -*- coding: utf-8 -*- '''Gooogle Cloud Vision APIに画像を投げるやつ.''' import base64 import cv2 from requests import Request, Session import json # ここにAPIキーを入れる api_key = '' # このスクリプトを単体で実行する場合はここにファイルパスを指定 sample_img_path = 'sample.jpg' # 検出する顔の数の最大数 (多いほどレスポンスが返ってくるのが遅い) max_results = 8 # DISCOVERY_URLは現時点(2016/08)でこれしかないのでこのまま DISCOVERY_URL = 'https://vision.googleapis.com/v1/images:annotate?key=' # cv画像と画像ファイルへのPathと検出最大数が引数 def facedetector_gcv(img, image_path, max_results): # 通信不良等を考慮してTry...expectしておく try: # base64convert用に読み込む image = open(image_path, 'rb').read() # 顔を検出するやつのResponse作成 str_headers = {'Content-Type': 'application/json'} batch_request = {'requests': [{'image': {'content': base64.b64encode(image)}, 'features': [{'type': 'FACE_DETECTION', 'maxResults': max_results, }]}]} # セッション作ってリクエストSend obj_session = Session() obj_request = Request("POST", DISCOVERY_URL + api_key, data=json.dumps(batch_request), headers=str_headers) obj_prepped = obj_session.prepare_request(obj_request) obj_response = obj_session.send(obj_prepped, verify=True, timeout=180) # Responseからjsonを抽出 response_json = json.loads(obj_response.text) # 返り値用 s = '' # 'faceAnnotations'があれば顔あり if 'faceAnnotations' in response_json['responses'][0]: faces = response_json['responses'][0]['faceAnnotations'] # 画像情報 s += image_path + ' ' # OpenCVで矩形を書き込み for face in faces: # 0と2が両端の番地 x = face['fdBoundingPoly']['vertices'][0]['x'] y = face['fdBoundingPoly']['vertices'][0]['y'] x2 = face['fdBoundingPoly']['vertices'][2]['x'] y2 = face['fdBoundingPoly']['vertices'][2]['y'] cv2.rectangle(img, (x, y), (x2, y2), (0, 0, 255), thickness=10) # 矩形情報を保存 s += (str(x) + ' ' + str(y) + ' ' + str(x2) + ' ' + str(y2) + ' ') # 矩形が書き込まれた画像とs = 'file_name x1 y1 x2 y2' # 顔が無ければsは空 return img, s except: return img, "" if __name__ == '__main__': # 画像読み込み img = cv2.imread(sample_img_path) # Goog;e API img, s = facedetector_gcv(img, sample_img_path, max_results) # 画像出力 cv2.imwrite('output_' + sample_img_path, img) # 矩形情報出力 f = open('./rect.txt', 'w') f.write(s) f.close()
PEP8ガン無視で横に長くてスマン。
- テスト -
フリー画像で顔があって可愛いと言えば河村友歌ちゃんかなと思い用意しました。
これを入力にします。
こうなります。
複数の顔画像が入った写真もテストしてみます。
こんな感じでmax_resultsで指定した数までは顔検出できます。
- レスポンス -
レスポンスで返ってくるのは以下の通りです。
{ "boundingPoly": 顔の矩形位置(4頂点のx,y座標) "fdBoundingPoly": 耳なども含めた顔の矩形位置(4頂点のx,y座標) "landmarks": 以下のパーツの位置、三次元座標軸(x,y,z) [ "UNKNOWN_LANDMARK" : 謎 "LEFT_EYE" : 左目 "RIGHT_EYE" : 右目 "LEFT_OF_LEFT_EYEBROW" : 左眉の左端 "RIGHT_OF_LEFT_EYEBROW" : 左眉の右端 "LEFT_OF_RIGHT_EYEBROW" : 右眉の左端 "RIGHT_OF_RIGHT_EYEBROW" : 右眉の右端 "MIDPOINT_BETWEEN_EYES" : 両目の中心 "NOSE_TIP" : 鼻の頂点 "UPPER_LIP" : 上唇 "LOWER_LIP" : 下唇 "MOUTH_LEFT" : 口全体の左端 "MOUTH_RIGHT" : 口全体の右端 "MOUTH_CENTER" : 口中央 "NOSE_BOTTOM_RIGHT" : 鼻の下右側 "NOSE_BOTTOM_LEFT" : 鼻の下左側 "NOSE_BOTTOM_CENTER" : 鼻の下中央 "LEFT_EYE_TOP_BOUNDARY" : 左目中央上境界 "LEFT_EYE_RIGHT_CORNER" : 左目右ライン "LEFT_EYE_BOTTOM_BOUNDARY" : 左目中央下境界 "LEFT_EYE_LEFT_CORNER" : 左目左ライン "LEFT_EYE_PUPIL" : 左目瞳 "RIGHT_EYE_TOP_BOUNDARY" : 右目中央上境界 "RIGHT_EYE_RIGHT_CORNER" : 右目右ライン "RIGHT_EYE_BOTTOM_BOUNDARY" : 右目中央下境界 "RIGHT_EYE_LEFT_CORNER" : 右目左ライン "RIGHT_EYE_PUPIL" : 右目瞳 "LEFT_EYEBROW_UPPER_MIDPOINT" : 左眉中間点座標 "RIGHT_EYEBROW_UPPER_MIDPOINT" : 右眉中間点座標 "LEFT_EAR_TRAGION" : 右耳 "RIGHT_EAR_TRAGION" : 左耳 "FOREHEAD_GLABELLA" : おでこ "CHIN_GNATHION" : アゴ、下顎下縁正中点 "CHIN_LEFT_GONION" : アゴの左側 "CHIN_RIGHT_GONION" : アゴの右側 ] "rollAngle" : 画像の回転角度 "panAngle" : 顔の左右回転角度, "tiltAngle" : 顔の左右回転角度, "detectionConfidence" : 顔検出信頼度 "landmarkingConfidence" : landmarksの信頼度 以下感情推定や状態推定 UNKNOWN 判定不能。 VERY_UNLIKELY, UNLIKELY, POSSIBLE, LIKELY, VERY_LIKELYで返ってくる。 "joyLikelihood" : 楽しそう "sorrowLikelihood" : 悲しそう "angerLikelihood" : 怒ってそう "surpriseLikelihood" : 驚いてそう "underExposedLikelihood" : 肌を露出してそう "blurredLikelihood" : ぼやけてそう "headwearLikelihood" : 帽子とか付けてそう }
返ってきすぎ。
感情推定や状態推定はちょっと精度悪くてあんまり信用できないです。
ただ、横顔や顔が途切れてても結構返ってくるのですごい精度です。
後Landmarkが返ってきたりするのも学習用データ作りが捗りますね。
- 精度に関する知見 -
OpenCVとdlibで顔検出をおこなった場合の知見を以前まとめました。
OpenCVは無駄な矩形を多く出力して、recallを上げてくるイメージです。
OpenCVでは、入力に顔画像の最小サイズを指定できますが、結局そのパラメータを調整すると顔がそのサイズ以下になった時に検出できないのでう~んという感じです。
ただ、追加の学習が非常に簡単に行えるので、精度向上を測るのはやりやすいですね。
Anime_Faceを代表に、色んな状況での顔検出に最適化する事ができます。
対してdlibは、デフォで顔検出に関してとても精度が高いです。
ただ、中身にHoGとSVMを使っている事もあり、顔っぽい文字やロゴを検出してしまうのがネックです。
また、オブジェクト検出用の学習も出来るには出来るんですが、学習用の関数がまだまだ使いにくい事もネックですね。
対して、Google Cloud Visionは追加での学習こそ出来ませんが、ものすごい精度で検出してきます。
しかも無駄な矩形をほとんど返さないのが魅力的です。
デフォルトの検出器を適当にprecisionで言うなら OpenCVが0.3、dlibが0.6、Googleは0.98という感じです。
しかも状態情報もくれるのでサイコー。
- 料金体系 -
最後に料金体系はこんな感じです。
- | ~1000枚 | ~100万枚 | ~500万枚 | ~2000万枚 |
---|---|---|---|---|
1000枚毎に | Free | $2.50 | $1.50 | $0.6 |
限度枚数投げると | Free | $2497.5 | $8496.0 | $16895.4 |
限度枚数投げるとというのは、例えば100万枚投げた場合、最初の1000枚はFreeの価格が適応されるので無料。その後の999000枚は$2.5/1000枚かかるので総額が
F + 999000 * 2.5 / 1000 = $2497.5
という感じです。その後も同様に計算して
F + $2497.5 + (3999000 * 1.50 / 1000) = $2497.5 + $5998.5 = $8496.0
F + $2497.5 + (3999000 * 1.50 / 1000) + (13999000 * 0.6 /1000)
= $8496.0 + $8399.4 = $16895.4
日本円にすると2000万枚投げたら大体180万円くらいですね。
ただ、今は初期登録で60日間使える$300を貰えるので、無料で$2.5/1000枚とFree分合わせて12万と1000枚投げられます。
12万枚かなりの精度で色んな情報が返ってくると思うと、課金まで行かなくても全然使えますね。
後、これ以上投げる場合の金額は相談してねって感じみたいです。
Googleの公式の金額のページはここ。相談先もここ。
https://cloud.google.com/vision/docs/pricing
他にもラベル検出(LABEL_DETECTION)、文字検出+OCR(TEXT_DETECTION)、 有害コンテンツ検出(SAFE_SEARCH_DETECTION)、各物体のランドマーク検出(LANDMARK_DETECTION)、ロゴマーク検出(LOGO_DETECTION)、色解析(IMAGE_PROPERTIES)が使えて、それぞれ大体同じ金額になると思います。
何故かラベル出すやつだけ高いです。企業にお金でも払ってるんでしょうか。
- おわりに -
人工知能だので画像認識系の機械学習技術が話題という事もあり、機械学習APIがポツポツ出てきてますが、精度や安定性はやっぱりGoogleには勝てないですね。
中身はDeep Learning、R-CNN辺りでしょうか。
1レスポンスで返ってくる辺り、感情推定なんかも同じネットワーク内でやってそうですね。
すごいぞGoogle。流石だGoogle。
「とりあえず顔検出用の学習データが欲しい」という時に無料枠でとりあえず使えますね。
そのデータを使いながら、環境に対して最適化していけば良いと思います。
あと、他のAPIも使う記事を気が向けば書きます
一応フォルダ内の画像を全部Google APIに投げて「顔画像あり」「顔画像なし」に分けて矩形情報を保存するスクリプトを書きました。
上部の画像単体を投げるスクリプトも一緒にGitリポジトリに入れてますので以下参照。
Google Cloud Visionを登録しよう
- はじめに -
Google Cloud Visionがすごい。とにかくすごい。
クレジットカードが無いと利用出来ないのはちょっとネックだけど。
でも今なら$300分を無料で使えるし、機械学習データ作る用にでも是非。
- APIキー発行まで -
Google Cloud PlatformのコンソールにGoogleアカウントでログインする。
https://console.cloud.google.com/home/dashboard
初回にクレジットカード情報を登録しろと通知が来た場合は、素直に登録する。
先述の通りクレジットカードを登録して課金を有効にしないとGoogle Cloud Visionは使えない。無料枠はあれど、課金を有効にしないとダメ。
なので実質クレカ必須。
通知が出なかった場合は、課金を有効にするため以下をクリック。
Google Cloud Platform の無料試用、利用規約に同意して続行。
個人情報とクレジットカード情報を入力して続行。
割りと丁寧にこんな通知が出る。
Google Cloud Platformはプロジェクト単位で管理ができる。
最初に新しいプロジェクトを作成する。
上部ヘッダー、左上から「プロジェクト」>「プロジェクトの作成」をクリック。
名前を入力しろとダイアログが出るので、自分の管理しやすい適当な名前を入力して「作成」。
右上の通知マークがくるくる回っている間は作成中なので待つ。
大体3分くらいで作成される。カップ麺と同じ。
できたら今度は左上のプロジェクトが変わる。もしくはクリックして変える。
基本はここにプロジェクト名が出てるので、自分の作成した設定なんか違うな~と思ったらまずプロジェクト名を見る。
プロジェクト名を確認しつつ、「APIを利用する」をクリック。
API Managerなるページに飛ばされるので、「+ APIを有効にする」をクリック。
色んなAPIの名前が出てくるけど、Google Cloud Visionは多分見当たらないと思うので検索ボックスに「Google Cloud Vision」と入力する。出てきたらGoogle Cloud Visionをクリック。
こんな感じの画面に飛べば正解。
まずはじめに「▶有効にする」をクリック。
こうなると思うので「認証情報に進む」
左側の認証情報からでも設定できるっちゃできる。
次の記事でPythonからAPIキーを叩いて画像認識をしたいと思うので、とりあえずブラウザキーを発行する。
「ウェブブラウザ(JavaScript)」こ表記はなかなか不親切だがこれでOK。
他の形式で欲しい人は他で。
次にAPIにつける名前を適当に考えて入力する。
HTTPリファラは、個人で使う分には必要なし。会社で使うならそのドメインを入力した方が良さ。
「APIキーを作成する」。
そしたらもうAPIキーが出てくるのでおしまい。「完了」
最後に出るAPIキーをコピペしておいても良いし、画面左の認証情報からいつでも参照できる。
OpenCVとdlibとOpenFaceでの顔検出と知見まとめ
- はじめに -
色々あって顔検出をする機会があった。世の中、顔認識(Face Recognition,Facial Recognition)と顔検出(face detection)がごっちゃになってるじゃねえかと思いつつ、とにかく画像から人の顔を高精度で出したいんじゃという話。
先に結論を言うと、OpenCVよりはdlibの方がやっぱり精度良くて、OpenFaceも使って動かしたんだけどそんな変わらないし、でもまあ先はあるよって話。
OpenFaceで顔検出と言っても、実際にはdlib(もしくはOpenCV)の顔検出とTorch7のCNNを接続するフレームワークのようなもので何でこれが話題になった時期があったのかという感じがある。
環境はUbuntu 14.04を想定。
- インストールして動かすかれこれ -
まずは必要な物をインストールする。
厳しい環境に身を置いているので、最初WindowsでOpenCVとdlibを動かした。Windowsでもインストーラとpipが使えれば出来るので奇跡的に出来た。時代は変わった。
OpenFaceはLinux, Unix環境しか対応してないとの事だったので、仕方なく仮想環境を作りインストールした。
環境は Ubuntu 16.04 LTS
必要なものは以下の通り
- python (Ubuntu デフォルトで可)
- python pip
- numpy
- scipy- torch7 (機械学習, Deep Learningライブラリ)
- opencv
- 必要な周辺ライブラリ沢山
- cmake- dlib
- boost
- boost-python
- scikit-image- openface
多い。OpenFaceの公式Setupには「Docker用意したから使ってくれよな」とあったけど、「"tested in Ubuntu 14.04 and OSX 10.10"」とも書いてあるし、OpenCVは先月3.x系が出てるしでダメそうだったので全部手動で入れた。インストール前にこの辺を読んで遺産感があるのに気付くべきだった。
- インストール作業 -
pythonはUbuntuデフォルトで充分。一応バージョンを確認するけど大抵2.7系だと思う。
python -V
一応定番apt-getのアップデートをしておく
sudo apt-get update sudo apt-get upgrade
パッケージ管理はやっぱりeasy_installとpip
sudo apt-get install python-setuptools sudo apt-get install python-pip
pipを入れたらまずはこの三種の神器
pip install numpy sudo apt-get install liblapack-dev libatlas-base-dev gfortran g++ pip install scipy pip install matplotlib
wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/3.0.0/opencv-3.0.0.zip sudo apt-get install unzip unzip opencv-3.0.0.zip
必要な周辺ライブラリを全載せ
sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff5-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen3-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev default-jdk ant libvtk5-qt4-dev
libtiffはUbuntu 14.04辺りからlibtiff5推奨になったらしいlibtiff4-devはエラーが出た。
cmakeを準備しつつコンパイル
sudo apt-get install cmake cd opencv-3.0.0 cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_FFMPEG=OFF -D BUILD_opencv_python2=ON . make -j1 sudo make install
make -jの後は自分のコア数を入れる。
Linuxだと一番簡単なコマンドは多分 nproc と打つ事。
今回は仮想環境なので1。
python用の設定はopencvのlib内にあるcv2.soというファイルをsite-packages以下に入れるだけ。GUIでやってもOK。
cp ~/ path to opencv /opencv-3.0.0/lib/cv2.so /usr/local/lib/python2.7/site-packages/
Linux系だとcv2用にリンクを貼っておく必要がある。
でないと" libdc1394 error: Failed to initialize libdc1394 "といったErrorが出る、
sudo ln /dev/null /dev/raw1394
python起動してimportできるか確認しておく
python
>>> import cv2
>>> cv2.__version__
'3.0.0'
>>> exit()
次はdlib。
dlibは前提としてgitが要るので先にそちらを準備しておく。
sudo apt-get install git
加えて前提として必要なskimageとライブラリ
sudo pip install cython sudo pip install scikit-image
確かdlibはpipで入れれば下記作業不要だけど、結局OpenFaceを入れる前にTorch7が必要で、その前提としてboostが必要みたいな感じで入れた気がする(曖昧)。
多分pipで入れても" Could NOT find Boost "なるエラーが出ると思うのでやったら吉。
sudo apt-get install python-dev python-numpy sudo apt-get install libboost-dev sudo apt-get install libboost-python-dev sudo apt-get install libboost-system-dev
boost.numpyのインストールは他に作業が必要だけど今回は無用
一応やりたい人向け参考URL(http://ttlg.hateblo.jp/entry/2015/12/17/124747)
多分これでdlibは入る(Windowsもboostインストーラとpipが動くのでここまではできる)
sudo pip install dlib
python起動してimportできるか確認しておく
python
>>> import dlib
>>> dlib.__version__
'18.17.100'
>>> exit()
次にTorch7を入れる。
git clone https://github.com/torch/distro.git ~/torch --recursive cd ~/torch sudo dpkg --configure -a bash install-deps ./install.sh
インストールの文字が最後に
Do you want to automatically prepend the Torch install location to PATH and LD_LIBRARY_PATH
と聞いてくるので yes と入力するると .bashrcにexportが追記される。
一応 source ~/.bashrc するかbashを再起動しておく。
witch thでpathが出て来ればOK。出てこない場合はPathを設定する。
~/.bashrcを開いて
export PATH=~/torch/bin:$PATH; export LD_LIBRARY_PATH=~/torch/lib:$LD_LIBRARY_PATH;
を追記する。
Torchにはluaのパッケージが幾つか用意されていて、今回のサンプルを動かすのに必要な物があるのでインストールしておく。
luarocks install nn luarocks install dpnn luacocks install optim luarocks install csvigo
lualocks installでインストール推奨とされているのは以下があるけど、ディープラーニングのトレーニングやCUDAを使う場合のみなのでインストールしてない。
必要そうだと判断したらインストール
cutorch and cunn (only with CUDA)
fblualib (only for training a DNN)
tds (only for training a DNN)
torchx (only for training a DNN)
optnet (optional, only for training a DNN)
上のやつを全乗せしたい時
for NAME in dpnn nn optim optnet csvigo cutorch cunn fblualib torchx tds; do luarocks install $NAME; done
Torch7で使うluarocksだと、無難に以下をインストールしておくと良い。
luarocks install image luarocks install nngraph
やっとOpenFace
git clone https://github.com/cmusatyalab/openface ~/openface --recursive cd ~/openface sudo python setup.py install
無事通れば終わり
- サンプルを動かす -
サンプルとして提示されてるのは以下のcompare.py
https://github.com/cmusatyalab/openface/blob/master/demos/compare.py
まず前提としてdlibの顔検出用のlandmarks.datファイルを用意する
自前で用意しなくても、modelsディレクトリにスクリプトが入っているので基本はそれで。
cd ~/openface/models ./get-models.sh
~/openface/の中に好きなsample.jpgとsample2.jpgを突っ込んで
python demos/compare.py ./sample.jpg ./sample2.jpg --verbose
って感じで入力して実行。--verboseでは動作詳細を見れる。
サンプルは「顔の場所を検出してcropして学習済みネットワークで特徴量化しそのベクトルのL2距離を比較する」というもの。
本家は「"OpenCV or dlib"」と言っているが、この推奨サンプルではcv2の画像読み込みでロードして顔検出精度が高いdlibで顔検出しているので「dlibもOpenCVも結局どっちも要るじゃねえか!」となる。
なんかそれっぽい数値が出たら終わり
正直もっと良いサンプルあるやろと思う。
- 感想 -
OpenFaceだけど、Deep Netなら他の便利なフレームワークがある印象が強い。dlibやOpenCVと簡易的に接続できると言っても、最近は他が簡易的になったし。
API(OpenFace API Documentation — OpenFace API Docs 0.1.1 documentation)を見てもそんな便利な機能があるわけではない。
各Deep LearningライブラリとdlibやOpenCVが個別で扱える事のメリットの方が大きいかなと思った次第。
Torch7で顔の分類や回帰を行っている。その学習済ネットワークがある、または入手できる。といった状況以外ではあまり使わなそう。
海外だとTorch7結構流行ってるのかなと思ったところで終わり。正直chainerやkerasが良いと思うよ正直。
記事を書くなら精度検証しろよとも思うけど、やっぱ所感でdlibが良い程度しか言う事がない。
dlibはHoG+SVMを使っているらしく、OpenCVはHaar-Like+Adaboostを使った物体検出系のカスケードらしい。
どちらもデフォルトだとSliding Windowやってるみたいで、dlibの方はSelective Searchとかも使えるけど顔検出だと微妙なのではと思う。
dlibの方が精度が良いのは目視した感じ確かだけど、Window走査の時間設定のパラメータ(upsample_num_times)を最小の0以外にすると処理時間が長く、2以上だと+メモリが必要だった。適当な仮想環境では落ちる程度に重かった。あと2以上にしてもそんな大胆に精度改善が見込める訳ではない。
OpenCVの方が遥かに軽いし、OpenCVでググってると「ここに乗ってるAdaboostを使った検出器はクソ早いし最高なんだ!Viola & Johnsが作ったスゲーやつなんだ!」と書いてあったりする。OpenCVはデフォルトのカスケードファイルがいくつかあって、顔だけじゃなく、目や耳用があったりする(全て実験してる人の記事:OpenCV 使用可能なCascadeClassifierの種類と効果 - Symfoware)。その辺は有効活用できそう。追加での学習もできるっぽい。
顔認識本当にやるならOpenCVとdlibを組み合わせてある程度データを作り、ちゃんと特徴量と学習器作ったりDeep Netにぶち込むのが良いんじゃないかと思った。
もう少しdlib使ってみたら日本語の記事増やしたいので書くかも。後はGoogle Cloud APIの顔認識も気になってはいる。
あと、「顔検出」とかでググるとオタクがとりあえずアニメ画像認識やってみたって感じのブログが山のように出てくるので日本語でググるよりは英語を乗り越えて公式のドキュメント理解に努めたほうが良いかも。
Active Object Localization with Deep Reinforcementを作っている
- はじめに -
この記事はDeep Learning Advent Calendar 2015の24日目の記事です.
Deep Q-Network(DQN)がNIPSで発表されてから*1はや2年.
DQNは, 深層強化学習として一分野を確立し, 機械学習分野自体の活発さ, Deep Learningの話題性も相まって, 怒涛の勢いで新しい研究成果が発表されています.*2
この記事では, DQNを物体認識タスクに応用したActive Object Localization with Deep Reinforcement Learning[ PDF ]について解説, 実装を行っていこうと思います.*3
(12/24現在まだ思うように実装が出来てませんすいません)
- 背景 -
そもそも物体認識タスクとは, 画像から特定の物体を検出するタスクの事を指します.
例えば, 私が昨年kazoo04 Advent Calendarで行ったものがそれですね.
この時の記事では, 画像の中からkazoo04という特定の物体(人物)を検出しています.
この記事で私は, kazoo04かどうか分類する学習器にかける前に, 様々な大きさの窓をスライドし, その枠内を入力としています(sliding window, Exhaustive Search).
この手法は, かなり以前から物体認識タスクで多く用いられていましたが, 元の画像サイズや窓を移動させる幅によって, かなりの計算時間がかかってしまう問題がありました.
またConvolutional Neural Networks(CNN)という画像認識に強いDeep Learningの手法が流行し, 学習器の性能が格段に向上しました.
過去のブログの記事にもしていますが, それまでSHIFTやHOGのような特徴量抽出を挟む事で実現していた認識処理を学習器1つで行えるようになりました.
こうのように機械学習による画像認識の精度が高まって行く中で, Exhaustive Searchで計算時間を使っていてはリアルタイム認識なんかは無理だよねという流れが出てきました. また, sliding windowのスケールの違いによって入力も違うため, 誤認識が発生するという問題もありました.
そこで, Exhaustive Searchのスケールによる誤認識を減らすための画像処理手法や計算量を減らす手法*4, 物体検出に対して効率的な手法*5が出てきたり, CNN以外でもsliding windowの欠点を補うようなRandom Forest的手法*6が出てきたりしました.
そして, 次の大きな成果としてR-CNNというモデルが現れました. R-CNN*7はGirshickらが2014年に提案した手法で, 先に物体が入る窓を推定*8し, その窓(window, bounding box)を入力としています.
CNN部分では, その入力を分類する学習に加えて, そのbox自体を矩形回帰するように学習させる事で, 物体の場所検出とその分類を同時に行う事ができるようになります.
分類と回帰を同じ学習器でも行うという点でも, CNN, ニューラルネットワークの強みを活かした手法です.
R-CNNは当初, ネットワークの大きさ等から認識に時間がかかるという問題がありましたが, Fast R-CNN*9のような改良手法が提案され, 今回用いてるPascal VOC(http://host.robots.ox.ac.uk/pascal/VOC/)というデータセットにおいてもかなりの結果を出しています.
近年では上記のようなCNNで抽出した特徴量をRNNにつなげることで, センテンス表現の学習を行う手法(Image Captioning*10 )等も発表されています.
今回のDQNを用いた手法は, 今までの趣向とは少し異なっており, トップダウンな探索によって物体の位置を検出するアルゴリズムになっています.
最初に画像の大きな領域を入力とし, 動的にその入力領域を変化させていきます. 動的な探索において強化学習(Q-learning)な技術が使われています.
また, マルコフ決定過程(MDP)に基づいた動的探索ステップを複数回行う事によって, その回数だけ複数の物体を検出する事も可能にしています.
- Q-learningな部分 -
一般的なQ学習の要領を用います. 以下に行動と報酬を示します.
- 行動
行動は8つのActionと終端条件(trigger)に分かれています.
Actionは, 入力範囲の上下左右の移動と拡大縮小です.
また, 全てのActionは以下の2式によって制御することができます.
は幅を制御するパラメータで, 論文中ではとして固定の値を用いています.
が大きければ探索が雑になり, 小さければ時間がかかるという事が感覚的にもわかると思います.
また, Triggerは1つの探索終了を示します.
inhibition-of-return(IoR)*11を参考に, 探索が終了した時点で, box内に十字のマークを挿入します. これは, 次の探索で同じ領域がゴールになることを防ぐためです.
報酬の定義を基に複数回繰り返す事で, 複数の物体を認識する事を可能にしています.
- 報酬
報酬関数にはIoU(Intersection-over-Union)を用います. IoUは, boxである(box)に対して, 目的となる領域(ground truth box)がどれだけ含まれているかとなります.
IoUを用いて, 状態において行動を行って状態に遷移する時の報酬関数は, 以下のように定義されます.
ある状態のIoUから次の状態へのIoUの差ですね.
またこの値は正負がbinaryで制御されます.
しきい値を超えていれば, 無ければの報酬という形です.
論文中ではに設定されています. は経験則によるものが大きく, はデカすぎるとなかなか達成できないので0.6という感じみたいです.
- 学習手法
学習では, パラメータを初期化した後, 目標となるに対して率直に+-で進むよう行動を選択していきます.複数目的があった場合は, 内1つがランダムに選択されます.
しかし, すべて貪欲に動いていれは汎化性能が上がらないため, 全てのtraining画像に対して学習を終えた後, ε-greedy法を用いた学習を行い探索します.
論文中では, ε-greedyなTrainingを15epoch分回しますが, 最初の5epochでを1~0.1に線形に下がるよう設定しているようです.
また, boxのスタート地点は4隅から, 全体の75%のサイズで始めます.
- CNNな部分 -
CNNのネットワーク構成は, 以下のようになっています.
実際にQ-learningを適応しているのは後ろ3層のみです.
これについては論文中でも言及されており, 前層のpre-trainingによって学習収束速度が向上すること, 全体を学習するにはさらに大きなデータセットが必要と考えられる事などから, 今後の研究課題であるとされています.
ちなみにpre-training層は分類器としてVOCデータセット学習したCNNの特徴抽出部分を用いています.
入力は224*224に正規化された画像のベクトル.
出力はActionとTriggerを含む9ユニットです.
出力で強化学習におけるQtableを再現するイメージです.
NNの部分は誤差逆伝搬法(back propagation)による最適化, Dropoutによる正則化を用いています.
また, 過去10Actionをbinary形式で保存したaction historyと呼ばれるユニットをQ-Network以前の層に挿入しています.
これにより短期的に良い行動を学習する事が可能となり, 精度にして3%前後の向上が見られるようです.
Deep Q-Networkの学習機構については, 日本語であれば次の記事が分かりやすいかと思います.
DQNの生い立ち + Deep Q-NetworkをChainerで書いた - Qiita
- 実装 -
こんな感じなので少しまって
う〜ん…DLAC用のDQN、特にパラメータがおかしい訳でもなくerrorも下がるのに思った動作になってる感じしない。
— ばんくし (@vaaaaanquish) 2015年12月23日
DQNと比較するためにSelective Searchな手法を適当に実装したけど, Selective Searchの方はそれっぽくてDQNの方は上手くいってないアレ。
— ばんくし (@vaaaaanquish) 2015年12月24日
私はAdvent Calenderに遅刻しています(酒飲みながら)
— ばんくし (@vaaaaanquish) 2015年12月24日
*1:Playing Atari with Deep Reinforcement Learning - http://arxiv.org/pdf/1312.5602.pdf
*2:自分もここ1ヶ月くらいで本腰入れて調査した程度なので詳しくはないです
*3:この記事で用いてる画像は論文中から引用したものです
*4:http://www.kyb.mpg.de/fileadmin/user_upload/files/publications/pdfs/pdf5070.pdf
*5:http://www.cv-foundation.org/openaccess/content_cvpr_2015/papers/Gonzalez-Garcia_An_Active_Search_2015_CVPR_paper.pdf
*6:http://www.habe-lab.org/habe/pdf/2011SSII_SIHF.pdf
*7:http://arxiv.org/abs/1311.2524
*8:bjectness. どちらかというとコンピュータビジョンな技術が多い. Selective Search(最初のR-CNN), BING等様々な手法がある
*9:http://arxiv.org/abs/1504.08083
*10:Deep Visual-Semantic Alignments for Generating Image Descriptions, http://cs.stanford.edu/people/karpathy/deepimagesent/
*11:http://www.cnbc.cmu.edu/~tai/readings/tom/itti_attention.pdf