【物体検出】AI開発者になりたいけど餅つきをしたくない

More than 1 year has passed since last update.


きっかけ

AI開発チームが「餅つき」をする理由」を紹介されたので、将棋AIで学んだ次の一歩を物体検出に決めました。

テレビ放送は見てないのでニュアンスは知りませんが記事から「正解をたくさん教え込まなければならないってエキスパートシステム作ってた人の発想か、GAN以前からDLの流れを追い損ねてね?」と印象を受けた。


技術調査@Qiita記事


道具と対象


やること


  1. chainercvインストール

  2. デモを動かしてみる

  3. 学習データをつくる


    1. アノテーションつける←ここを沢山はやりたくない

    2. 学習する




環境


再掲

ハード

CPU:i7-4770S @ 3.10GHz
GPU:GeForce GTX 750 Ti ドライバーのバージョン391.24
ソフト
Microsoft Windows 10 Pro (x64)
Visual Studio Community 2017
CUDA9.0
cuDNN7.1.2
python3.6.4(Anaconda3 5.1.0)
chainer3.5.0
cupy2.5.0


さきに結果


試行錯誤と手順


chainercvインストール


chainercvインストール

>conda env create -f environment.yml

>conda activate chainercv
>pip install -e .


デモを動かしてみる


  • 適当な画像を用意しておく(仮にa.jpgとしてコマンド実行する)



    • pixabayでとんかつとかプチトマトとか検索しとけばよいかと

    • 残念ながらダイニングテーブル、鉢植えなどざっくりした分類しか学習していない




a.jpgに対してデモ実行

>python examples\ssd\demo.py --gpu 0 a.jpg



【参考】トレーニング実行


愛機ではOutOfMemory

>python examples\ssd\train.py --model ssd300 --batchsize 32 --gpu 0



代わりにgoogleにやらせる

!apt -y install libcusparse8.0 libnvrtc8.0 libnvtoolsext1

!ln -snf /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so.8.0 /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so
!pip install 'cupy-cuda80==4.0.0rc1' 'chainer==4.0.0rc1'
!pip install -U numpy
!pip install chainercv
!git clone https://github.com/chainer/chainercv.git
!python chainercv/examples/ssd/train.py --model ssd300 --batchsize 32 --gpu 0


学習データをつくる


  • ペイントで丸、三角、バツを書く

  • バウンディングボックスにアノテーションをつける


  • VGG Image Annotatorツール


    • 導入が一番簡単でHTMLファイル1つで構成されています

    • Region Shapeがいろいろ選べるのですが、PASCAL VOCに寄せてRectangleにしておく

    • 出力がCSV|JSON、できたらXML(PASCAL VOC format)がよかった

    • viaでアノテーションをつける




学習する


  • 【コード改変】trainとdatasetを変更する


    1. アノテーションの記録、読み取り方法:XML→JSON(ツールの都合)

    2. ラベル:車とか人とか12種類のなんか→丸、三角、バツの3種

    3. PASCAL VOCからダウンロードする→用意した画像を読む

    4. 画像がJPG→PNG

    5. アノテーションのファイル数:画像ファイルと同じ→ひとファイル(ツールの都合)



  • 学習しようとするとOutOfMemoryになる

  • バッチサイズを小さくしてみる


バッチサイズ指定

>python train.py --gpu 0 --batchsize 6



  • やっぱりgoogleにやらせる

  • ソースと画像はzipにしてgoogle driveにuploadしておく


driveからソースと画像を取得する

# さっきの続き

!pip install -U -q PyDrive
from google.colab import auth
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from oauth2client.client import GoogleCredentials
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
id = 'ファイルの共有をしてIDを確認する、ここは内緒'
downloaded = drive.CreateFile({'id':id})
downloaded.GetContentFile('chainer-bbox.zip')
!mkdir chainer-bbox
!unzip chainer-bbox/chainer-bbox.zip -d chainer-bbox
!ls chainer-bbox


学習実行

import os

