今回の記事はKerasの画像前処理のパラメータチューニングを解説します。

データ拡張(Data Augmentation)とは

データ拡張は、訓練データの画像に対して移動、回転、拡大・縮小など人工的な操作を加えることでデータ数を追加するテクニック。学習データを追加すると、モデルの汎化性能が改善できます。

機械学習、ディープラーニングの世界では大量のデータが必要となるので、オリジナルデータが少ない場合、ImageDataGeneratorを使用することで簡単に画像を増やす事ができます。

KerasライブラリのImageDataGeneratorクラスのパラメータを変更します。

KerasのImageDataGeneratorクラス

keras.preprocessing.image.ImageDataGenerator(featurewise_center=False, samplewise_center=False, featurewise_std_normalization=False, samplewise_std_normalization=False, zca_whitening=False, zca_epsilon=1e-06, rotation_range=0.0, width_shift_range=0.0, height_shift_range=0.0, brightness_range=None, shear_range=0.0, zoom_range=0.0, channel_shift_range=0.0, fill_mode='nearest', cval=0.0, horizontal_flip=False, vertical_flip=False, rescale=None, preprocessing_function=None, data_format=None, validation_split=0.0)

引数

featurewise_center: 真理値。データセット全体で,入力の平均を0にします。

samplewise_center: 真理値。各サンプルの平均を0にします。

featurewise_std_normalization: 真理値。入力をデータセットの標準偏差で正規化します。

samplewise_std_normalization: 真理値。各入力をその標準偏差で正規化します。

zca_epsilon: ZCA白色化のイプシロン。デフォルトは1e-6。

zca_whitening: 真理値。ZCA白色化を適用します。

rotation_range: 整数。画像をランダムに回転する回転範囲。

width_shift_range: 浮動小数点数(横幅に対する割合)。ランダムに水平シフトする範囲。

height_shift_range: 浮動小数点数(縦幅に対する割合)。ランダムに垂直シフトする範囲。

shear_range: 浮動小数点数。シアー強度(反時計回りのシアー角度)。

zoom_range: 浮動小数点数または[lower,upper]。ランダムにズームする範囲。浮動小数点数が与えられた場合,[lower, upper] = [1-zoom_range, 1+zoom_range]です。

channel_shift_range: 浮動小数点数。ランダムにチャンネルをシフトする範囲。

fill_mode: {"constant", "nearest", "reflect", "wrap"}のいずれか。デフォルトは 'nearest'です。指定されたモードに応じて,入力画像の境界周りを埋めます。

constant: kkkkkkkk|abcd|kkkkkkkk (cval=k)

nearest: aaaaaaaa|abcd|dddddddd

reflect: abcddcba|abcd|dcbaabcd

wrap: abcdabcd|abcd|abcdabcd

cval: 浮動小数点数または整数。fill_mode = "constant"のときに境界周辺で利用される値。

horizontal_flip: 真理値。水平方向に入力をランダムに反転します。

vertical_flip: 真理値。垂直方向に入力をランダムに反転します。

rescale: 画素値のリスケーリング係数。デフォルトはNone。Noneか0ならば,適用しない。それ以外であれば,(他の変換を行う前に) 与えられた値をデータに積算する。

preprocessing_function: 各入力に適用される関数です。この関数は他の変更が行われる前に実行されます。この関数は3次元のNumpyテンソルを引数にとり,同じshapeのテンソルを出力するように定義する必要があります。

data_format: {"channels_first", "channels_last"}のどちらか。"channels_last"の場合,入力のshapeは(samples, height, width, channels)となり,"channels_first"の場合は(samples, channels, height, width)となります。デフォルトはKerasの設定ファイル~/。keras/keras。jsonのimage_data_formatの値です。一度も値を変更していなければ,"channels_last"になります。

validation_split: 浮動小数点数。検証のために予約しておく画像の割合(厳密には0から1の間)です。

では猫の画像を準備します。

