Numerai で Random Seed Average
この記事は、Numerai Advent Calendar 2020の1日目の記事です。
2日目の記事はUKIさんの「NumeariトーナメントのValid Corrをちょびっとだけ上げる小技」です。
参考資料
はじめに
ニューラルネットワークなどの機械学習ではモデルの初期値を乱数で生成しています。
その初期値によってスコアが変動しまうことに悩んでおりました。
初期値を変えながらモデルを作成して、validationのスコアがいいものを選んだらいいのか?どうアプローチをしたらいいのか?と悩んでおりましたところ、ランダムシードアベレージという手法を教えていただきました。
実験
実験Notebookはこちら(Gist)。
- 公式example scriptの初期値を変えながら30個のモデルを生成します。
- 各モデルのvalidation予測のスコアの平均を計算します。
- 各モデルのvalidation予測を平均した予測のスコアを計算します。
結果
| モデル | validationスコア |
| ---- | ---- | ---- |
| model_0 | 0.028905115759917572 |
| model_1 | 0.028839441329809517 |
| model_2 | 0.02921323028079193 |
| model_3 | 0.028522350017145304 |
| model_4 | 0.02936801687338555 |
| model_5 | 0.029079186323748136 |
| model_6 | 0.028979724294433268 |
| model_7 | 0.029251024058632485 |
| model_8 | 0.02840886764966899 |
| model_9 | 0.02880805730907734 |
| model_10 | 0.02843635982530843 |
| model_11 | 0.026877035233155034 |
| model_12 | 0.02839237423196859 |
| model_13 | 0.028494873071677432 |
| model_14 | 0.02799380622096903 |
| model_15 | 0.028915742343947268 |
| model_16 | 0.02921264209585863 |
| model_17 | 0.028761814861732047 |
| model_18 | 0.029395473225945552 |
| model_19 | 0.028925262488193715 |
| model_20 | 0.02911980690722348 |
| model_21 | 0.028839393923219304 |
| model_22 | 0.02903148499758035 |
| model_23 | 0.028984570921122724 |
| model_24 | 0.029681396528901567 |
| model_25 | 0.029568379432439205 |
| model_26 | 0.028575497738446528 |
| model_27 | 0.029951257363657842 |
| model_28 | 0.028710364124751427 |
| model_29 | 0.028693068012659983 |
| スコアの平均値 | 0.028864520581512277 |
| 予測の平均のスコア | 0.02916771995422608 |
考察
スコアの平均値よりも、予測を平均したもののスコアの方が高くなりました。
違う初期値で作成したモデルの予測をそれぞれsubmitするよりも、平均してからsubmitしたほうが、Payoutsは多くなると期待できそうです。
私のニューラルネットワークのモデルはXGBoostよりも更にばらつきがでるので、とりあえずRandom Seed Averageしておけば初期値ガチャに悩まなくて済みそうです。
また、予測は1アカウント10個までしか提出できないので節約できておトクですね!
Kerasで予測の平均を出力する
さて、10個の予測を平均しようとすると、予測の計算に10倍の時間がかかってしまいます。
Kerasなどを使用してGPUで予測を計算している場合、GPUの計算能力に空きがあれば、並行で実行して時間を短縮することができます。
Kerasで各モデルの平均を出力するモデルの作成方法をご紹介します。
KerasにはAverageレイヤーがあるのでこれを利用します。
models = []
for filename in model_filenames:
model = keras.models.load_model(filename)
# model.nameがレイヤー名になるので、かぶらないように変更する
model = keras.Model(inputs=model.inputs, outputs=model.output, name=filename)
models.append(model)
input = keras.layers.Input(models[0].input.shape[1:])
models_outputs = []
for m in models:
models_outputs.append(m(input))
ave_layer = keras.layers.average(models_outputs)
ave_model = keras.Model(inputs=input, outputs=ave_layer)
ave_model.summary()
ave_model.save(save_model_filename)
この ave_model
を使えば1つのモデルと同等の時間で、予測を計算できます。
終わりに
これでようやく初期値の悩みから解放されました。
Discussion