わくわく技術ブログ

プログラミング・統計・機械学習

3段階 Kaggle環境構築

先月よりKaggleに挑戦し始めました。 コンペに参加しながら計算環境について検討したので、これから始める方向けにまとめます。 環境構築に時間を掛けずに、アルゴリズムの検討に時間を掛けたいですね。

想定読者

  • これからkaggleに挑戦する、もしくは挑戦し始めたくらいで計算環境が未整備
  • WindowsコマンドプロンプトLinuxターミナル(Bashなど)のコマンド実行方法がわかる
    • コマンドを覚えている必要はない
  • Windowsユーザー
    • Mac/Linuxユーザーも、後半の手順は同様に参考にしてもらえれば
  • KaggleではPythonを使って挑戦する
    • Pythonの使用経験は多少ある

この記事に書くこと/書かないこと

書くこと

  • Kaggleに挑戦するにあたってオススメの計算環境,ツール

書かないこと

  • Kaggleで使うべきアルゴリズム
  • Kaggleの公式サイトの見方(有用な議論の発見の仕方など)

各環境の利用目的/導入方法概要

ローカルでの動作環境構築 → Google Colaboratoryの利用 → GCP(GCE: Google Compute Engine)上で環境構築の順でステップアップしながら整えていくのが良いと考えている。 それぞれの利用目的と導入方法の概要をまとめると次の通り。

※補足:Kaggle Kernelは、Commit時に再実行されたり、出力したファイルをCommitせずにローカルに持ってくる手軽な方法がなかったりして、ちょっと使いやすさで他に劣ると考えているためここでは紹介しない。

1. ローカル

利用目的

  • Kaggle参加にあたって使うツール類やSubmitまでの手順に慣れる
  • 軽い処理を気軽に試す
  • 電気代だけで何時間でも動かせる環境として使う

導入方法

2. Google Colaboratory

利用目的

  • ネットワーク越しの環境に慣れる(セッションがいつ切れても良いように実装する)
  • GPU/TPUを使って計算する

導入方法

3. GCP(GCE: Google Compute Engine)

利用目的

  • 処理時間(待ち時間)を短縮する
  • 大量メモリを必要とする処理を行う

導入方法

  • Kaggle提供のDockerイメージを利用する
  • Jupyter NotebookにSSHポートフォワーディングを利用してアクセスする
  • 適宜スペックを変更する

構築方法

1. ローカル(Windows)

Windows機械学習用途でPythonを使うには、Pythonディストリビューション(便利ツールやライブラリがセットになったもの)を導入するのが圧倒的に楽である。

一番の有名どころはAnacondaだが、自分はWinPythonを使っている。

  • Anaconda

    • 機械学習用途で圧倒的人気
    • Pythonの複数バージョンを併用できる
      • ただしKaggle用途では単一バージョンで良さそう
    • △ (defaultでは)隠しフォルダにインストールされるので全体像が見えにくい
    • △ Anaconda独自管理ツールを併用する
      • conda コマンド
        • pipと機能が重複する
      • Anaconda利用者向けの情報を探す必要がある
  • WinPython

    • 独自ツールは含まれない
      • 一般的な管理ツール(pipなど)を使う
      • Web開発などでPython経験があれば慣れた方法が使える
    • ポータブル
    • Pythonバージョンは固定
      • 使いたいバージョンのWinPythonをダウンロードする

Kaggleでよく使われるライブラリのうち、AnacondaやWinPythonに含まれないものは追加でインストールする。

WinPythonではXGBoostとLightGBMが含まれていなかったので追加する。 'WinPython Command Prompt.exe'を起動すると各コマンド(pythonpipなど)にPATHが通った状態でコマンドプロンプトが起動するので便利。

コマンドプロンプトが開いたら、次のようにするだけでインストールできる。

pip install xgboost
pip install lightgbm

ここまででツールは揃った。

コーディングのエディタなどはそれぞれ好みがあると思うが、KaggleではJupyter notebookやその類似のものを使うことが多い。(Kaggleが提供しているKernelというツールや、後述するGoogle Colaboratoryもその一種。)Jupyter Notebookではグラフや文字列の出力をそのまま保存できるのでとても便利。

Web開発ではVisual Studio CodeやPyCharmを使うことが多いと思う。それらにもJupyter Notebook統合の機能があり、特にPyCharmのコード補完機能は優れている。が、自分はいまいち使いにくいと感じたので素のJupyter Notebookを使っている。

