前回の記事は「Kerasでアクティベーションのパラメータチューニング」を話しました。

今回の記事は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)