読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

AWS LambdaでGnuGo

[追記 2018-11-27] デフォルトの設定では中盤でのGnuGoのestimateがAmazon API Gatewayタイムアウトである29秒以内に完了しなかったです。AWS Lambdaはメモリを増やすとCPUパワーも増える仕様なので、256MBに増やしたところ、estimateできました。メモリ最大の3GB設定で使うといいと思います。

初めてAWS Lambdaを使ってみました。

AWS Lambdaはサーバーレスアーキテクチャのサービスで、課金が処理の時間だけにかかるサービスです。
自動でスケールするらしいので、頻度はそれほどでもなく、ただ処理に比較的時間がかかるようなサービスを提供したい時に最適です。

モバイルの囲碁アプリに整地機能を入れるとき、GnuGoをアプリに載せるのは大変なので、ウェブAPIとして実装している方多いのではないでしょうか?
GnuGoは正確に整地しようとすると結構計算に時間がかかります。またしょっちゅう使われる機能ではない反面たまたま同時にリクエストを受ける可能性も十分あり、必要な際には複数インスタンスが起動してなおかつ処理時間だけ課金されるサーバーレスサービスがうってつけになります。

しかも無料枠があるので、趣味でアプリを作っている方も気楽に使えます。
1局面30秒使うとして、メモリ3GBなら4,444リクエストが無料です。

前置きはこのぐらいにして、以下が作ったパッケージです。

github.com

インストール

gnu.zipにAWS Lambda用の、ハンドラと呼ばれる関数の定義ファイルとAWS Lambda上で動くGnuGoが同梱されています。
特にソースを見る必要はなく、

  1. AWS Lambdaで関数を「一から作成」
  2. gnugo.zipをアップロード
  3. メモリを3GBに増設
  4. トリガーにAPI Gatewayを追加 (API GatewayREST APIを提供するサービスです。デフォルト29秒でタイムアウトします)
  5. APIを設定

以上です

使い方

作ったREST APIに、以下のようなJSONをpostしてください。

{
    "move": "est",
    "method": "aftermath",
    "sgf": "(;FF[4]...)"
}

成功するとレスポンスのbodyに、

{
    "stdout": "...",
    "stderr": "..."
}

というJSONが返されます。

Happy Go programming!

iOSアプリのシンプルなプライバシーポリシー

この度、iOSアプリを一つ申請し承認いただきました。(契約関係でトラブっていてまだApp Storeには掲載されていません)
6年ぶりのiOSアプリ申請で色々新鮮でした。
中でもすべてのアプリにプライバシーポリシーURLの掲載を求められたことがびっくりしました。
(ニュースで話題になったのかも知れませんが当時iOSアプリを出す予定はなく気にしていませんでした)
ネットをググればプライバシージェネレータなるものも多数あり、やってみましたが、個人情報を全く収集しなくても結構なボリュームになります。
今回、アプリのローカリゼーションを行ったこともあってできるだけ短い記述で済ませたいと思い自分で書きました。
以下がそのページです。

https://new3rs.github.io/a_master_of_go/privacy_policy.html

一言語で7行程度です。
法律的にどうなのかはわかりませんが、少なくともこれでApp Storeの申請は通りました。
ご参考に。

クラウドでLeela Zeroを動かしてローカルのLizzieで見る

以前、VPSサービスGPUEaterでLeela ZeroとLizzie動かす方法を紹介しました。

nextliteracy.hatenablog.com

VPSVNCで繋いて、VPS側でLizzieを動かす方法でしたが、この方法だとVPS側にデスクトップ関連のインストールする必要があってその時間が比較的長く、サクッと使ってみる気にはなれないものでした。

今回は、ローカル(自分のパソコン)でLizzieを動かして、Leela ZeroはVPSサービスで動かす方法を紹介します。元ネタは以下のイシューです。

github.com

VPSサービスとしてGPUEaterを例にしますが、sshでつながるVPSならどれでも同じだと思います。

手順

GPUEaterでアカウントを作る。

省略^^:

インスタンスを生成する。

省略^^:

SSHで接続してインストール作業をする。

SSH接続手順は省略^^;

Leela Zeroをインストールする。

シェルから以下を順に実行してください。スクリプトにして一括実行するのもいいかと思います。おおよそ2分30秒です。
最後のwgetは私のDropboxに置いてあるELF OpenGo v1ウェイトです。お好きなものを用意してください。

