ImageDataGenerator のパラメータの最適化 (1)

はじめに

kaggle の digit-recognizer の学習時に, ImageDataGenerator を使っている. これは, 学習時にデータ拡張することで, 学習する画像の範囲を広げたり, その結果として過学習を防ぐことができる. 主なパラメータは, 下記の通りである. その結果, どのように変形されるかは, 画像から感じてほしい.

  • ratation_range
  • width_shift_range
  • height_shift_range
  • shear_range
  • zoom_range

https://raw.githubusercontent.com/satomshr/kaggle_mnist_cnn/main/CNN1r/05/image_data_generator.png

大きく変形させると, 過学習は防げるが, 学習そのものの精度も悪くなる可能性がある. 一方で変形が少ないと, データ拡張の効果が薄れる. そこで最適なパラメータを探索する必要が出てくる.

ここでは ベイズ推定 による最適化を試みる. 結論を先に言うと, うまくいかなかった. この後のブログでランダムサーチなどの別のやり方を試みる予定である.

スクリプト

Parameters optimization of ImageDataGenerator usi…

ベイズ推定は GPyOpt を使った. GPyOpt は kaggle のノートブックに入ってないので, 8 行目で pip でインストールしている.

50 行目の関数 image_data_generator_opt_f() が, GPyOpt で最小化する関数である. 122 行目の return を見れば分かるが, 学習の全 epoch の val_loss の最小値を返すようにしており, val_loss を最小にするパラメータを求めるようにしている.

125 行目で各パラメータの探索範囲を設定している. 注意してほしいのは, shear_range のパラメータで, このとき私は勘違いをしていて 0.1 から 0.4 という 小さい範囲 を設定している. 本来であれば, rotation_range と同じようにもっと大きな範囲を指定すべきである.

132 行目が GPyOpt の初期化 (7 回計算する), 134 行目で最適化計算 (13 回) をしている.

結果

rotation_range width_shift_range hight_shift_range shear_range zoom_range val_loss
1 19.19686431951373 0.20901088144099314 0.38405454186111176 0.23996402282257057 0.10206638888533845 0.022220429033041
2 28.816929542901924 0.39100920908804004 0.2770841119453179 0.34061018253006625 0.11146590049130006 0.023088127374649048
3 43.43410413174117 0.2834173438742231 0.27375949896818885 0.15555809611038365 0.3424101150282481 0.029848376289010048
4 17.01003601991092 0.38785226660815364 0.30289497170727797 0.2637924404969271 0.1803972318546122 0.02294338308274746
5 10.755445837282691 0.39576001559070983 0.39205077518912257 0.38281055792921836 0.396320750705659 0.028119152411818504
6 33.27088427662058 0.3605383199770277 0.13505776272360873 0.13831266468917783 0.17340673816256794 0.025382887572050095
7 49.3506844198074 0.2978424133940589 0.2990829261451698 0.14435462701646262 0.1211438599851377 0.032194338738918304
8 23.09093999418877 0.4 0.1 0.1 0.4 0.0249733105301857
9 18.550498114931145 0.1 0.1 0.4 0.4 0.02369987592101097
10 18.63230824366345 0.4 0.4 0.1 0.1 0.023234009742736816
11 18.1519017887764 0.1 0.4 0.1 0.1 0.020590541884303093
12 18.10422186453 0.1 0.4 0.1 0.1 0.021966272965073586
13 17.718261335584014 0.1 0.4 0.1 0.1 0.023602882400155067
14 18.759275901922862 0.1 0.4 0.1 0.1 0.02378304861485958
15 18.276551985644694 0.1 0.4 0.1 0.1 0.023956721648573875
16 18.742473332615006 0.1 0.4 0.4 0.1 0.022985640913248062
17 18.388879177471168 0.1 0.4 0.4 0.1 0.0249274130910635
18 19.806055360855435 0.1 0.4 0.1 0.1 0.02428913302719593
19 27.73900197039526 0.1 0.4 0.1 0.1 0.02649843692779541
20 18.01584412083525 0.4 0.1 0.1 0.1 0.021857010200619698

11 行目の val_loss が最小値になっており, そのときのパラメータは次のとおりである.

  • rotation_range ; 18.15
  • width_shift_range ; 0.1
  • height_shift_range ; 0.4
  • shear_range ; 0.1
  • zoom_range ; 0.1

width_shift_range, shear_range, zoom_range の 3 つのパラメータは, 振った範囲で最小の値となっており, データ拡張しないほうが学習結果が良い という, 当たり前な結果になってしまった. GPyOpt はきちんと仕事をしていると思うが, 結果としてはイマイチなパラメータが出てきた.

まとめ

ImageDataGenerator のパラメータの最適化をベイズ推定 (GPyOpt) で行ったところ, データ拡張の効果を小さくするほうが良いという, 当たり前な結果になってしまった. val_loss は小さくなっているかもしれないが, 過学習の懸念がある.

次は, ランダムサーチ で最適値を見つけられないか, トライする 予定である.