'Jupyter Notebook.exe'を起動すると勝手にブラウザが開いてJupyter Notebookが使える。

Jupyrter自体の使い方は検索するとたくさん出てくるので他に任せる。セルの実行と追加/削除のショートカットキーは覚えているかどうかで効率がかなり変わると思う。

2. Google Colaboratory

ローカル環境で動かすことに慣れたら、Google Colaboratory(以下Colab)で動かすことに慣れるようにする。 ColabはGoogleが提供するサービスでJupyter Notebookに似た操作感がある。(ただしショートカットキーが異なる。)

Colab使う際には、Google Drive(以下Drive)に.ipynbファイルを保存するのが一般的。また、Kaggleで使うデータもDriveに置くのが簡単。

Colabの画面から直接ファイルを新規作成したりファイルアップロードしたりもできるが、既定の場所に自動でファイルが作られてしまう。そのため、先にDriveにファイルを作っておいて、それを編集したほうがファイルが迷子にならずに済む。

まずはDrive上でそれっぽくフォルダを作る。(input,output,scriptフォルダを作るのが一般的のよう。)

Driveでのフォルダ構成

ローカルのJupyter Notebookファイル(.ipynb)をDriveにアップロードしたら、右クリックメニューで「アプリで開く」→「Colaboratory」の順に選ぶと、Colabでそのファイルを開くことができる。 コピーではなくファイルそのものが開かれるので、編集結果は何もせずともそのまま反映される。

右クリック、アプリで開く

Colabの使い方はローカル環境で動かすJupyter Notebookと似ているが、クラウドで動いている点と、一定時間で接続が切れてしまう点が異なる。そのため、テストデータや出力結果の保存をどうするかが問題になる。

Colab上では、Driveとの連携のための特別パッケージを使うことができ、Driveのファイルの読み書きをスムーズに行うことができる。参考:ColaboratoryでのGoogle Driveへのマウントが簡単になっていたお話

私はいつも最初にDriveのマウントとカレントディレクトリの変更を実行している。 URLが表示されるのでそちらにアクセスするとGoogleアカウントとの連携画面に移動する。表示された通りに進めればOK。

# 自分のGoogle Driveにアクセスできるようにする
# Google Driveのトップが "/content/drive/My Drive/"になる
from google.colab import drive
drive.mount('/content/drive')

# 自分は"Kaggle/Santander/script"にノートブックファイルを配置しているので
# 相対パスで扱いやすいようにos.chdir()でカレントディレクトリを変更する
os.chdir("/content/drive/My Drive/Kaggle/Santander/script")

GPUやTPUが必要になったら、「ランタイムの切り替え」をすると使えるようになる。

ただし、Kaggle初心者がGPUやTPUの必要になる画像/音声データを使ったコンペに参加するのは、トライ・アンド・エラー回数が少なくなるので敷居が高めだと思う。

3. GCP(GCE: Google Compute Engine)

自分のようにノートPCしか無い人はデータとアルゴリズムによっては足りなくなる。Google Colabも12GBくらい使えるが、それ以上はエラーになってしまう。また、処理時間が掛かってしまい待ち時間が長くなってしまうケースというのがありうる。

そんな時にはクラウドサービス上で自分用のサーバーを建てて、その中でJupyter Notebookを動かすとよい。 特にGoogle Cloud PlatformのGoogle Compute Engineがオススメだ。 また、Kaggleが提供しているDockerコンテナが存在するので、それを使う方針で説明する。

GCEの選定理由

最初に悩むのが、どのクラウドサービスを使うかだと思う。クラウドサービスとして個人用で候補に上がるのはAWS EC2, MS Azure VM, GCPのGCEあたりだろう。Kaggle用としてはGCEを使うのがおすすめなので、手順としてはそれを前提とする。

