grbl1.1+Arduino CNCシールドV3.5+bCNCを使用中。
BluetoothモジュールおよびbCNCのPendant機能でスマホからもワイヤレス操作可能。
その他、電子工作・プログラミング、機械学習などもやっています。
MacとUbuntuを使用。

CNCマシン全般について:
国内レーザー加工機と中国製レーザー加工機の比較
中国製レーザーダイオードについて
CNCミリングマシンとCNCルーターマシンいろいろ
その他:
利用例や付加機能など:
CNCルーター関係:



*CNCマシンの制作記録は2016/04/10〜の投稿に書いてあります。


ラベル Hyperopt の投稿を表示しています。 すべての投稿を表示
ラベル Hyperopt の投稿を表示しています。 すべての投稿を表示

2018年11月20日火曜日

Kaggle Digital Recognizer(MNIST): Keras, fit_generator() + hyperopt

Kaggle Digital Recognizer(MNIST)の続きです。前回から少しだけ内容を変えてみたらベストスコアがでました。
改良点は以下です。

fit_generator():
前回は、通常の訓練model.fit()を使った後にData Augmentationとしてmodel.fit_generator()を追加して二段階で訓練しましたが、今回は最初からfit_generator()だけで訓練してみることにしました。

BatchNormalization:
CNNに関しては前回よりも層を少なくして、conv2dの後に必ずBatchNormalization()を入れ、プーリング層(学習なし)を使わずにstrides=2のconv2d()(学習あり)で1/2にダウンサンプリングすることにしました。

Hyperopt:
Hyperoptに関しては前回同様Dropout率だけを最適化しています(合計3箇所)。探索回数はとりあえず10回。

スコア:
結果はこれまでのベストスコアである0.99771(Top 5%)まで向上しました。
この辺りまで来るとスコアを0.001上げるのはかなり至難の技で、正直0.997以上になるとは期待していませんでした。しかし予想以上に満足できる結果が得られたので、Digital Decognizer(MNIST)に関してはひと段落ついたという感じです。

ただし、調べれば調べるほど興味深い項目が登場してきて、今後試してみたいのは:
・他のMNISTデータセットで今回のモデルの精度を確かめてみる(KaggleのMNISTデータセットにオーバーフィッティングしていないかどうかの検証)。
・今回はHyperoptによってDropout率を自動的に決定させましたが、Dropoutを一般化したDropconnectというのもあるらしく、それを使うとどうなるか(Keras Dropconnect Implementation)?

Kaggleで勝つデータ分析の技術
門脇 大輔 阪田 隆司 保坂 桂佑 平松 雄司
技術評論社
売り上げランキング: 363


追記:
その後、既存のkeras.datasets.mnistのデータセット(60000+10000)で検証してみると0.997以上の正解率となりました。おそらくKaggleのMNISTデータも多数含まれているので似たような結果となったのだと思います(しかし偶然KaggleのMNISTデータだけにオーバーフィットしすぎているというわけでもなさそう)。

2018年11月16日金曜日

Kaggle Digital Recognizer(MNIST): Hyperopt + Data Augmentation

引き続きKaggle Digital Recognaizer(MNIST)のスコア向上のため、今回はHyperoptData Augmentationを組み合わせてみました。
結果として、これまで0.995前後(Top 18%)のスコアがでていましたが、今回の方法で0.99671(Top 9%)まで向上しました。それでも28000個あるデータのうち92個が間違っているということになります。


今回の方法:

・畳み込み層を増やしてもう少し特徴量検出できるようにする
・あまり自動調節させるハイパーパラメータは増やさない
・バッチサイズやデータ分割などは一般的な値にしておく
・Dropout率でモデル全体の精度を調整

要は、Hyperoptによるハイパーパラメータ最適化はDropout率(合計5個)だけに絞り、その他は固定。
探索回数は20回(GTX1060で約2時間)。

前回までと異なるのは:
・ダブルの畳み込み層をもう一式追加
・Dense層出力ユニット数の増加
・最後にData Augmentationでの訓練を追加
ということになります。

