アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うことを書いてます。

少ない画像をpythonのPILで加工しバリエーションを増やす。学習精度はあがるか?。/使い方20:ニューラルネットワークコンソール

少ない(1カテゴリあたり40枚~60枚しかない)カラー画像データを、水増しするなどの、学習精度向上策を検証してみます。 

ベースにするのは、前回のデータとモデルです。

arakan-pgm-ai.hatenablog.com

Accuracyが約71%とかなり情けない結果でしたから、それを少しでも引き上げてみたいな・・ということです。 

さて、やってみます。

 

カラー画像データの水増し

 

利用したCaltech101の画像データは、1カテゴリあたり40枚~60枚程度です。 

これをもとに、なんとか30倍の1200枚~1800枚程度にはしたいなと思うわけです。 

それもただコピーするだけでは意味がありません。

回転させたり、反転させたり、画像補正をかけたりといった変更を加えて、少しずつ異なる画像にしようと思います。 

これは、手作業でもやれます。

地道に画像加工ソフトとかを使ってやれば・・ですけど。 

例えば、Ralphaなんかだと、変換後のファイル名規則を指定して、一括でグレイスケール化や回転などの処理を行うことができますし。

f:id:arakan_no_boku:20171104103555j:plain

上の例だと、リストの画像ファイルすべてを90度回転させて128x128にリサイズした画像ファイルを、「もとのファイル名」_G.jpg という名前にして、afterフォルダの下に生成してくれます。 

これを地道に繰り返していけば、画像の水増しはできます。 

でも、自分は・・根気が続きません。

 

pythonのPILを使って一括処理で水増しする

 

横着者はプログラムを書け。

というころで、pythonプログラムで一括処理をします。 

ソースはこんな感じです。

# -*- coding: utf-8 -*-
import os
from PIL import Image, ImageFilter

def main():
    data_dir_path = u"./out/"
    data_dir_path_in = u"./in/"
    file_list = os.listdir(r'./in/')

    for file_name in file_list:
        root, ext = os.path.splitext(file_name)
        if ext == u'.png' or u'.jpeg' or u'.jpg':
            img = Image.open(data_dir_path_in + '/' + file_name)
            tmp = img.transpose(Image.FLIP_LEFT_RIGHT)
            tmp.save(data_dir_path + '/' + root +'_r01.jpg')
            tmp = img.transpose(Image.FLIP_TOP_BOTTOM)
            tmp.save(data_dir_path + '/' + root +'_r02.jpg')
            tmp = img.transpose(Image.ROTATE_90)
            tmp.save(data_dir_path + '/' + root +'_r03.jpg')
            tmp = img.transpose(Image.ROTATE_180)
            tmp.save(data_dir_path + '/' + root +'_r04.jpg')
            tmp = img.transpose(Image.ROTATE_270)
            tmp.save(data_dir_path + '/' + root +'_r05.jpg')
            tmp = img.rotate(15)
            tmp.save(data_dir_path + '/' + root +'_r06.jpg')
            tmp = img.rotate(30)
            tmp.save(data_dir_path + '/' + root +'_r07.jpg')
            tmp = img.rotate(45)
            tmp.save(data_dir_path + '/' + root +'_r08.jpg')
            tmp = img.rotate(60)
            tmp.save(data_dir_path + '/' + root +'_r09.jpg')
            tmp = img.rotate(75)
            tmp.save(data_dir_path + '/' + root +'_r10.jpg')
            tmp = img.rotate(105)
            tmp.save(data_dir_path + '/' + root +'_r11.jpg')
            tmp = img.rotate(120)
            tmp.save(data_dir_path + '/' + root +'_r12.jpg')
            tmp = img.rotate(135)
            tmp.save(data_dir_path + '/' + root +'_r13.jpg')
            tmp = img.rotate(150)
            tmp.save(data_dir_path + '/' + root +'_r14.jpg')
            tmp = img.rotate(165)
            tmp.save(data_dir_path + '/' + root +'_r15.jpg')
            tmp = img.rotate(195)
            tmp.save(data_dir_path + '/' + root +'_r16.jpg')
            tmp = img.rotate(210)
            tmp.save(data_dir_path + '/' + root +'_r17.jpg')
            tmp = img.rotate(225)
            tmp.save(data_dir_path + '/' + root +'_r18.jpg')
            tmp = img.rotate(240)
            tmp.save(data_dir_path + '/' + root +'_r19.jpg')
            tmp = img.rotate(255)
            tmp.save(data_dir_path + '/' + root +'_r20.jpg')
            tmp = img.rotate(285)
            tmp.save(data_dir_path + '/' + root +'_r21.jpg')
            tmp = img.rotate(300)
            tmp.save(data_dir_path + '/' + root +'_r22.jpg')
            tmp = img.rotate(315)
            tmp.save(data_dir_path + '/' + root +'_r23.jpg')
            tmp = img.rotate(330)
            tmp.save(data_dir_path + '/' + root +'_r24.jpg')
            tmp = img.rotate(345)
            tmp.save(data_dir_path + '/' + root +'_r25.jpg')
            tmp = img.filter(ImageFilter.FIND_EDGES)
            tmp.save(data_dir_path + '/' + root +'_r26.jpg')
            tmp = img.filter(ImageFilter.EDGE_ENHANCE)
            tmp.save(data_dir_path + '/' + root +'_r27.jpg')
            tmp = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
            tmp.save(data_dir_path + '/' + root +'_r28.jpg')
            tmp = img.filter(ImageFilter.UnsharpMask(radius=5, percent=150, threshold=2))
            tmp.save(data_dir_path + '/' + root +'_r29.jpg')
            tmp = img.filter(ImageFilter.UnsharpMask(radius=10, percent=200, threshold=5))
            tmp.save(data_dir_path + '/' + root +'_r30.jpg')

