データナード

機械学習と自然言語処理についての備忘録 (旧ナード戦隊データマン)

keras-tunerを使う

keras-tunerとは、kerasのハイパーパラメータチューニングのためのツールです。

概要

  • 問題: kerasでlaserを実装する際に、論文内に記述のない部分があり、その部分のパラメータをどうするのかわからない。
  • 現状の解決策: keras-tunerで大雑把に良いパラメータらしきものを見つける。
  • 方法: build_model関数の引数で主要なパラメータの設定ができる状態にしたので、それらの中でチューニングしたいものに焦点をあててkeras-tunerを使う。

コード

import numpy as np
import tensorflow as tf
import tensorflow.keras.layers as layers
from tensorflow.keras import backend as K
from kerastuner import HyperModel
from kerastuner.tuners import RandomSearch
from model import build_model
#tf.executing_eagerly()
 
class MyHyperModel(HyperModel):
    def __init__(self, params):
        self.params = params
 
    def build(self, hp):
        #self.params["use_emd"] = hp.Choice('use_emd', values=[False, True])
        self.params["drate"] = 0.1
        self.params["emdrate"] = hp.Choice('emdrate',
                                           values=[0.0, 0.05, 0.1, 0.2, 0.5])
        #self.params["drate"] = hp.Choice('drate', values=[0.0, 0.1, 0.2])
        #self.params["rdrate"] = hp.Choice('rdrate', values=[0.0, 0.1, 0.2])
        #self.params["use_lstm"] = hp.Choice('use_lstm', values=[False, True])
        #self.params["use_initial"] = hp.Choice('use_initial',
        #                                       values=[False, True])
        #self.params["use_raw_est"] = hp.Choice('use_raw_est',
        #                                       values=[False, True])
        self.params["use_zero_replacer"] = hp.Choice('use_zero_replacer',
                                                     values=[False, True])
        self.params["lidemb_dim"] = hp.Choice("lidemb_dim", values=[4, 32])
        self.params["emb_dim1"] = hp.Choice("emb_dim1", values=[100, 320])
 
        return build_model(**self.params)
 
 
def main():
    from params.light import PARAMS, DG, CONFIG
    gen = DG.data_generate_phase2_grp(DG.data_generate_phase1(), 100000, 10000)
    hypermodel = MyHyperModel(PARAMS)
    tuner = RandomSearch(hypermodel,
                         objective='val_sparse_categorical_accuracy',
                         max_trials=20,
                         directory='my_dir',
                         project_name='test_search3')
    X, Y = next(gen)
    train_size = int(0.8 * X[0].shape[0])
    X_train = [X[0][:train_size], X[1][:train_size], X[2][:train_size]]
    X_val = [X[0][train_size:], X[1][train_size:], X[2][train_size:]]
    Y_train, Y_val = Y[:train_size], Y[train_size:]
    assert X[0].shape[1] > 30
    tuner.search(X_train, Y_train, validation_data=(X_val, Y_val), epochs=2)
    tuner.results_summary()
 
 
if __name__ == "__main__":
    main()

# https://github.com/sugiyamath/keras-laser

サマリーの出力

[Trial summary]
 |-Trial ID: 079e0f15561f8fb8d6d33aff233718f0
 |-Score: 0.0027058369014412165
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 320
 |-emdrate: 0.5
 |-lidemb_dim: 4
 |-use_zero_replacer: 0
[Results summary]
 |-Results in my_dir/test_search3
 |-Showing 10 best trials
 |-Objective(name='val_sparse_categorical_accuracy', direction='max')
[Trial summary]
 |-Trial ID: b37992b182d681a3393aad64e7c68ede
 |-Score: 0.21182836592197418
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 320
 |-emdrate: 0.2
 |-lidemb_dim: 4
 |-use_zero_replacer: 0
