TensorFlow + Kerasでサルを分類できるのか試してみる(2) ~ 学習データを増やして精度を上げる

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

はじめに

前回はFlickr APIを使った学習データの取得から、ファイルフォーマットの変換、そして機械学習の実行までやりました。

今回は精度を上げる工夫として、学習データを水増ししてみます。

TensorFlow + Kerasでサルを分類できるのか試してみる(1) ~ 環境構築から学習まで

動作環境

  • macOS High Sierra Version 10.13
  • python 3.6.3
  • pyenv 1.1.5
  • anaconda 3-5.0.0
  • Keras 2.0.8
  • tensorflow 1.3.0

学習データの水増しとは

機械学習で精度を上げるにはデータの質と量が重要になってきます。

学習用データがあらかじめ用意されていればありがたいですが、独自に学習モデルを構築する場合などは自前でデータを用意しなければなりません。

しかし、十分な精度を出すには何千、何万のデータが必要になるため、大量のデータを準備するのが難しいケースがあります。

そのため、少ないデータで十分な精度を出すために、データを水増しさせることで絶対量を増やす工夫をよく行います。

実際にどのように行うかというと、既存の画像データを少し修正することで、異なる画像だけれども同様の特徴量を持った画像を量産させることができます。

画像の拡張パターンは無数に存在しますが、一般的なものだと以下のような拡張がよく使われます。

  • 画像全体を回転させる
  • 一定の範囲内でズームもしくはシフトさせる
  • 画像を反転(水平/垂直)させる etc.

ImageDataGeneratorを使った画像データの拡張

画像処理ライブラリのPillowでも出来ますが、Kerasで提供されているImageDataGeneratorが良さそうだったので、今回はこれを使ってデータを拡張してみます。

ImageDataGenerator

拡張するデータは前回Flickrで取得した画像(サル、チンパンジー、ゴリラを各300枚ずつ)です。

まず、データ拡張スクリプトと同じディレクトリに画像ファイルを配置します。

./data/
 |- monkey
 |- chimpanzee
 |- gorilla

次に画像データを拡張するスクリプトです。

import glob
import traceback

import numpy as np
from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array

base_path = './data_augmented/'


def generate_images(class_name, genetator):
    # jpgファイル取得
    dir = base_path + class_name + '/'
    images = glob.glob(dir + '/*.jpg')
    print(len(images))

    for i, image in enumerate(images):
        # 画像を読み取り
        image = load_img(image)
        # numpy arrayに変換
        x = img_to_array(image)

        # 4次元データに変換
        x = np.expand_dims(x, axis=0)

        g = genetator.flow(x, save_to_dir=dir, save_prefix=class_name, save_format='jpg')

        for j in range(11):
            g.next()

    print(len(glob.glob(dir + '/*.jpg')))

if __name__ == '__main__':

    try:
        # 画像データの拡張パラメータを設定
        train_datagen = ImageDataGenerator(
            rotation_range=0., # 画像をランダムに回転する回転範囲(0-180)
            width_shift_range=0., # ランダムに水平シフトする範囲
            height_shift_range=0., # ランダムに垂直シフトする範囲
            shear_range=0.2, # シアー強度(反時計回りのシアー角度(ラジアン))
            zoom_range=0.2, # ランダムにズームする範囲
            horizontal_flip=True, # 水平方向に入力をランダムに反転
            vertical_flip=True, # 垂直方向に入力をランダムに反転
            rescale=1.0 / 255, # 与えられた値をデータに積算する
            )

        generate_images('monkey', train_datagen)
        generate_images('gorilla', train_datagen)
        generate_images('chimpanzee', train_datagen)

    except Exception as e:
        traceback.print_exc()

画像が拡張されて生成されました。

次の部分で画像拡張のオプションを設定しています。

# 画像データの拡張パラメータを設定
train_datagen = ImageDataGenerator(
    rotation_range=0., # 画像をランダムに回転する回転範囲(0-180)
    width_shift_range=0., # ランダムに水平シフトする範囲
    height_shift_range=0., # ランダムに垂直シフトする範囲
    shear_range=0.2, # シアー強度(反時計回りのシアー角度(ラジアン))
    zoom_range=0.2, # ランダムにズームする範囲
    horizontal_flip=True, # 水平方向に入力をランダムに反転
    vertical_flip=True, # 垂直方向に入力をランダムに反転
    rescale=1.0 / 255, # 与えられた値をデータに積算する
    )

他にもパラメータがあるので、詳細は公式リファレンスを参照して下さい。

ImageDataGeneratorのflowで拡張したデータのバッチを生成します。
その際、画像データは4次元データに変換する必要があります。

# 画像を読み取り
image = load_img(image)
# numpy arrayに変換
x = img_to_array(image)
# 4次元データに変換
x = np.expand_dims(x, axis=0)
g = genetator.flow(x, save_to_dir=dir, save_prefix=class_name, save_format='jpg')

生成したバッチは無限ループのため、必要回数実行することで画像を水増ししていきます。

今回はそれぞれ300枚を10倍にして3000枚ずつ生成しました。
(ローカル環境だとなぜかぴったり10倍にできなかったので、多めに生成して調整しました)

今回はデータを水増ししてから学習させていますが、fit_generatorを使うと生成されたジェネレータをそのまま読み込むことで効率的に学習させることができます。

水増しデータを学習

前回作成したスクリプトを使います。

NPZファイルの作成

photo_countを3000にして実行します。

$ python convert-npz.py monkey chimpanzee gorilla

学習データから機械学習を実行

読み込むnpzファイルを修正して機械学習スクリプトを実行します。

$ python ml-monkey.py
Using TensorFlow backend.
/Users/yuichi/.pyenv/versions/anaconda3-5.0.0/envs/keras/lib/python3.6/site-packages/sklearn/model_selection/_split.py:2010: FutureWarning: From version 0.21, test_size will always complement train_size unless both are specified.
  FutureWarning)
Epoch 1/60
.
.
.
Epoch 58/60
894/894 [==============================] - 0s - loss: 0.2109 - acc: 0.9318     
Epoch 59/60
894/894 [==============================] - 0s - loss: 0.2066 - acc: 0.9318     
Epoch 60/60
894/894 [==============================] - 0s - loss: 0.1696 - acc: 0.9631     
192/224 [========================>.....] - ETA: 0s[0.77153050899505615, 0.7321428571428571]
Loss =  0.771530508995
Accuracy =  0.732142857143

正解率が0.74になりました!

何度か試したところ、大体0.68~0.74の間で推移しました。
水増しなしで0.57~0.64くらいだったので、ある程度精度が向上することができたみたいです。

最後に

学習用データが少なくても精度を上げるためのテクニックについて紹介しました。
機械学習では学習データの量が問題になることが多いので、結構使えるテクニックだと思います。

Kerasで用意されているImageDataGeneratorを使えば簡単にデータを拡張することができるので、ぜひ試してみて下さい。

次回は可視化について試してみたいと思います。

参考

Keras公式サイト(日本語)

スポンサーリンク

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

SNSでもご購読できます。