GCEをおすすめする理由は、環境構築の手軽さとお金事情だ。

  • GCP(Google Cloud Platform)のGCE(Google Compute Engine)

    • プリエンプティブインスタンスにするととても安い
      • 24時間以内に必ず終了するインスタンスのこと
        • × 24時間で必ず停止する、それ以外にも勝手に停止することがある
        • ○ 長時間の利用には向かないが、止め忘れで課金されるリスクが低い
    • 無料トライアルの300ドルが使える
    • 管理画面が(AWSよりは)わかりやすい
    • スペックの変更が細かく可能
      • CPUは2coreだけどメモリは30GB みたいな設定ができる
  • AWS(Amazon Web Service)のEC2(Elastic Compute Cloud)

    • クラウドと比較して圧倒的に人気
      • 情報量が多い
    • Spotインスタンスはかなり安い
      • 稼働保証がないかわりに安くできる
        • △ 料金はこちらで指定して、オークションで買うような形式。少々面倒。
        • ○ 稼働時間に直接制限がない
        • × 停止(シャットダウン)しておくことができず削除になってしまう
    • 無料トライアルでは低スペックマシンしか使えない
    • 管理画面がわかりにくい
      • リージョンごとに画面を切り替える必要がある
        • Kaggleは安いリージョン(米国など)を使うのがおすすめだが、東京リージョンを既に使っている人は一覧性が低くなる
          • 高スペックマシンを使うことが多いと思うのでリスクになる
  • Microsoft AzureのVirtual Machine

    • 管理画面などの機能面は悪くない
    • GCP GCEのプリエンプティブインスタンスAWS EC2のSpotインスタンスのような割安プランが無い
    • 無料トライアル2ヶ月目以降は用途が限定される
      • 本番利用不可 など
      • 建てられるVMの性能も制限あり

GCE上の環境構築

まずはGCEのインスタンス(マシン)を用意する。

詳細手順は他の記事参考:GCP(Google Cloud Platform)での無料GCE(Google Compute Engine)インスタンス作成に任せるとして、ポイントは下記の通り。

  • リージョンは料金表を見ながら安いところにする
    • 自分はus-east1にしている
  • CPU,メモリは後から変更できるので、ひとまず安いもので十分
  • ディスクは30GB以上欲しい
    • データを一時的に置いたりするため
    • HDDで十分速い
    • あまり大きな容量にすると停止中もお金がかかるので注意
  • OSはUbuntuが何かと情報が多くて無難
  • プリエンプティブのオン/オフのメニューは隠れているので探す

また、自分の場合は普通のインスタンスとプリエンプティブのインスタンスを1つずつ建てている。多くの人が使っているためか、プリエンプティブインスタンスが使えない事があったため。そのような状況を1週間で2回経験している。

GCEのインスタンスを作成すると自動で起動する。停止や再起動はブラウザから行える。

起動中のインスタンスにアクセスして環境を整えたりするのには、Cloud SDKを使うのがよい。Googleアカウントでログインすると、暗号化通信のためのあれこれを勝手にやってくれる。インストーラをダウンロードしてきて指示の通りに進める。

Cloud CLIがインストールできたら、コマンドプロンプトで起動しているGCEインスタンスにアクセスする。 このとき、今後のJupyterのアクセスのために毎回 "-- -L 18888:localhost:8888" とオプションをつけるようにする。 (あとで説明する。)

gcloud compute ssh {インスタンス名} --zone {ゾーン名} -- -L {ローカル側ポート番号}:localhost:{リモートのポート番号}
# 例) gcloud compute ssh instance-1 --zone us-east1-b -- -L 18888:localhost:8888

Dockerインストール

GCEで建てたマシンに地道に準に必要なものをインストールしたり、ローカル環境と同様にAnacondaを使っても良い。

しかし、LinuxマシンならDockerを使うのが便利。Kaggleが公式に提供しているDockerイメージを利用でき、Kaggle Kernelと同じライブラリが使えるようになる。個人的にKernelの操作性は微妙だと思っているが、ライブラリ類は揃っているしKernelコンペというものもあるので、同じ環境が揃うのは嬉しい。
※ ただしGPU利用版は未提供

Docker公式サイトに各ディストリビューションでのインストール方法が載っているのでその通りに実行していく。 日本語で読みたい場合は参考:Ubuntuにdockerをインストールする の「2. リポジトリからのインストール」「4. 一般ユーザでの実行」を実行して、一旦接続を切ってgcloud comute ssh {インスタンス名} --zone {ゾーン名} -- -L {ローカル側ポート番号}:localhost:{リモートのポート番号}で接続しなおす(マシンの再起動は不要)。

Docker起動

次のコマンドでKaggle公式のDokerを起動する。

docker run --name kaggle -v $PWD:/tmp/working -w=/tmp/working -p 8888:8888 -itd kaggle/python jupyter notebook --no-browser --ip="0.0.0.0" --notebook-dir=/tmp/working --allow-root