apt update
git clone -b next http://github.com/gcp/leela-zero.git
cd leela-zero
git submodule update --init --recursive
apt install -y libboost-dev libboost-program-options-dev libboost-filesystem-dev opencl-headers ocl-icd-libopencl1 ocl-icd-opencl-dev zlib1g-dev
mkdir build && cd build
cmake ..
cmake --build .
wget https://www.dropbox.com/s/qxd2bu0xb59lb5f/elf_converted_weights.txt.gz

次に以下を実行して、OpenCL最適化を終わらせておきます。

cd
leela-zero/build/leelaz --weights leela-zero/build/elf_converted_weights.txt.gz --gtp
Setting max tree size to 4136 MiB and cache size to 459 MiB.

という感じのメッセージで止まったら終了してください。

以上でサーバ準備完了です。VPSインスタンスの起動を含めても5分かからないはずです。

ローカルのLizzieの設定ファイルを変更する。

(普通ローカル環境も維持したいかと思いますので、変更するよりはもう一式Lizzieをインストールしてから設定することをおすすめします)
以下のように、engine-commandプロパティを変更してください。

{
  "leelaz": {
    "automatically-download-latest-network": そのまま,
    "max-analyze-time-minutes": そのまま,
    "analyze-update-interval-centisec": そのまま,
    "network-file": そのまま,
    "max-game-thinking-time-seconds": そのまま,
    "engine-start-location": そのまま,
    "engine-command": "ssh -i ~/.ssh/gpueater.pem root@<IPアドレス> leela-zero/build/leelaz --weights leela-zero/build/elf_converted_weights.txt.gz --gtp --lagbuffer 0 --threads 3",
    "print-comms": そのまま
  },

~.ssh/gpueater.pemはご利用のVPSsshに合わせて変更してください。
<IPアドレス>はご利用のVPSインスタンスIPアドレスです。
--weightsはもしLeela Zeroのインストールの際に違うウェイトをダウンロードしたならそれに合わせてください。
--threadsはご利用のVPSインスタンスの性能に合わせて変えてください。

ダミーのファイルを作る

engine.start-locationとengine-commandの--weightsオプションを組み合わせたファイルを用意してください。空のファイルで結構です。
(Lizzieがウェイトファイルが存在するか確認するので、それを誤魔化すために作ります)

お疲れ様でした。以上で設定完了です。いつものようにLizzieを起動してください。VPS上のLeela ZeroをLizzieで使うことができます。

20万円近くする高性能パソコンを買わなくても、GPUEaterなら1時間50円程度で高性能パソコンと同等にLizzieを使うことができます。

対局場控室で、持ち込みのノートPCは非力とお嘆きの解説の先生がた!、この方法ならノートPCでもいくらでも高性能Lizzieになりますよ!

Enjoy!

Leela ZeroのウェイトをCore MLで計算させる

AZ.jsをSwiftに移植しました。

その際に、Leela ZeroのウェイトをCore ML上に移す作業があったのですが、ハマり所があったので、備忘録です。

Leela Zeroのウェイトは、leela-zeroレポジトリのtraining/tfフォルダ以下のスクリプトを使って、TensorFlowに読み込むことができます。なので、後はtfcoremlで.mlmodelに変換すれば完了です。
github.com

以下、ポイントは2点ありました。

  • tfcoremlはテンソルのフォーマットにNHWCしかサポートしていません。レポジトリのtfprocess.pyは(GPU用に)NCHWフォーマットなので、NHWCフォーマットに対応させました。
  • Core MLは、現在、モデルの実装が限定されているようです。無次元+チャンネルの場合バッチあり、2次元+チャンネルの場合バッチなしの2つです。1次元+チャンネルの場合2次元+チャンネルの1次元を要素数1にして代用するようです。なので本当の意味での1次元+チャンネルはサポートされていません。Leela Zeroは1次元+チャンネルを内部でreshapeする構造なのでこのままではCore MLに合わせることはできませんでした。なのでLeela Zeroのモデルを、内部のreshapeを取り払って2次元+チャンネルの入力に変更しました。

ELF OpenGo v1のウェイト(20b, 224c)を変換してみたところ、私のiMac(27インチ ,Late 2012, i5)で推論が1回170--220ms程度でした。同じマシンのChrome(webgl)でWebDNN上のものが360ms前後なので倍ぐらいのスピードですか。Core ML(tfcoreml?)は量子化をしているようで出力の数字が荒っぽくなります。