シン・Numerai TournamentデータをColab Pro+で扱うTips
はじめに
2021年09月08日(水)、チョットpython書ける人の不労所得先として日本でも名が知られてきた米国のヘッジファンドNumeraiが、毎週開催しているコンペであるNumerai Tournamentの新データをリリースしました。
- 特徴量数: 3倍
- レコード数: 5倍
- ターゲット数: 20倍 (ただし評価に使われるのは1つ)
という非常に大きな改変であり、今までのtournamentも決して小さなデータではなかっただけに、
「メモリが足りないYOOOOO!」
という声はリリース以前から国内外から聞かれていました。
一方で、今までのtournamentのデータだとmodel performanceのムラが大きいことが指摘されており(Leaderboadの順位が頻繁に入れ替わる)、新データのリリースで、よりパフォーマンスが安定したモデルを作ることができ、参加者の稼ぎも大きくなるのでは、という期待もされていました。
運営のbacktestでも、以前のデータセットに比べより良いパフォーマンスが出るらしいです。
この記事では、新・Numerai Tournamentのデータを扱うため
「Google Colab Pro+は月々約5,000円...Numeraiからの報酬であるNMRは今約5,000円なので、毎月1NMR稼げるだけで元が取れるジャン...!」
と自らを納得させ、断腸の思いでGoogle Colab Pro+を契約した私が、同じような皆様のために新・Numerai TournamentのデータをGoogle corab pro+で扱うtipsを書いていきたいと思います。
ただし、Colabは引き当てる環境は運次第なところがあるため、同じことをしても動かないこともあるかもしれません。そんな時はガチャをガチャガチャ引き直していただけると幸いです。
Colab Pro+でNumeraiをするTips
Numeraiは優しいので、exampleをgithubに用意してくれています。
が、これをこのまま実行すると、colab pro+のハイメモリでも動きません (!?)。それだけ巨大なデータなのですね。
なんとか動かすために、多少の工夫が要ります。
Tips 1: ハイメモリにする
「ランタイム」 --> 「ランタイムのタイプを変更」で、ランタイムの仕様をハイメモリにします。
残念ながらこれだけだとダメです (!?)。
Tips 2: featuresをint8にcastする
特に決定木系のモデルを使う場合、大事なのは特徴量の相対的な大小関係です。特徴量自体のスケールには依存しません。
Numerai Tournamentの特徴量 ('feature_XXX')は、新リリースだと1,050個ありますが、全て
0, 0.25, 0.5, 0.75, 1
の分位特徴量です。元々float32型ですが、これは無駄に重いので4を掛けてint8に型変換します。
0, 0.25, 0.5, 0.75, 1 --> 0, 1, 2, 3, 4
データが重いのでこの処理は高速に行うことが望ましいです。
以下のsnippetは、私がkaggle masterの友人に土下座して手に入れたものです。
def cast_features2int(df):
"""Cast numerai quantile features to int for saving memory
"""
cols = df.columns
features = cols[cols.str.startswith('feature')].values.tolist()
df_cast = (df[features].fillna(0.5) * 4).astype(np.int8)
df_ = df[list(set(cols.values.tolist()) - set(features))]
df = pd.concat([df_, df_cast], axis=1)
df = df[cols]
return df
Numerai Tournamentのデータの特徴量は未だかつてnanが入っていたことはありませんが、今後そういうこともあるかも、ということらしい(Super Massive Data Release: Deep Dive)ので、欠損値を中央値である0.5で埋める処理をしています。
Tips 3: LightGBMはData Structure (training) APIを使う
メモリ効率の良いlightgbmは、まず使用モデルの候補に上がります。せっかくなのでLightGBMもGPU版を使いましょう。Colabだと、以下を実行する必要があります。
# Install_LightGBM_with_GPU
! git clone --recursive https://github.com/Microsoft/LightGBM
%cd /content/LightGBM
! mkdir -p build
%cd build
! cmake -DUSE_GPU=1 /content/LightGBM
! make -j$(nproc)
! sudo apt-get -y install python-pip
! sudo -H pip install setuptools pandas numpy scipy scikit-learn -U
%cd /content/LightGBM/python-package
! sudo python setup.py install --precompile
%cd /content/
import lightgbm as lgb
print("lightgbm Version: ", lgb.__version__)
lightgbmのparamsに、GPUを指定することを忘れないでください。
params = {
'device': 'gpu' # GPU!
}
LightGBMは、sklearn APIとtraining APIどちらを使っても精度は変わりませんが、sklearn APIはtraining APIのwrapperなので、オリジナルのtraining APIを用いた方がいいケースもあります。
例えば、training APIを使って以下のようにpandasではなくnumpyを使ってDatasetを定義して学習させると、lgb.Datasetがpandas自体を保存する必要がなくなるため、メモリ使用のスパイクを回避できます。
numpyにしてしまうとfeature名が消えてしまいますが、dataset内のfeature_name=...にfeatureのリストを渡してやればfeature名付きfeature importanceも問題なく得ることができます。
# dataset making
train_set = lgb.Dataset(training_data[features].values, training_data[target].values, feature_name=features)
val_set = lgb.Dataset(validation_data[features].values, validation_data[target].values, feature_name=features)
# train
model = lgb.train(params, train_set, valid_sets=[train_set, val_set], verbose_eval=100)
この方法を使えば、Google Colab Pro+でも全データを使って自分は訓練可能でした。
feature importanceも問題なくgetだぜ!
More ideas
色々できることはあるような...気がします...
てかそもそもですね、
「全データ使う必要ある?」
「全データ使わない方がいいんじゃない?」
というのはあります。運営も、
You need to sample every 4th era to get non-overlapping eras with the 20 day targets, but every 12th era to get non-overlapping eras with the 60 day targets. If you choose not to subsample in this way, you instead need to be very careful about purging overlapping eras from your cross-validation folds. (20日ターゲットを使う場合は4 eraごとにサンプリングしたデータを使う必要があるし、60日ターゲットを使うなら12 eraごとだ。もしサンプリングせず全データを使うなら、交差検証のときに重複のあるeraの扱いはかなり丁寧に行う必要があるぞい)
と言ってますし。targetも21種類提供されてますので、それに合わせてsamplingして訓練データを使う方が安全みたいですね。
終わりに
シン・Numerai Tournamentデータまだまだ未知が多いです。いい発見があればこっそり教えてください。 Shall we play to earn?
Discussion
以下の記述なしでも今のColab だとGPU利用できませんか?勘違いでした。