ハイパーパラメータチューニング,最適化:Optuna,Keras,Pythonで機械学習モデル自動調整【ニューラルネットワーク,ディープラーニング,ラズパイ】

AI、機械学習、ディープラーニングにおいて、「ハイパーパラメータ」という概念は重要です。ハイパーパラメータとは、ニューラルネットワークにおける

・中間層数
・各層のニューロン数
・活性化関数
・ドロップアウト率
・最適化アルゴリズム

を指します。

これらは、ディープラーニング予測結果の精度・学習速度に大きな影響を与えます。中間層数やニューロン数が少なければニューラルネットワークの表現力が落ちその分、予測精度が大きく下がります。

一方で中間層、ニューロン数が多すぎると、その分計算量が上がり学習にかかる時間が多くなります。またネットワークの表現力がありすぎて、過剰に学習データに忠実になってしまう過学習が起こってしまいます。これにより思ったほどの精度が得られません。

そのため、予測したい事象に対して十分な精度の持つモデルを作りたい場合、適切なハイパーパラメータ設定・チューニングを行う必要があります。

しかしながらハイパーパラメータをこれがベストだと一意に決める方法は無いようです。対応としてはある程度の組み合わせを実際に試してみて、一番精度の良いものを選択するという方法が取られるようです。

今回は、ハイパーパラメータ最適化をを自動的・効率的に探索する、ライブラリ「Optuna」を利用した、AIプログラムのサンプルを公開します。

※Optunaについてはこちら
ハイパーパラメータ自動最適化ツール「Optuna」公開 | Preferred Networks Research & Development

ハイパーパラメータ探索するモデルですが、以前に公開した、工数見積もりを行う回帰問題型のディープラーニングモデルを対象とします。

https://nine-num-98.blogspot.com/2019/11/ai-deep-learning.html

上記のプログラムに、Optunaを実装してアップグレードした形になります。

開発環境

■ハードウェア

Raspberry Pi 3 Model B


■OS

Raspbian GNU/Linux 9.11 (stretch)


■プログラミング言語、主なライブラリとバージョン

・Python 2.7.13
・Optuna 0.11.0
・Keras 2.1.5
・numpy 1.12.1
・theano 1.0.1
・matplotlib 2.0.0
・scipy 1.2.1
・pandas 0.24.2
・logging 0.5.1.2


※Optunaのインストール方法はこちら(公式ドキュメント 英語)
https://optuna.readthedocs.io/en/stable/installation.html


※ラズパイのAI環境開発は以下の本が参考になります。


プログラム


GitHubにサンプルプログラムを公開します。

https://github.com/kotetsu99/deep_regression_opt


■各ファイル等の概要

(1) 01-deep_regression_train.py: 学習プログラム
 ・学習用データセットファイルを読み込んで予測モデルを作成する
 ・エポック数に対する損失関数の値変化のグラフを出力する
 ・ハイパーパラメータ探索を実装。設定については、(5)dnn.conf で行う。

(2) 02-dnn_visualization.py: モデル可視化プログラム
 ・(1)で生成したニューラルネットワークモデルの構造をコンソール画面上およびファイルに出力し、可視化する。以下の記事で解説。
https://nine-num-98.blogspot.com/2020/03/dnn-visualization.html

(3) 03-deep_regression_predict.py: 予測プログラム
 ・予測モデルと説明変数(テスト項目数)を引数とし、テスト消化の所要日数の予測値を返す

(4) 04-deep_regression_plot.py: データプロットプログラム
 ・テスト項目数のベクトルを読み込んで、テスト項目数-予測消化日数をグラフを出力する
 ・プロットしたデータのcsvファイルを出力する

(5) dnn.conf: プログラム設定ファイル
 ・(1)(3)(4)のプログラムに関する設定ファイル
 ・(1)のハイパーパラメータ最適化(Optuna)に関する設定は、本ファイルで設定

(6) logging.conf: ログ出力設定ファイル
 ・(1)のログ出力に関する設定ファイル

(7) dataset/train.csv: 学習用データセット
 ・1列目がテスト項目数、2列目が消化日数
 ※開発現場での実績を元にしたわけではなく、適当なサンプルです。