オプションが長いので説明。爆速でKaggle環境を構築するに記載の手順ほぼそのままだが、デーモン起動する方が便利なのでその点を変えている。

  • --name kaggle
    • kaggleという名前で起動する
      • docker stop kaggleとすれば止まる、docker start kaggleとすれば再び起動する
  • -v $PWD:/tmp/working -w=/tmp/working
    • dockerの中と外とでカレントディレクトリを共有する
    • dockerを停止してもファイルが残るようになる
  • -p 8888:8888
    • ポート8888番を8888番に転送する
  • -itd kaggle/python jupyter notebook --no-browser --ip="0.0.0.0" --notebook-dir=/tmp/working --allow-root
    • kaggle/python(Kaggleの提供するコンテナ)でjupyterコマンドを実行する
    • デーモンとして起動する(sshが切れても勝手に終わらないようにする)
    • --ip="0.0.0.0"
      • 外部から(どこからでも)繋がるように
    • --allow-root dockerを使うとrootでの実行になるのでrootを許可する

無事に起動しても何らかのエラーが出ても、コンソール上には何も表示されないdocker logs {コンテナ名}コマンドで出力を確認し、http://{12桁の英数字}:8888/?token={長い英数字}と表示されたら問題なくJupyterが起動している。

docker logs kaggle
# 出力例

[I 01:20:01.337 NotebookApp] The Jupyter Notebook is running at:
[I 01:20:01.337 NotebookApp] http://3078d3d264c3:8888/?token=c7601ca8dd41f61e739373168c07bb232557a5de8a19357b
[I 01:20:01.337 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 01:20:01.338 NotebookApp]

    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://3078d3d264c3:8888/?token=c7601ca8dd41f61e739373168c07bb232557a5de8a19357b&token=c7601ca8dd41f61e739373168c07bb232557a5de8a19357b

Jupyterに接続

上の手順でhttp://{12桁の英数字}:8888/?token={長い英数字}が無事に表示されたら、ローカル端末からGCEの上で動くJupyter Notebookにアクセスする。

表示されたURLの{12桁の数字}の部分をlocalhostに、ポート番号888818888に変えたものをブラウザに打ち込む。http://localhost:18888/?token={長い英数字}

自分はPuttyでのクリップボードへのコピー方法が最初分からなかったが、該当部分をマウスで選択するだけでいい。(ctrl-cは別の意味になるので)。

Jupyter Notebookの画面が開かれればOK!存分にKaggleを楽しめる。 なお、gcloudコマンドで起動したコンソール画面(Puttyの画面)は閉じないこと。理由は下の補足参照。

うまくいかない場合は、

  • docker logs kaggleでエラーが表示されていないか
  • ここまでの手順で888818888を間違っていないか
  • gcloud compute sshで開いた黒い画面を閉じていないか
  • (docker logsにエラーもアクセス履歴も何もないなら)gcloud ssh のときに -- -L 18888:localhost:8888 を忘れていないか

を確認する。

GCEのシャットダウン、再起動

無駄な課金を防ぐには、使わない時にはGCEのインスタンスをシャットダウンしておく必要がある。 (GCEではOSシャットダウン時はディスクのみ課金、サービスによって扱いが異なるので注意。)

ブラウザから強制的に止めてしまっても自分の環境では問題は起きていない。気になる人は念の為に次のコマンドで停止する。

docker stop kaggle    # "kaggle"という名前のDockerコンテナの停止 = Jupyterが止まる
sudo shutdown -h now  # サーバーのシャットダウン

逆に停めていたサーバーを起動するときには、ブラウザから操作すればよい。

サーバーを起動するだけでは中のDockerコンテナまでは起動しないので明示的にコマンドで起動する。 毎回docker runするのではなく、2回目以降はdocker startする。

docker start kaggle   # "kaggle"という名前のDockerコンテナの起動

# この後、docker logs kaggle でアクセスURL(token)を確認する

Google Cloudのスマホアプリからもステータスチェックや開始/停止できる。停止漏れの確認に使える。

データの保存先

軽いファイルの保存や出力結果をローカルで軽く確認したいときは、Jupyter Notebookのダウンロード機能、アップロード機能を使えばいい。

大きなファイルサイズのものはGoogle Cloud Storageにデータを保存しておくのがよい。アメリカに置けば5GBまで無料らしい。 GCEのマシンにはデフォルトでgsutilというGoogle Cloud Storageを操作するためのツールがインストールされている。 ブラウザで操作しても良いが、大きなファイルサイズのデータは、これを使ってGoogle Cloud Storageとやりとりをすると非常に高速。詳細は他記事を参照。