if __name__ == '__main__':
    main()

pythonのPILという画像操作ライブラリを使ってます。 

簡単に解説するします。

  • img.transpose(Image.FLIP_LEFT_RIGHT)は「左右反転」
  • img.transpose(Image.FLIP_TOP_BOTTOM)は「上下反転」
  • img.transpose(Image.ROTATE_90)は「90度回転」以下度数だけ変えてます。
  • img.rotate(15)は「15度回転」・・あとは、度数を変えているだけです。
  • img.filter(ImageFilter.EDGE_ENHANCE)はエッジ強調フィルターです。
  • img.filter(ImageFilter・・も同様に画像の画質に変化を加えてるだけです。

例えば、このソースのあるフォルダに「in」と[out」というフォルダを作り、「in」の下に以下のように画像ファイルをおいて実行します。

f:id:arakan_no_boku:20171104110033j:plain

そうすると、「out」フォルダにこんな感じで画像データができあがります。

f:id:arakan_no_boku:20171104110329j:plain

いい感じです。 

結局、この処理後にRalphaを使って、一括でグレースケール変換したものも追加したので、最終的には30x2=60倍に水増しして、枚数が10000枚を超えました。 

 

画像水増しして学習・評価をやりなおす

 

画像データをすべて水増ししたら、再度DATASETを作り直して、ニューラルネットワークコンソールで学習・評価をやり直してみます。 

DATASETの作り直し方については、以下を参考にしてください。

support.dl.sony.com

arakan-pgm-ai.hatenablog.com 

 

学習と評価の実施

 

前回と同じプロジェクトを開きます。 

arakan-pgm-ai.hatenablog.com

DATASETは、今回生成したものに変更します。 

あと、CONFIGタブも変更しておきます。 

データ量が増えたので、デフォルトのepochとbatchsizeに戻します。

f:id:arakan_no_boku:20171104114959j:plain

 さて学習します。 

時間は結構かかりました。 

”BOKU"のPCのスペックがしょぼい(5年前位に3万円ほどで買ったノートPC・・推して知るべしですね。)のもありますが、なんと学習に11時間ですよ(^_^;) 

その結果はこんな感じです。

f:id:arakan_no_boku:20171105000337j:plain

かなりきれいな学習曲線ですね。 

これは期待ができそうです。 

それで評価した結果はこちら。

f:id:arakan_no_boku:20171105000313j:plain

96.27%は上出来です。 

なんせ、前回 約71%しか出なかったモデルはそのままで、学習データの水増しをしただけですからね。 

学習データ量が少ないときに、回転させたりエッジを強調するようなフィルターをかけた画像を追加すると、学習精度は改善する。 

ということで、良さそうですね。 

ただ、学習に時間がかかりすぎるので、ここから更にチューニングするのは、あきらめることにします(笑) 

ではでは。 

関連情報

ニューラルネットワークコンソールの関連記事一覧はこちらです。

arakan-pgm-ai.hatenablog.com

NNablaの関連記事一覧はこちらです。

arakan-pgm-ai.hatenablog.com

f:id:arakan_no_boku:20170910161122j:plain