(8) dataset/plot.csv: データプロット用データセット


(9) model/: 予測モデル保存先ディレクトリ


(10) log/: 実行ログ保存先ディレクトリ

プログラム使用方法

(1)dnn.confでハイパーパラメータ最適化(Optuna)設定

Optunaによるハイパーパラメータチューニングを行う事前設定を行います。設定は、dnn.confで行います。dnn.confの内容について各パートごとに見ていきます。

  1 [File Path]
  2 # データセットファイルパス
  3 dataset_file: dataset/train.csv
  4

学習データセットの保存先をここで指定します。

  5 [Train Parameter]
  6 # バッチサイズ
  7 batch_size: 8
  8 # エポック数
  9 epochs: 3000
 10 # 収束判定ループ(エポック)回数
 11  # *** 以下の条件を満たすエポックがpatience回続いたら打切り。***
 12  #     val_loss(patience回前の損失関数値) - min_delta  < val_loss(最新の損失関数値)
 13 patience: 300
 14 # 収束判定用差分パラメータ
 15 min_delta: 0.00001
 16

学習データのバッチサイズ、エポック数についても、ハイパーパラメータに含まれるかと思いますが今回は最適化の対象外とします。また損失関数がほぼ変わらない際に、途中で学習を打ち切り、無駄な学習を抑えるための収束判定処理を導入しています。

エポック終了後に毎回損失関数の値が計算されます。その値が一定値(min_delta)以上、下がらない状態が指定回(patience回)続いた場合、学習を切り上げて、プログラムを終了します。

以降が、Optuna関連の設定になります。

 17 [Trials]
 18 # 最適化探索試行回数
 19 trials: 20
 20

 最適化探索では、ハイパーパラメータを色々変えて試して、一番良いものを予測モデルとして生成します。では何回試すのか?という設定をここで行います。上記では20回試すとなっています。

 21 [Layer]
 22 # 中間層数の最小値
 23 layer_min: 1
 24 # 中間層数の最大値
 25 layer_max: 5
 26

中間層数の探索範囲を設定しています。ここでは、中間層数の数を1~5の間で振ることを定義しています。

 27 [Mid Units]
 28 # 中間層ユニット(ニューロン)数の最小値
 29 mid_units_min: 10
 30 # 中間層ユニット(ニューロン)数の最大値
 31 mid_units_max: 30
 32 # 中間層ユニット(ニューロン)数の最小値-最大値の刻み値
 33 mid_units_step: 5
 34

各中間層のニューロン数の探索範囲を設定しています。ここでは、中間層数を10~30の間で、5刻み(10,15,20...,30)に振ることを定義しています。

 35 [Dropout]
 36 # ドロップアウト率の最小値
 37 dropout_rate_min: 0.0
 38 # ドロップアウト率の最大値
 39 dropout_rate_max: 0.1
 40

ドロップアウト率の探索範囲を設定しています。ここでは、0~0.1の間で振ることを定義しています。

 41 [Activation]
 42 # 活性化関数のリスト
 43 activation_list: relu
 44
 45 [Optimizer]
 46 # 最適化アルゴリズムのリスト
 47 optimizer_list: adam

活性化関数、勾配降下法の最適化アルゴリズムの探索範囲をそれぞれ設定しています。これらは、特に種類は振らずに、活性化関数はrelu関数、最適化アルゴリズムはadamと固定しています。大体この設定が定番なので。

ハイパーパラメータ等のディープラーニングの基本概念については、以下の書籍が参考になります。



(2)学習プログラム実行

以下のコマンドを実行します。

$ nohup python 01-deep_regression_train.py model/dnn_model.h5 &

データセット(dataset/train.csv)を学習し、予測モデル(dnn_model.h5)をmodelディレクトリ配下に生成します。学習時間がかなりかかるため、バックグラウンドで実行させます。

実行中、log/ディレクトリ配下に、実行ログが保存されます。

・log/dnn.log

このログファイルには、試行したハイパーパラメータが記録されていきます。探索が完了したら、最適だったハイパーパラメータ設定が提示されます。

