Python
機械学習
DeepLearning
Keras

Kerasでデータ拡張(Data Augmentation)後の画像を表示する


概要

KerasのImageDataGeneratorクラスが生成する画像ファイルを表示してみて、設定パラメータによってどんな画像が生成されるのか確認してみる記事。

ImageDataGeneratorはデータ拡張を行うためのクラスです。


データ拡張(Data Augmentation)とは

機械学習を実際にやってみようと思うと学習データ集めに苦労する。学習データが少ないと過学習(Overfitting)が起きてしまい汎化性能(未知のデータに対する性能)がでないと言われている。

この問題を緩和するために使われるのが「データ拡張」。

データ拡張は画像に変換処理(反転、拡大、縮小など)を加えることで、学習データの「水増し」を行う。水増しされることで同じ画像が学習されることが少なくなるので汎化性能が改善されるよう。


Keras ImageDataGeneratorクラスとは

機械学習のライブラリではデータ拡張をサポートとしているものがある。

今回はKerasのImageDataGeneratorクラスを試してみる。

ImageDataGeneratorは様々な変換処理を画像に加えることができるが、今回はそのうち以下のパラメータを使って画像の可視化をしていく。

パラメータ
説明

rotation_range
画像を回転させる角度

width_shift_range
水平にシフトする画像横幅に対する割合

height_shift_range
水平にシフトする画像縦に対する割合

horizontal_flip
水平方向反転

vertical_flip
垂直方向反転

zoom_range
拡大縮小範囲

shear_range
シアー強度


今回試したコードの概要

以下コードの説明。

コードの説明後、変換後の画像を見ていきます。


Import


show_generator.py

import matplotlib.pyplot as plt

from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator



  • keras.preprocessing.imageにデータ拡張に便利な関数が入っている。


  • matplotlibは画像の可視化に使う。


画像の読み込み


show_generator.py

# 画像ファイルをPIL形式でオープン

img = image.load_img(img_path)
# PIL形式をnumpyのndarray形式に変換
x = image.img_to_array(img)
# (height, width, 3) -> (1, height, width, 3)
x = x.reshape((1,) + x.shape)

次にImageDataGeneratorクラスに渡す画像データを用意する。

ImageDataGeneratorクラスがndarray形式の4次元配列を要求するのでその変換もここで行っておく。


ImageDataGenerator生成


show_generator.py

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)

ImageDataGeneratorクラスを生成。

生成時に渡すパラメータを色々変えると様々なデータ拡張を行ってくれるので、今回はここを変えてみてどんな変換が起きるか見てみる。

上記設定は何もしないになっている。


画像生成、表示


show_generator.py

max_img_num = 16

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=4, col=4)

ImageDataGeneratorから変換画像を取得して表示。

表示は以下の関数で行っている。


show_generator.py

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()



rotation_range

rotation_rangeは画像を回転させるパラメータ。

設定は整数で何度回転させていか設定可能。

例えば90度と設定すると、Kerasの中で「-90〜90」の中でランダムに1つ数字を選んで回転処理するようになっている。

以下変換後の画像。

rotation_range=90

rotation_range_90.png

回転させることで元の画像にない領域がでてくる。

これはImageDataGenerator生成時に設定するfill_modeでどの画素で埋めるかを指定可能。

fill_modeには、constant,nearest,reflect,wrapがあり上記例ではfill_mode=nearestになっている。

fill_mode=constant(cvalで埋める色を変えられます)

rotation_range_90_constant.png

fill_mode=reflect

rotation_range_90_reflect.png

fill_mode=wrap

rotation_range_90_wrap.png


width_shift_range / height_shift_range

画像をシフトさせます。

少しややこしいのがこの変数は3つの型でシフトを指定できる。


意味

int
シフトさせる画素数

1-D array
シフトさせる画素数

float
シフトさせる割合(元画像の解像度に対して)

int型の場合、width_shift_range=128と設定すると、「-127〜127」の数字の中からランダムに選択して、選択した画素数シフトする。

1-D array型の場合、基本的にはintと同じだがランダムに選ばれる数字を限定することができる。例えば、width_shift_range=[128,256]と設定すると「-256,-128,128,256」の中からランダムにシフトする画素数が選択される。

float型の場合、画像の幅に対する割合で表現するので、元画像が水平480でwidth_shift_range=0.5とするとシフト量は「-240〜240」画素シフトする。

画素数で指定するのは面倒くさいのでfloatで設定するのが楽。

シフトしてできた元画像にない部分はfill_modeで指定可能。

width_shift_range=0.5

widht_0.5.png

width_shift_range=0.2

widht_0.2.png

height_shift_range=0.5

height_0.5.png


horizontal_flip / vertical_flip

ランダムに反転。

horizontal_flip=True

horizontal_flip.png

vertical_flip=True

vertical_flip.png


zoom_range

拡大したり縮小したり。

こちらもシフトと同じで複数の型で指定可能。


意味

1-D array
拡大縮小させる範囲 [lower, upper]

float
拡大縮小させる範囲 [lower, upper] = [1-zoom_range, 1+zoom_range]

lower〜upperの範囲で乱数を2つ取り、それぞれx軸とy軸の拡大率にする。

kerasの中では具体的には以下のようなことをしている。


sample.py

x, y = np.random.uniform(lower, upper, 2)


ややこしいですが、

x > 1の場合、画像内の物体が縮小されたように見える。

0 < x < 1の場合、画像内の物体が拡大されたように見える。

マイナスの場合はさらに反転が加わる。

zoom_range=[1,1.5]

zoom_1_1.5.png

zoom_range=[0.5,1]

zoom_0.5_1.png

zoom_range=[-1.5,-1]

zoom_-1.5_-1.png

zoom_range=[-1,-0.5]

zoom_-1_-0.5.png


shear_range

シアー強度というもので画像変換を行う。

せん断写像というらしいが、いまいちわかっていないので実験した画像だけのせておく。

shear_range=40

shear_40.png

shear_range=90

shear_90.png


まとめ

今回は画像の可視化のためにImageDataGeneratorクラスを使ってみたが、KerasではImageDataGeneratorクラスをモデル学習時に渡すことで、これまで見てきた変換をランダムに適用したミニバッチは作ってくれるようになっているので、学習プロセスに簡単にデータ拡張を組み込めるようになっている。

データ拡張を便利だが、変換を強くかけすぎると現実には存在しないような画像になってしまい、意味のないデータになってしまう(shear_range=90とか)。なので今回のように変換パラメータを色々試して、実際に画像を確認してから使用することが効果的だと思う。


参考