In [1]:
import matplotlib.pyplot as plt
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
Using TensorFlow backend.
In [2]:
# 画像ファイルをPIL形式でオープン
img = image.load_img('./data/cat01.png')
# PIL形式をnumpyのndarray形式に変換
x = image.img_to_array(img)
# (height, width, 3) -> (1, height, width, 3)
x = x.reshape((1,) + x.shape)
In [3]:
datagen = ImageDataGenerator(
           rotation_range=0,
           width_shift_range=0,
           height_shift_range=0,
           shear_range=0,
           zoom_range=0,
           horizontal_flip=False,
           vertical_flip=False)
In [4]:
def show_imgs(imgs, row, col):
    """Show PILimages as row*col
     # Arguments
            imgs: 1-D array, include PILimages
            row: Int, row for plt.subplot
            col: Int, column for plt.subplot
    """
    if len(imgs) != (row * col):
        raise ValueError("Invalid imgs len:{} col:{} row:{}".format(len(imgs), row, col))

    for i, img in enumerate(imgs):
        plot_num = i+1
        plt.subplot(row, col, plot_num)
        plt.tick_params(labelbottom="off") # x軸の削除
        plt.tick_params(labelleft="off") # y軸の削除
        plt.imshow(img)
    plt.show()
In [5]:
max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    # このあと画像を表示するためにndarrayをPIL形式に変換して保存する
    imgs.append(image.array_to_img(d[0], scale=True))
    # datagen.flowは無限ループするため必要な枚数取得できたらループを抜ける
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)
C:\Users\jingw\Anaconda3\envs\tf36\lib\site-packages\matplotlib\cbook\__init__.py:424: MatplotlibDeprecationWarning: 
Passing one of 'on', 'true', 'off', 'false' as a boolean is deprecated; use an actual boolean (True/False) instead.
  warn_deprecated("2.2", "Passing one of 'on', 'true', 'off', 'false' as a "

rotation_range

rotation_range: 整数.画像をランダムに回転する回転範囲.

「-90〜90」の中でランダムに1つ数字を選んで回転処理するようになっている。

rotation_range=45に変換します。

In [6]:
datagen = ImageDataGenerator(
           rotation_range=45,
           width_shift_range=0,
           height_shift_range=0,
           shear_range=0,
           zoom_range=0,
           horizontal_flip=False,
           vertical_flip=False)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

width_shift_range

width_shift_range: 浮動小数点数(横幅に対する割合)。

ランダムに水平シフトする範囲.

width_shift_range=0.25に変換します。

In [9]:
datagen = ImageDataGenerator(width_shift_range=0.25)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

height_shift_range

height_shift_range: 浮動小数点数(縦幅に対する割合)。

ランダムに垂直シフトする範囲

height_shift_range=0.25に変換します。

In [10]:
datagen = ImageDataGenerator(height_shift_range=0.25)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

shear_range

shear_range: 浮動小数点数。

シアー強度(反時計回りのシアー角度)

shear_range=50に変換します。

In [11]:
datagen = ImageDataGenerator(shear_range=50)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

zoom_range

zoom_range: 浮動小数点数または[lower,upper]。

ランダムにズームする範囲.浮動小数点数が与えられた場合,

[lower, upper] = [1-zoom_range, 1+zoom_range]です。

zoom_range=0.5に変換します。

In [13]:
datagen = ImageDataGenerator(zoom_range=0.5)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

channel_shift_range

channel_shift_range: 浮動小数点数。

ランダムにチャンネルをシフトする範囲

channel_shift_range=100

In [14]:
datagen = ImageDataGenerator(channel_shift_range=100)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

horizontal_flip

horizontal_flip: 真理値

水平方向に入力をランダムに反転します

horizontal_flip=0.4

In [15]:
datagen = ImageDataGenerator(horizontal_flip=0.4)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)

vertical_flip

vertical_flip: 真理値

垂直方向に入力をランダムに反転します。

vertical_flip=0.4

In [16]:
datagen = ImageDataGenerator(vertical_flip=0.4)

max_img_num = 4
imgs = []
for d in datagen.flow(x, batch_size=1):
    imgs.append(image.array_to_img(d[0], scale=True))
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=2, col=2)