📖

Google Cloud Run で Numerai Compute に対応してみた

2022/12/08に公開

English version

Numerai Compute 対応

Numerai には Numerai Compute という Webhook の仕組みがあります。公式の numerai-cli を使用すると AWS 環境で Webhook から予測の提出までの自動化をセットアップしてくれます。numerai-cli を使用するのが簡単なのですが、モデルの学習で GCP を使用しているため自動化も GCP にまとめておきたかったため Cloud Run を使用して Numerai Compute に対応してみたので記事にしてみました。Webhook 用に、データ取得・推論・予測提出するメソッドを実行するエンドポイントを Fast API で作成してコンテナにまとめます。コードは以下になります。

numerai-compute-cloudrun-template

使用方法は、以下になります。

  1. まず上記のコードをコピーしていただき、「GCP_PROJECT」という環境変数にGCPのプロジェクト名を設定します。
  2. 次に、 numerai-public-idnumerai-secret という名前で Numerai の API キーを Secret Managerに登録します。
  3. 実行用のサービスアカウトを numerai-compute という名前で作成します。
  4. 作成したサービスアカウントから cloud run/secret/artifact registry にアクセスできるように権限を付与します。
  5. predictors/pred1/predictor.py にデータ取得・推論・予測提出するコードを記載します。
  6. Makefile の存在するルートディレクトリで make release-pred1 と実行します。
  7. コンテナイメージがビルド・プッシュされて Cloud Run のデプロイされた URL が表示されるのでコピーします。
  8. Numerai のモデルの Compute に https://YOUR_CLOUD_RUN_URL/pred/YOUR_NUMERAI_MODEL_ID のように submission webhook を設定します。

※ 現状、ログの確認や停止・削除は GCP の Console から実施しています。

Numerai Compute に対応してみて

これまでは毎週末Google Colabのノートブックを手動実行して予測を投稿していたのですが、モデル数が増えてくるとインスタンスを割り当ててもらえなくなったり、全部を実行し終わるのに10分以上かかっていたのが今は自動で予測投稿するようになったので気持ちがとてもらくになりました。もしまだ自動化していないようでしたら自動化おすすめですよ!

Numerai Compute の Webhook リクエスト

Numerai Compute は各モデルについてのコンテキストメニューから Compute を選択することで設定できます。Submission webhook に指定したURL宛に送られるリクエストは以下になります。テスト実行時と実際に送られてくるものでは、roundNumberが数字型ではなくて文字列になっていること、isTest項目が増えていること、の2点が異なっています。ただし、予測提出にはリクエスト内容に応じて分岐処理などはしなくてもよいためそこまで注意する必要はないと思います。

round 開始時

{
    "roundNumber": 371,
    "dataVersion: 1,
    "triggerId": "99361e43-xxxx-xxxx-xxxx-73c29c72xxxx"
}

テスト実行時

{
    "roundNumber": "test",
    "dataVersion": 1,
    "triggerId": 'ea6a1f34-xxxx-xxxx-xxxx-0cb7b184xxxx'
    "isTest": true
}

Fast API 用のリクエスト定義

上記のリクエストに Fast API で対応するため以下のクラスを定義しています。このように定義しなくてもPOSTリクエストが来たことをトリガーに動かすこともできるのですが、Cloud Run で運用していて想定外のリクエストを受信した際にバリデーションではじいてくれるためこのようにしています。

class NumeraiComputeWebhookRequest(BaseModel):
    roundNumber: int | str
    dataVersion: int
    triggerId: str
    isTest: bool | None = None

Discussion