2018-11-5

Docker使って手軽にGCEで機械学習できる環境を整えた

最近、強化学習的なとこに手を出してみたけど手元のMacbook AirじゃメモリやCPU的に厳しいのでクラウドで実行することを検討した。 最初はAmazon EC2借りようかなーと考えていたけれど、Google Compute Engine(GCE) だとプリエンプティブという格安実行モードがあることを知り、GCEで実行することにした。 プリエンプティブモードで実行すると、1日しかインスタンスを実行できない、突然インスタンスが停止するなどのデメリットがある代わりに、通常価格より50%以上安くインスタンスを利用できる。

しかし毎回ファイルを転送してsshで繋いで実行するのは正直面倒くさい。そこでDockerを使って効率的にプログラムをGCEで実行する環境を整えた。 具体的には機械学習用イメージのビルド→イメージのアップロード→コンテナの起動・実行をコマンドラインからささっと実行できるようにした。

環境構築にあたって以下の2つのサービスを使用した。

  • Google Compute Engine
  • Google Container Registry(Dockerイメージのアップロード先)

Google Container Registryは使用したネットワークとストレージ分だけ課金されるので、少しでも課金額を抑えたい場合には1レジストリだけ無料で使えるDocker Hubなどを使った方がいいかもしれない。

Step.0 前準備

gcloudのインストール

Google Compute Engineをコマンドラインから使うためにglcoudをインストールする・ ここでは導入方法の説明は省くがGCPのgcloudコマンドをインストールする - Qiitaを参考にすればインストールできると思う。

プロジェクトの作成・Google Container RegistryのAPI有効化

Google Cloud Platformにアクセスして新しいプロジェクトを作成する。 左のサイドーからContainer Registryを選択してAPIを有効化する。 (Google Container Registry以外のサービスを使う人、既に有効化している人はこの作業をする必要はありません)

スクリプトで使用する用の環境変数の設定

今回の説明ではプロジェクト名や、イメージの名前を環境変数に設定して使用する(スクリプトにベタ打ちしてGithubにアップしちゃうのが怖いので)。 CLOUDML_HOST_REGIONにはasia.gcr.ioeu.gcr.ious.gcr.ioなどから選べる (参考:Pushing and Pulling Images  |  Container Registry  |  Google Cloud)。 CLOUDML_PROJECTIDには作成した自分のプロジェクトIDを、CLOUDML_IMAGE_NAMEには適当にイメージの名前を設定する。

bash
Copied!
$ export CLOUDML_HOST_REGION="REGION TO UPLOAD"
$ export CLOUDML_PROJECT_ID="YOUR PROJECT ID"
$ export CLOUDML_IMAGE_NAME="YOUR IMAGE NAME"

Step1. Dockerfileの準備

普通にDockerfileを作成する。今回はtensorflow、keras、lightgbmのCPU版をインストールしている。 また実行するファイルをビルドするときに変えられるように実行ファイル名を変数として持たせている。 注意点としてpythonの引数に-uを指定しないと出力がフラッシュされなくて、Stack Driverにログが正しく表示されないのでちゃんと指定する。

Step2. アップロード用のスクリプトの準備

DockerfileからイメージをビルドしてGoogle Container Repositoryにアップロードするスクリプトを作る。 実行したいファイルを引数に渡すとそのファイルを実行するイメージをビルドしてくれる。main.pyというスクリプトを実行するイメージを作成したい場合には以下のように実行する。

bash
Copied!
$ ./deploy.sh main.py

実行に成功すると最後にレポジトリの名前を出力してくれる。

Step3. 実行用のスクリプトの準備

使用するイメージの名前、使うインスタンスの名前を指定するとGCE上で実行してくれるスクリプトを作る。 細かいインスタンスの設定はgcloud beta compute instances create-with-containerの引数で行う。 今回は4コアCPU、メモリ20GB、ディスクサイズ50GB、プリエンプティブ有効の設定で実行した。 他の設定で実行したい場合には一度手動でインスタンスを作成して課金額を確認したあとに https://cloud.google.com/sdk/gcloud/reference/beta/compute/instances/create-with-containerを参考にして引数を決定するのが良いと思う。

2018年11月4日現在gcloud beta compute instances create-with-containerは実行することができるが、ベータ版のコマンドなので今後のアップデートで実行できなくなる可能性がある。

実行してみる

今回作成したスクリプトを使用してkerasのmnistを実行してみる。今回作成したスクリプトに置いてある。 環境変数などを設定したあとにdeploy.shを実行すると長々とビルドメッセージが流れたあと最後にレポジトリの名前を教えてくれる。

bash
Copied!
$ ./deploy.sh main.py

deploy.shの実行が終わったら次のようにしてコンテナを実行する。今回はインスタンス名としてtest-instance1を指定したが、自分で実行するときは好きな名前を使用して問題ない。

bash
Copied!
$ ./exec_container.sh test-instance1 レポジトリ名

コンテナの実行に成功するとインスタンス、IPアドレス、CPU数などの詳細が出力される。 ブラウザ上でGCEのインスタンス一覧を確認するとコンテナが実行されていることが確認できる。 またインスタンスを選んでログを表示すればプログラムが実行されていることが確認できる。

今回はCPUしか使用してないがDockerfileとexec_container.shを修正すればGPUも使用できるようになるはず。 現状exec_container.pyにバグがあるみたいで、処理が一通り終わるともう一度コンテナがはじめから実行されてしまう。時間があったら今後修正する予定。