Keras: ImageDataGenerator

Takami Torao Keras 2.2 TensorFlow 1.8 #Keras #TensorFlow
  • このエントリーをはてなブックマークに追加

概要

Keras 2.2 に付属するデータ拡張と正規化のための多機能前処理ユーティリティ ImageDataGenerator のパラメータごとの効果を整理する。明文化されていない部分については Github のソースを参照する必要がある。

ImageDataGenerator は拡大縮小や回転、明るさなどを変更することで画像の特徴のバリエーションを水増しし、少ない訓練データでモデルの精度を上げる目的で使用される。

画像変換のパラメータ

アフィン変換と明るさの変換を行うことができる。

channel_shift_range

画像の明るさをランダムに変化させる。

このパラメータは画像のカラーチャネル値 (RGB の場合はピクセルごとに 3 次元) それぞれに指定された範囲の値を加算する。float 値 \(t\) を指定した場合、カラーチャネルに加算される intensity 値は \(\pm t\) 範囲のランダムな値である。ただし、画像のカラーチャンネル階調の最小値 \(x_{\rm min}\)、最大値 \(x_{\rm max}\) を超えることはない。つまり: \[ \begin{array}{l} -t \leq {\rm intensity} \lt t \\ x' = \left\{ \begin{array}{ll} x_{\rm min} & \ \ {\rm if} \ x + {\rm intensity} \lt x_{\rm min} \\ x_{\rm max} & \ \ {\rm if} \ x + {\rm intensity} \gt x_{\rm max} \\ x + {\rm intensity} & \ \ {\rm otherwise} \end{array} \right. \end{array} \]

カラーチャネルに加減される intensity 値は画像に対して同一であるため、色調を変更せず明るくまたは暗くする効果を持つ。

channel_shift_range=100
channel_shift_range=100

例えば RGB カラーモデルの配列では各カラーチャネルは 256 階調を持つため 0-255 の範囲で指定する (rescale=1./255 の正規化は画像変換後に適用される)。

width_shift_range, height_shift_range

上下または左右にランダムにスライドさせる。

設定値 \(d\) は移動距離となる乱数の範囲を示す。値によって以下のように解釈される。

  • float で \(d \lt 1\) の場合、画像の横幅/縦幅に対する割合を示す。
  • float で \(d \geq 1\) の場合、\(-d \leq x \lt d\) 範囲のピクセル数を示す。例えば 3.0 を指定した場合、1次元配列で [-3, -2, -1, 0, 1, 2] とした場合と等価である。
  • int の場合、\(-d \lt x \lt d\) 範囲のピクセル数を示す。例えば 3 を指定した場合、1次元配列で [-2, -1, 0, 1, 2] とした場合と等価である。
  • 1次元配列の場合、それらの中からランダムに選ばれた値のピクセル数が適用される。

移動により発生した空白領域を埋める方法は fill_mode で指定することができる。デフォルトは "nearest" が適用される。

width_shift_range=0.2
width_shift_range=0.2
height_shift_range=0.2
height_shift_range=0.2

horizontal_flip, vertical_flip

縦反転、横反転をランダムに行う。

横方向または縦方向の反転を行うかを True/False で指定する。

horizontal_flip=True
horizontal_flip=True
vertical_flip=True
vertical_flip=True

rotation_range

ランダムな角度で画像を回転させる。

例えば rotation_range=45 を指定した場合 \(\pm 45^\circ\) の範囲でランダムに回転する。

rotation_range=60
rotation_range=60

shear_range

ランダムな角度で画像を傾かせる。

縦方向と横方向への傾き (シアー) の範囲を度数で指定する。

shear_range=60
shear_range=60

zoom_range

画像を縦横ランダムに拡張/縮小する。

パラメータの値に対する解釈は以下の通り。

  • float 値 \(t\) を指定した場合、拡大率の取りうる範囲は \(1\pm t\) となる。つまり [1-t, 1+t] を指定した場合と等価。
  • 2 要素の配列 [min, max] で指定した場合、それらはランダムに取りうる拡大率の範囲とみなされる。min == max の場合、固定倍率の拡縮が行われる。
zoom_range=0.4
zoom_range=0.4

fill_mode

縮小や回転などによって発生した余白を埋める方法。

constant, nearest, reflect, wrap のいずれかを指定することができる。constant を指定した場合、cval で余白部分のカラーチャネルに設定する階調を指定することができる。

fill_mode=constant
fill_mode="constant", cval=0xCC
fill_mode=nearest
fill_mode="nearest"
fill_mode=reflect
fill_mode="reflect"
fill_mode=wrap
fill_mode="wrap"

画像変換テスト用スクリプト

このページ用に作成したスクリプト。

# -*- encoding: utf-8 -*-
#
from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img
from PIL import Image, ImageDraw
import numpy as np, math

GENERATORS = [
  {
    "div": 1,
    "generators": {
      "fill_mode-constant": ImageDataGenerator(zoom_range=[1.75, 1.75], fill_mode="constant", cval=0xCC),
      "fill_mode-nearest" : ImageDataGenerator(zoom_range=[1.75, 1.75], fill_mode="nearest"),
      "fill_mode-reflect" : ImageDataGenerator(zoom_range=[1.75, 1.75], fill_mode="reflect"),
      "fill_mode-wrap"    : ImageDataGenerator(zoom_range=[1.75, 1.75], fill_mode="wrap")
    }
  }, {
    "div": 4,
    "generators": {
      "rotation_range": ImageDataGenerator(rotation_range=60),
      "width_shift_range": ImageDataGenerator(width_shift_range=0.2),
      "height_shift_range": ImageDataGenerator(height_shift_range=0.2),
      "shear_range": ImageDataGenerator(shear_range=60),
      "zoom_range": ImageDataGenerator(zoom_range=0.4),
      "horizontal_flip": ImageDataGenerator(horizontal_flip=True),
      "vertical_flip": ImageDataGenerator(vertical_flip=True),
      "channel_shift_range": ImageDataGenerator(channel_shift_range=100)
    }
  }
]

def create_samples(file):
  original = load_img(file)
  X = np.expand_dims(img_to_array(original), axis=0)

  margin = 1
  max_screen_size = 480
  rate = min(1.0, min(float(max_screen_size) / original.width, float(max_screen_size) / original.height))
  screen_size = (int(original.width * rate), int(original.height * rate))

  for gs in GENERATORS:
    div = gs["div"]
    thumb_size = (int(original.width * rate / div), int(original.height * rate / div))
    for id in gs["generators"]:
      g = gs["generators"][id]
      g.fit(X, seed=1234)
      generator = g.flow(X)
      screen = Image.new("RGB", screen_size)
      x = y = 0
      while y < screen.height:
        while x < screen.width:
          thumb_array = next(generator)
          thumb = array_to_img(thumb_array[0])
          thumb = thumb.resize(thumb_size, resample=Image.BICUBIC)
          screen.paste(thumb, (x, y))
          x += thumb_size[0] + margin
        x = 0
        y += thumb_size[1] + margin
      screen.save("%s.png" % id)

if __name__ == "__main__":
  import sys
  create_samples(sys.argv[1])

正規化のパラメータ

正規化はアフィン変換や明るさ変換が行われたあとに適用される。ジェネレータが生成するテンソルを入力とするニューラルネットワークに向けた処理である。

rescale

テンソルの正規化係数を指定する。

このパラメータは画像変換を行なったあとにすべてのテンソル値 (つまりすべてのピクセルのカラーチャネル) に乗算する係数を指定する。例えば RGB 各チャネルに 256 階調を持つ一般的なフルカラー画像であれば、rescale=1./255 と指定することで、このジェネレータによって生成されるテンソルを 0 から 1 の範囲に正規化することができる。

array_to_img()save_image() はテンソル中の最大値/最小値を 0-255 に変換しているだけであるため、正規化した画像を正確には復元することができないrescale によって 0~1 範囲に正規化された画像を元に戻すにはテンソルに 255 を乗算したテンソルをそれらに scale=False で適用することで元の 256 階調に戻すことができる (いずれもデフォルト True であるため注意)。

sample pixels
[[[[ 62.  60.   9.]
   [ 72.  48.  59.]
   [ 31. 157. 128.]
   [107. 215.   2.]]

  [[101.  48.   7.]
   [ 86.  30. 132.]
   [ 13. 215. 198.]
   [118. 255.   0.]]

  [[158.  30.   5.]
   [ 99.  12. 205.]
   [  0. 255. 246.]
   [114. 230.   7.]]

  [[216.  12.   2.]
   [107.  14. 223.]
   [ 50. 209. 192.]
   [159. 209. 101.]]]]
Tensor 1: 256階調 RGB 4×4
[[[[0.24313727 0.23529413 0.03529412]
   [0.28235295 0.18823531 0.23137257]
   [0.12156864 0.6156863  0.5019608 ]
   [0.41960788 0.8431373  0.00784314]]

  [[0.39607847 0.18823531 0.02745098]
   [0.3372549  0.11764707 0.5176471 ]
   [0.0509804  0.8431373  0.77647066]
   [0.46274513 1.         0.        ]]

  [[0.61960787 0.11764707 0.01960784]
   [0.38823533 0.04705883 0.80392164]
   [0.         1.         0.96470594]
   [0.44705886 0.90196085 0.02745098]]

  [[0.8470589  0.04705883 0.00784314]
   [0.41960788 0.05490196 0.8745099 ]
   [0.19607845 0.8196079  0.75294125]
   [0.62352943 0.8196079  0.39607847]]]]
Tensor 2: rescale=1./255

上記は 4x4 RGB 画像の適用例である。rescale 値を \(f=1/255\) とすると \(\vector{T}_2 = f \times \vector{T}_1\) となっていることが分かる。

samplewise_center, featurewise_center

値の平均が 0.0 となるように調整する。

このパラメータはゼロを中心にプラスとマイナス方向に分布する入力データを生成するための正規化処理を行う (このパラメータは rescale の後に適用される)。具体的には以下のようにテンソルのそれぞれの値から平均値を減算する。\[ \vector{T}' = \vector{T} - \bar{t} \]

samplewise_center での \(\bar{t}\) はサンプルに対する平均であり、featurewise_center はデータセット全体に対する平均である。

[[[[-0.16601309 -0.17385623 -0.37385625]
   [-0.12679741 -0.22091505 -0.1777778 ]
   [-0.28758174  0.20653594  0.09281045]
   [ 0.01045752  0.43398696 -0.40130723]]

  [[-0.01307189 -0.22091505 -0.38169938]
   [-0.07189545 -0.2915033   0.10849673]
   [-0.35816997  0.43398696  0.3673203 ]
   [ 0.05359477  0.59084964 -0.40915036]]

  [[ 0.2104575  -0.2915033  -0.38954252]
   [-0.02091503 -0.36209154  0.39477128]
   [-0.40915036  0.59084964  0.5555556 ]
   [ 0.03790849  0.4928105  -0.38169938]]

  [[ 0.43790853 -0.36209154 -0.40130723]
   [ 0.01045752 -0.3542484   0.4653595 ]
   [-0.21307191  0.41045755  0.3437909 ]
   [ 0.21437907  0.41045755 -0.01307189]]]]
Tensor 3: rescale=1./255, samplewise_center=True

rescale で正規化された \(\vector{T}_2\) の平均 \(\bar{t}=0.409150\) より、\(\vector{T}_3 = \vector{T}_2 - \bar{t}\) であることが分かる。

samplewise_std_normalization, featurewise_std_normalization

値を標準偏差で正規化する。

テンソル \(\vector{T}\) に含まれる値の分布の広がりを正規化するために使用する (対応する xxxwise_center と共に使用する必要がある)。\(\vector{T}\) の平均値を \(\bar{t}\)、標準偏差を \(\sigma\) としたとき、このパラメータを True にすることで以下の変換が行われる。\[ \vector{T}' = \frac{\vector{T} - \bar{t}}{\sigma} \]

samplewise_std_normalization での \(\sigma\) はサンプルに対する標準偏差であり、featurewise_std_normalization ではデータセット全体に対する標準偏差である。

これらのパラメータを True にする場合は、それぞれ対応する samplewise_centerfeaturewise_center が暗黙的に True に設定される (False のままでは警告が出るため明示的に指定するとよい)。

[[[[-0.5043192  -0.52814525 -1.1357108 ]
   [-0.38518867 -0.67110187 -0.5400583 ]
   [-0.8736238   0.6274206   0.28194216]
   [ 0.03176813  1.3183776  -1.2191021 ]]

  [[-0.03971016 -0.67110187 -1.159537  ]
   [-0.21840599 -0.88553685  0.32959434]
   [-1.0880587   1.3183776   1.1158558 ]
   [ 0.16281167  1.7948993  -1.2429283 ]]

  [[ 0.6393336  -0.88553685 -1.1833631 ]
   [-0.06353626 -1.0999717   1.1992471 ]
   [-1.2429283   1.7948993   1.6876822 ]
   [ 0.11515947  1.4970733  -1.159537  ]]

  [[ 1.3302907  -1.0999717  -1.2191021 ]
   [ 0.03176813 -1.0761456   1.413682  ]
   [-0.64727575  1.2468994   1.0443774 ]
   [ 0.65124667  1.2468994  -0.03971016]]]]
Tensor 4: rescale=1./255, samplewise_center=True, samplewise_std_normalization=True

\(\vector{T}_3\) の分散は \(\sigma = 0.329183\) である。\(\vector{T}_4 = \vector{T}_3 / \sigma\) であることがわかる。

zca_whitening, zca_epsilon

ZCA 白色化を行う。

白色化 (wwhitening) とは共分散行列 \(\Sigma\) が単位行列となるような変換のこと。つまり白色化は特徴を非相関化するための前処理である。featurewise_center=True とともに使用する。

参照

  1. ImageDataGenerator
  2. Francois Chollet (2018)PythonとKerasによるディープラーニング, マイナビ出版
  3. 太田満久, 須藤広大, 黒澤匠雅, 小田大輔 (2018) TensorFlow開発入門 Kerasによる深層学習モデル構築手法, 翔泳社
  4. サンプル画像: Biandintz eta zaldiak クリエイティブ・コモンズ・ライセンス