Kaggleで多くの実験を回すためにやっている簡単なこと

4 min読了の目安(約4000字TECH技術記事

はじめに

こんにちは。fkubota(Kaggle Expert 20201001現在)です。先日公開したKaggle日記の記事が好評だったので、調子に乗ってもう一つ。

今回は、僕が行っているとても簡単だけど効果が大きいKaggleの実験高速化の話です。おそらく当たり前すぎてこれまで記事にされなかったのかもしれませんが、これから積極的にKaggleに参加したいビギナーのために書きます。今回も、キラキラした画期的な特徴量エンジニアリングではなく、泥臭いテクニックを話します。

なぜ多くの実験を行いたいか

言うまでもないですが、多くの実験を行ったほうが勝つ確率は上がります。僕は今回の鳥コンペが初画像コンペでしたのでより多くの実験を行って勘所をつかむ必要がありました。案の定、Pytorchの癖をはじめはつかむことができず、コンペの1/3はPytorchのお勉強に使ってしまいました。
とにかく、ビギナーであればあるほど多くの経験をしてKaggleに慣れる必要があります。しかし、それと同時にビギナーは戦い慣れしていない為、思いついたアイデアを早く形にすることができません。
今回は、そこに対して僕が行っている簡単なことを紹介します。

アイデアを試す過程

一般的にアイデアを形にしてサブミットするまでの過程は以下のようになると思います。

  1. アイデアを思いつく
  2. 既存のコードを編集してアイデアを形にしていく
  3. 実行
  4. サブミット

今回、工夫を入れるのは2. 既存のコードを編集してアイデアを形にしていく の部分です。ここに多くの時間を費やすはずです。3は時間はかかることがありますが、待ち時間なので、手を動かす2の方を改善していきます。

待ち時間

2. 既存のコードを編集してアイデアを形にしていく は言い換えれば動かないコードを動くようにする過程です。この時間は短ければ短いほどいいです。では、改善できそうな場所はどこでしょうか。

Kagglerなら必ず書いたことがあるコード

kf = KFold(n_splits=5, shuffle=True)
for fold_i, (train_idx, valid_idx) in enumerate(kf.split(X)):
    X_train, X_valid = X.values[train_idx, :], X.values[valid_idx, :]
    y_train, y_valid = y[train_idx], y[valid_idx]
    
    hogehoge01
hogehoge02

アイデアをhogehoge01hogehoge02に入れる場合を想像してください。よくあるシチュエーションだと思います。この時、hogehoge01hogehoge02 でバグが発生したためなんどもセルを実行すると思います。最悪なのはhogehoge02にバグがある場合です。hogehoge02 を直す為だけにKfoldのループを待たなければなりません。待ち時間を短くするためのアドホックな手法としては、X.iloc[:10, :] などを行い、Xを一時的に小さくするなどでしょうか。しかしこれも問題が起こります。このセルの次のセルで、Xを小さくしたために、データのシェイプが一致しないというバグが発生することがあります。結局、X.iloc[:10, :] --> X として実行し、ながいループを待つことになります。絶好のTwitter時間です。

DEBUGモード

僕はノートブックを作成した時には必ず、ノートブックの上方にDEBUGという変数を用意します。

例えばDEBUGモードがTrue、Falseで処理に以下の違いが現れます。

DEBUG False True
n_samples 1000000 100
save model? True False
save features? True False
n_splits 5 2
epoch 50 3

といった感じです。動かないコードを動くようにする過程では、データをすべてメモリに載せる必要はないし、オブジェクトも保存する必要はありません。学習の時間も最小限で構わないです。僕の ノートブック(人に見てもらうクオリティではないですが...)やパイプラインでは、以下のようなif DEBUGが頻出します。

これだけですが、やってみるとものすごく効率があがります。僕は初めて参加した分子コンペで使い始めてからその効果がものすごくて毎回使っています。本当に待ち時間がほぼゼロになりますからおすすめです。強い人はもっといろいろやってるのかもしれませんが、クソザコExpertの僕は今の所この方法です。これを踏み台にしてもっと良くしてください。そして教えてください。

もう一つの恩恵

副産物としてさらに良いことがあります。ノートブック特有のバグに、もう一度実行するとエラーが発生するというものがあります。

  • セルは消してしまったが、メモリに変数が残っているためたまたま動いていたコードが再実行した際には動かなくなってしまった。
  • 実は、同じセルを二回実行しなければならなかった

などビギナーあるあるだと思います。これを避けるためには、コードが完成したら、ノートブックを一度リロードするという方法があると思います。ただこれもやりたくない場合が多いと思います。

僕の場合、ノートブックの前半などで前処理や特徴量生成などの重い処理を行っているのでそれをもう一度実行するのは気が引ける が殆どの理由でした。これも同じ経験した人は多いのではないでしょうか。DEBUGモードを実装していれば問題ありません。実行自体に殆ど時間がかからないのでリロードして全体実行もすぐに完了します。これでコードの再現性を担保できます。コンペも仕事も僕は必ず以下の手順を踏むようにしています。

  1. DEBUG == True
  2. コード編集
  3. 完成
  4. reload
  5. run all
  6. 全て動くか確認
  7. DEBUG == False
  8. run all

データをすべてメモリに載せるのは、7以降だけです。

コツ

僕がDEBUGモードを使い始めて気づいたコツをここで紹介しておきます。
DEBUGモード時に一番効果があるのは、データ数を減らすことですが、ここでも注意が必要です。
例えば、10000サンプルがdataという変数に格納されている場合を考えます。減らす方法としては、data[:20]data[::100] などが考えられます。この時に注意してほしいのがクラス数です。10クラスのデータセットだとします。上記のようなデータの減らし方をした場合、運悪くすべてのパターンのクラスが入らない場合があります。これにより余計なバグが混入する場合があるので注意してください。今回の鳥コンペの場合は以下のような方法を取りました。

  • 264種類の鳥の音ファイルから2つずつ。
  • 合計264x2 = 528 ファイルを使用する。

こんな感じです。なぜ、x2なのかというと2foldだからです。データを小さくするときのコツとしては、図形の面積を小さくすればいいのではなく、図形の相似を保ったまま小さくするようなイメージです。大きなデータの性質をある程度保ったまま小さくすると小さくしたことによるバグはなくなります。

終わりに

以上です。非常に簡単でコンペの初期に一度実装してしまえばその後ずっと恩恵が受けられるテクニックをご紹介しました。機械学習をやっている人はデバッグ?が苦手(僕もそうなんですが...)なイメージがあったため記事にしてみました。
最後まで見ていただきありがとうございました!!

また、以下のことを知らない人はこちらも試してみても良いかもしれません。