2020-03-09 15:33:59,317:107:INFO: trial#0: n_layer= 3, mid_units= 25, dropout_rate= 0.0665731568912, activation= relu, optimizer= adam
2020-03-09 15:35:02,623:454:INFO: Finished trial#0 resulted in value: 0.0195753395557. Current best value is 0.0195753395557 with parameters: {'dropout_rate': 0.06657315689123626, 'n_layer': 3, 'optimizer': u'adam', 'activation': u'relu', 'mid_units': 25.0}.
2020-03-09 15:35:02,637:107:INFO: trial#1: n_layer= 1, mid_units= 20, dropout_rate= 0.00865121786145, activation= relu, optimizer= adam
2020-03-09 15:35:40,986:454:INFO: Finished trial#1 resulted in value: 0.00305488109589. Current best value is 0.00305488109589 with parameters: {'dropout_rate': 0.008651217861451543, 'n_layer': 1, 'optimizer': u'adam', 'activation': u'relu', 'mid_units': 20.0}.

・・・(中略)・・・

2020-03-09 15:49:47,453:107:INFO: trial#19: n_layer= 1, mid_units= 10, dropout_rate= 0.0178154725078, activation= relu, optimizer= adam
2020-03-09 15:50:46,370:454:INFO: Finished trial#19 resulted in value: 0.00799487903714. Current best value is 0.00245423913002 with parameters: {'dropout_rate': 5.2268471448235765e-05, 'n_layer': 1, 'optimizer': u'adam', 'activation': u'relu', 'mid_units': 10.0}.
2020-03-09 15:50:46,395:50:INFO: best_trial.number: trial#17
2020-03-09 15:50:46,420:54:INFO: best_vmae: 0.00245423913002
2020-03-09 15:50:46,420:57:INFO: --- best hyperparameter ---
2020-03-09 15:50:46,445:60:INFO: activation : relu
2020-03-09 15:50:46,446:60:INFO: dropout_rate : 5.22684714482e-05
2020-03-09 15:50:46,446:60:INFO: mid_units : 10.0
2020-03-09 15:50:46,447:60:INFO: n_layer : 1
2020-03-09 15:50:46,448:60:INFO: optimizer : adam
2020-03-09 15:50:46,448:61:INFO: ------------

↑の例では、trial#0 ~ trial#19 の合計20回が試行され、ハイパーパラメータを探索した結果、最も優秀だったものは、以下の組み合わせということでした。

----------------------------------
・中間層数: 1
・各層のニューロン数: 10
・活性化関数: relu関数
・ドロップアウト率: 5.22684714482e-05
・最適化アルゴリズム: adam
----------------------------------


また学習終了後、↑の最適予測モデルの学習過程(損失関数の推移)を記したグラフが出力されます。

・dnn_reg_train_figure.png




(3)モデルを可視化して構成・ハイパーパラメータを確認

生成された、モデルの構成を確認するためのプログラム 02-dnn_visualization.py を用意しています。ハイパーパラメータ最適化の件とは、ややそれる内容ですので以下の記事で解説しています。

https://nine-num-98.blogspot.com/2020/03/dnn-visualization.html

実行は必須ではないので、この作業は飛ばしてもOKです。


(4)予測プログラム実行

以下のコマンドにより、与えられた説明変数(テスト項目数)データに対する予測値(所要日数)が出力されます。

$ python 03-deep_regression_predict.py model/dnn_model.h5 100
Using Theano backend.
ディープラーニングによる予測消化日数
=1.2323265 [日]

テスト100項目を消化するため、1.2日程度必要との結果が出ました。


(5)プロットプログラム実行

$ python 04-deep_regression_plot.py model/dnn_model.h5 dataset/plot.csv


テスト項目数に対する予測消化日数をプロットしたグラフ、およびそのデータのcsvファイルを出力。

以下の2つのファイルが生成されます。

・result_figure.png
・result.csv

グラフのresult_figure.pngを示します。



trainが学習データ、predictが予測データを示しています。


本プログラムの使用方法については以上です。
コードの解説記事は以下にアップしております。
https://nine-num-98.blogspot.com/2020/03/ai-hyper-opt-02.html

スポンサーリンク