[Trial summary]
 |-Trial ID: eb8da46c8b1d161be11c14063373e154
 |-Score: 0.200715109705925
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 100
 |-emdrate: 0.0
 |-lidemb_dim: 32
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: f755ac3b9a3f1104365d261b93e5a66c
 |-Score: 0.19279088079929352
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 100
 |-emdrate: 0.2
 |-lidemb_dim: 32
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: 7a4589f4f3643f0ad8c284b382dfc389
 |-Score: 0.18892540037631989
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 320
 |-emdrate: 0.5
 |-lidemb_dim: 4
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: a4c9839439a6915c4602a8c90e357a0b
 |-Score: 0.1798415184020996
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 320
 |-emdrate: 0.05
 |-lidemb_dim: 4
 |-use_zero_replacer: 0
[Trial summary]
 |-Trial ID: 59adf3c61c78a8e41778115db50ac51f
 |-Score: 0.16225357353687286
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 100
 |-emdrate: 0.1
 |-lidemb_dim: 4
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: 3854b04d6846dc129e4c346ed088b39b
 |-Score: 0.15809817612171173
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 320
 |-emdrate: 0.0
 |-lidemb_dim: 32
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: 43f18571aaadaf68eab2890014a5fdca
 |-Score: 0.15742172300815582
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 320
 |-emdrate: 0.2
 |-lidemb_dim: 4
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: ef037ca4447e95d7250d9923c6694c51
 |-Score: 0.1531696915626526
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 100
 |-emdrate: 0.1
 |-lidemb_dim: 32
 |-use_zero_replacer: 1
[Trial summary]
 |-Trial ID: 3ce0a0aa28605376d6d73c64099a837f
 |-Score: 0.14099343121051788
 |-Best step: 0
 > Hyperparameters:
 |-emb_dim1: 100
 |-emdrate: 0.05
 |-lidemb_dim: 32
 |-use_zero_replacer: 0

考察

  • 探索したいパラメータの他に、epochsとtrialsを指定する。探索するパラメータ、epochs、trialsが増えれば最適なものが見つかる可能性が高くなるかもしれないが、探索全体にかかる時間が増える。
  • laserというモデルに限っては、sentembレイヤーが適切な類似度を取れるかどうかを基準に精度を測ったほうが目的にかなっているため、翻訳精度を指標に使わないほうが良いかもしれない。
  • epochsが2程度のときに最もよいval_accを出すパラメータの組み合わせについて、epochsを増やしたときに別のパラメータの組み合わせに負ける可能性もあるので、どういうepochsを設定すればよいか。

参考

追記

2020-04-15 13:10

mask_zero=Trueを使うべきかもしれない。結局、ミニバッチの方法を変えても、何らかのパラメータによって文ベクトル内に0.0が大量に含まれてしまう現象が発生することがわかった。やはりsentembの出力を一定のイテレーションごとに評価するためのカスタムコールバックを作るべきだと思うが、効率よくsentembを評価する方法としてどのデータ(タスク)を利用するべきか。STSかPIを使う場合は、多言語で評価が行えればよいが...

2020-04-16 9:12

現在うまく行っているパラメータ(middle.py)は以下: https://github.com/sugiyamath/keras-laser/blob/master/scripts/model_scripts/params/middle.py

パラメータのリストはmodel_scripts/params/ に保存したが、基本的には以下のような傾向にあるように思える:

  • LSTMの代わりにGRUを使うとうまく行かない場合がある。
  • mask_zero=Trueをつけたほうがいい。
  • use_zero_replacer=Trueをつけても正常に機能しているように見える。
  • embeddingの次元, lstmの層数, sentembの線形変換後の次元数, などが多いほうが、学習によって精度の上昇が継続する傾向にある。
  • デコーダ入力にspatialdropoutを使わないほうが良い。
  • recurrent_dropoutを使わないほうが良い。
  • デコーダの出力は、トークン数が同じものでバッチ化しているので、カスタムlossを使う必要がない。
  • batch normalizationを使うと文ベクトルの類似度がちゃんと取れなくなる傾向にある。

なお、これらは単なる経験的な事象をまとめただけなので、理論的根拠はありません。