スペック変更

マシンをシャットダウンしている間なら、CPUとメモリの量を変更できる。 データサイズとアルゴリズムによって必要なメモリは異なるので、動かしながら調整していくといい。

もともとGCEでは一度マシンを削除しないと変更できなかったらしくその時の情報が検索すると出てくる。しかし今はブラウザからクリックだけでできる。(スクリーンショットは載せてもすぐに変わりそうのため省略する)

補足1:gcloudコマンドのオプションとポートの関係

gcloudに接続するときのコマンドは下記の通り(再掲)

gcloud compute ssh {インスタンス名} --zone {ゾーン名} -- -L {ローカル側ポート番号}:localhost:{リモートのポート番号}
# 例) gcloud compute ssh instance-1 --zone us-east1-b -- -L 18888:localhost:8888

この--から後が、SSHポートフォワーディングの設定になっている。 上記の例ではlocalhost:18888にアクセスするとSSHのトンネルを通って(つまり暗号化された状態で)サーバーの8888番ポートにアクセスしたことになる。(サーバー上でlocalhost:8888にアクセスしたのと同じになる。)

さらに、Docker起動時に-p 8888:8888指定をしているので、Ubuntu8888ポートがDockerコンテナの8888ポートに繋がる。 この仕組みを利用してローカルのブラウザからJupyterにアクセスしている。そのため、GCEのネットワーク設定を変えることなくJupyterにアクセスできるようになる。

ポートフォワーディングはPuttyの画面を開いている間だけ有効なので、Puttyの画面を閉じてしまうとブラウザからアクセスすることができなくなるので注意。

Jupyter Notebookへのアクセスとポート番号

補足2:ネットワークファイアウォールの追加設定

補足1の通り、SSHポートフォワーディングを利用してサーバー(の中のDockerの)Jupyterにアクセスしている。そのためSSH用の22番ポートだけ使えれば良い。

GCEではデフォルトで外部からの8888番に対するアクセスは拒否されているが、内部からのアクセスは許容するdefault-allow-internalというルールが付いている。 外部アクセス禁止かつJupyterの起動時にtokenを使っていれば、すぐさまセキュリティ上問題になる可能性は低いと思う。一方でroot権限で動いているJupyterからはどんな事でも出来てしまうので、万一不正アクセスされた場合には怖い。

そのため、GCEの「VPCネットワーク」→「ファイアウォールルール」で、内部外部を問わず8888ポートへのアクセスを禁止しておくことを推奨する。

補足3:JupyterのPassword認証を使いたい / 起動ごとにtokenを調べるのが面倒 なとき

Jupyter Notebookの設定変更はjupyter_notebook_config.pyファイルを書き換える方法が一般的だが、実は起動オプションだけで相当数の(一時的な)設定変更ができる。 参考:Jupyter Notebook公式

例えばtokenは使わず毎回同じパスワードで起動したいとする。 パスワードの生成方法はJupyterを導入しよう -リモート編-などを参考にして、下記オプションで起動すればjupyter_notebook_config.pyを変えることなく設定を反映させて起動できる。

# passwd()して"ubuntu"を変換したら'sha1:a0a28df801c9:7bab5ea21d39cf03bb54100dcaf8cf9664dc9ddb'になったとする
--NotebookApp.token='' --NotebookApp.password='sha1:a0a28df801c9:7bab5ea21d39cf03bb54100dcaf8cf9664dc9ddb'

ただし、セキュリティとしては弱くなる。 補足2に書いた通り、万が一乗っ取られると危ない。補足2のファイアウォールルールの追加はセットで行うべきと思う。

まとめ

3段階でKaggleに挑戦するための環境を整えていく方法を紹介した。

  1. ローカルで動かす
  2. Google Colaboratoryを使う
  3. Google Compute Engine上で動かす

それぞれに利点/欠点があるので、コンペの期限やお財布事情(無料トライアル枠の残高)などを見ながら使い分けていきたい。

この記事で記載できなかったこと

  1. GCP上でGPUを計算に使う環境の構築
    • 現状ではCPU対応のDockerイメージしか公開されていない
    • GCEのCUDAドライバ対応マシンイメージを使う + tensorflowなどをインストールし直す といった手順が必要なはずだが試せていない
  2. Dockerを使わずにGCP上で手軽に環境を整える方法
    • 本来は何度もマシンの作成/削除を繰り返さないならDockerを使う必要はない

その他

本文中で紹介しなかった参考記事/動画