Data Augmantation(訓練データの変形加工:水増し)するためにKerasのImageDataGeneratorを使用しました。
ImageDataGeneratorを使うには元データのshapeを(-1, 28, 28, 1)にしておく必要があるようです。これまではCNNモデル入力層でkeras.layers.Reshape()を使って(784, )から(-1, 28, 28, 1)に変換していましたが、ImageDataGeneratorの入力次元数とモデルの入力次元数が異なるためエラーがでてしまい、モデルに入力する前に(-1, 28, 28, 1)へ変換することにしました。

流れとしては:
・訓練画像を元にHyperoptで最適化
・最適化されたモデルをData Augmentationで追加訓練
という二段階の訓練です。
Data Augmentationの訓練は結構すぐに収束してしまいましたが、その訓練の差なのかほんのわずか向上しました。


まとめ:
個人的には、これまでスコア0.995が壁になっていて、手動でいろいろ試してみたけれどもなかなか超えられませんでした。今回のスコアは期待していた以上に良かったので、MNISTに関してはもうこの辺で充分かと思いますが、あと試してみたいのは以下。
・最初からImageDataGeneratorで訓練
・交差検証(KFold

基本的なMNIST分類問題ですが、こうやってスコア向上を目標に試してみると、いろんなテクニックが見つかりかなり勉強になります。基本的なCNNアルゴリズムだけでなく、その他の方法も組み合わせることでわずかながらでも向上するということが分かったのもよかったです。

関連:
Kaggle Digital Decognizer(MNIST): Keras, fit_generator() + hyperopt


直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ
Posted with Amakuri at 2018.12.21
Antonio Gulli, Sujit Pal
オライリージャパン
販売価格 ¥3,672

2018年11月10日土曜日

Hyperopt:Digital Recognizer(MNIST)のハイパーパラメータの最適化



今回は、HyperoptでMNISTのハイパーパラメータの最適化を行いました。Hyperoptは前回試したHyperasの元となっているライブラリです。Hyperasはシンプルに使える反面やや扱いにくい部分(慣れていないだけかもしれませんが)もあったため、大元のHyperoptで書き直してみました。

データは前回同様KaggleのDigital Recognizer(MNIST)で、最適化するハイパーパラメータは以下です。

・Dropout率
・Dense層出力ユニット数
・batch_size数
・validation_splitの比率

Hyperoptの使い方:

ハイパーパラメータのディクショナリー設定:
まずハイパーパラメータのディクショナリーを以下のようなフォーマットで用意します。

params = {
    'Dense_0':          hp.choice('Dense_0', [128, 256, 512]),
    'Dense_1':          hp.choice('Dense_1', [64, 128, 256]),
    'Dropout_0':        hp.uniform('Dropout_0', 0.0, 1.0),
    'Dropout_1':        hp.uniform('Dropout_1', 0.0, 1.0),
    'Dropout_2':        hp.uniform('Dropout_2', 0.0, 1.0),
    'Dropout_3':        hp.uniform('Dropout_3', 0.0, 1.0),
    'batch_size':       hp.choice('batch_size', [16, 32, 64]),
    'validation_split': hp.uniform('validation_split', 0.1, 0.3)
}

離散値の場合はhp.choice()、連続値の場合はhp.uniform()を使います。このあたりはHyperasと同じような感じです。このほか乱数用のhp.randint()や正規分布用のhp.normal()などいくつかあります(ここに書いてあります)。


ハイパーパラメータの挿入と戻り値の設定:
次はモデルの構築です。MNISTデータの前処理をしておいてから、CNNを用いてMNIST分類モデルを構築します。そして最適化したい変数の部分(以下の場合:CNN層内のドロップアウト率)に、

model.add(Dropout(params['Dropout_0'], seed=seed))

という感じで挿入しておきます。
model.compile()、model.fit()したあと model.evaluate()でlossとaccを求めて、その値を戻り値とします。サンプルなどではlossのかわりにaccを評価値として次のfmin()関数に渡していますが、どちらがいいのかは不明。または、hist=fit()のhistoryからhist.history['val_loss'][-1]で最後のロス値を取得する方法でもいいのかもしれません(あるいは'val_acc')。尚、accを渡す場合はマイナスをかけて最大値を最小値に反転させておく必要があります。
またモデルなどその他の値やオブジェクトを渡すときはディクショナリーにするといいようです。ディクショナリーにする場合は、次のfmin()関数に値を渡すために'loss'と'status'のキーが最低含まれていないといけないようです。今回は追加でモデルも含めたので以下のような戻り値としました。あとでベストmodelを参照する場合は追加しておくといいと思います。

return {'loss': -acc, 'status': STATUS_OK, 'model': model}


最適化:
最後に、best=fmin()で最適なパラメータを見つけます。fmin()へモデルとハイパーパラメータディクショナリーを渡し、探索回数などを指定して最適化します。探索回数は多いほどいいと思いますが、それなりに時間はかかります(数時間とか)。
trialsには探索結果の記録が保持されるので後で参照します。

trials = Trials()
best = fmin(fn=cnn_model, 
            space=params, 
            algo=tpe.suggest, 
            max_evals=20, 
            trials=trials,
            verbose=1,
            rstate=np.random.RandomState(seed))

fn:CNNモデル(前述の'loss', 'status', 'model'が戻り値)
space:パイパーパラメータのディクショナリー
algo:使用するアルゴリズム(TPEなのでこのまま)
max_evals:探索回数
trials:探索記録保持先
verbose:ログ出力
rstate:乱数固定


結果参照:
best=fmin()からは最適化されたパラメータのディクショナリーが出力されます。そのままだと、hp.choice()の場合リストのインデックス番号が返されるので、

space_eval(params, best)

で実際の値に変換出力してくれます(以下)。

{'Dense_0': 512,
 'Dense_1': 256,
 'Dropout_0': 0.19796353174591008,
 'Dropout_1': 0.30328292011950164,
 'Dropout_2': 0.7005074297830172,
 'Dropout_3': 0.3974900176858912,
 'batch_size': 64,
 'validation_split': 0.16617354953831512}

あらかじめtrials=Trials()と定義しておけば、trialsの中に全ての情報が記録されるので、必要に応じて値やモデルを参照することができます。

trials.best_trial['result']

で以下が出力されます(複数回探索した中でのベストの結果)。lossはaccをマイナス反転したものなのでaccのこと、modelはそのときのベストモデル、statusは処理が無事完了なら'ok'。

{'loss': -0.9935714285714285,
 'model': <keras.engine.sequential.Sequential at 0x7fc5c3da87f0>,
 'status': 'ok'}

ベストモデルは、

best_model = trials.best_trial['result']['model']

によって参照することができるので、このモデルを使ってpredict()することができます。

まとめ:
前回のHyperasよりも使い勝手はよさそうです。それほど面倒なコーディングをすることもないので、個人的にはHyperoptのほうが便利かと。要は、パイパーパラメータディクショナリーとモデルを最適化関数に入れれば答えがでてくるということです。
詳しいドキュメントがないので(ここくらい)、細かな使い方はわからないのですが(ソースを読み解くしかないかも)、いろいろ応用できそうです。
今回はmax_evals=20で20回探索(NVIDIA GTX1060で49分)した結果、スコアは0.99257でした。まあまあの結果でしたが、実際100回以上(数時間)は回したほうがいいのかもしれません。

こちらのサイトでは様々なベイズ最適化ライブラリーを比較しており、時間的にはHyperoptが一番速いようです。10次元以下の最適化であればPyBOが優れているようで、それ以上の次元ではどれも遅くなるようです。また20次元や40次元になるとほとんどのライブラリが最適化できなくなるようで、Spearmintが20次元でも機能していたようです。

追記1:
その後100回(約6時間)回してみましたがスコアは0.99185という結果。validationセットでのスコアは0.995だったので向上しましたが、オーバーフィッティング気味だったったのか結果的にはいまいち。いずれにせよ0.992前後が限界という感じ。CNNの層を少し改造するか、kerasのImageDataGeneratorでデータ水増しした方がいいのかもしれません。

追記2:
validation_splitを0.2に固定して、Dropout率とDense層出力ユニット数だけをハイパーパラメータとして10回ほど探索すると0.99442まで向上しました。普通に考えてvalidation dataは少ないほどval_accは上がってしまうと思うので固定にしたほうがよさそうです。

関連:
GPyOpt: Digital Recognizer(MNIST) CNN Keras ハイパーパラメータ最適化
Kaggle Digital Recognizer(MNIST): Hyperopt + Data Augmentation
Kaggle Digital Decognizer(MNIST): Keras, fit_generator() + hyperopt


人気の投稿