os.chdir('chainer-bbox')
!python train.py --gpu 0


  • モデル保存が随時のsnapshotでもいいけど回数ついてるし扱い面倒いので最終的なモデルをnpzシリアライズ追加

  • あとgoogleでも長いこと終わらないのでイテレート回数減

  • で改めて学習開始


検証する


  • 【コード改変】demo.pyでつかうラベルの名前を丸、三角、バツにする

  • いったん、学習データを丸だけに絞ってみる。かつひとファイルにひと丸だけにしてみる。

  • で検出。検出できた、もどき

  • これ失敗してます。原因は思い当たってます。やはり、学習データのつくりの問題。アノテーションで与えたバウンディングボックス領域が大きすぎました。

  • で再度学習やりなおし。


    • 丸をひとつ検出できた

    • 丸をふたつ検出できた



  • よし、できた。。。丸だけ。

  • 丸の学習データ12枚、検証用4枚の計16枚。ここまで餅つきはしてない。


学習データを餅つきする(準備のみ)


  • 使わなくなったけど学習の待ちの間に餅つきのスクリプト書いたので公開します。


    • 使い方:バッチファイルにPNGファイルをドロップする。

    • またはfor /f %%a in ('dir /b *.png') do call _rotate %%aで一括処理できる。とおもう。

    • 結果:元画像を90度、180度、270度、および水平反転で8倍に増やしてくれます。




_rotate.bat

if "x"=="x%1" goto usage

call :write_ps %1
call :run_ps
call :del_ps

goto :eof

:write_ps
>%~dpn0.ps1 echo ^
[void][Reflection.Assembly]::LoadWithPartialName("System.Drawing"^);^
$image = New-Object System.Drawing.Bitmap("%1"^);^
$image.RotateFlip("Rotate90FlipNone"^);^
$image.Save("%~dpn1_r90%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.RotateFlip("Rotate90FlipNone"^) ;^
$image.Save("%~dpn1_r180%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.RotateFlip("Rotate90FlipNone"^);^
$image.Save("%~dpn1_r270%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.RotateFlip("Rotate90FlipX"^);^
$image.Save("%~dpn1_x0%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.RotateFlip("Rotate90FlipNone"^);^
$image.Save("%~dpn1_x90%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.RotateFlip("Rotate90FlipNone"^);^
$image.Save("%~dpn1_x180%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.RotateFlip("Rotate90FlipNone"^);^
$image.Save("%~dpn1_x270%~x1", [System.Drawing.Imaging.ImageFormat]::Png^);^
$image.Dispose(^);^

exit /b

:run_ps
powershell -NoProfile -ExecutionPolicy Unrestricted %~dpn0.ps1
exit /b

:del_ps
del %~dpn0.ps1
exit /b

:usage
echo usage: %~nx0 filepath
>nul pause
goto :eof



検証する、つづき


  • よし、引き続き三角とバツもいってみます。それぞれtrain10枚、test5枚ずつ。

  • 複合画像、丸を検出、三角は誤検出、バツを見逃し、重なった図形はだめ。

  • 三角もバツも単独の画像ならいけますね。


    • 丸は正解、三角は誤認、バツが無視

    • 三角も単独ならでる

    • バツも単独ならでる



  • なお元のモデルと追加学習したモデルで人と馬の写真を検出させると。これはヒドイ。


    • 事前事前

    • 事後事後というか事故ですね



  • 学習データにノイズを載せました。


    • ノイズ例1

    • ノイズ例2



  • バツも検出できました。バツも検出

  • 写真に図形描画して検出できるようになりました。写真のなかに図形

  • 手書きでもう一度手書き、バツの認識が弱い


つぎの一歩


  • 気になるキーワードGAN


技術調査


どっちにしようDiscoGAN or MASK R-CNN


  • どちらもChainer実装があるので愛機環境ですぐ動きそう

  • githubの最終更新はDiscoGANは2017年、MASK R-CNNは5日前

  • クラス分けまであるしMASK R-CNNをためします


それはまた別のお話

おわり