Azure で Leela Zero を動かす手順

[「囲碁AIブームに乗って、若手棋士の間で「AWS」が大流行　その理由とは？」](https://www.itmedia.co.jp/enterprise/articles/1902/22/news006.html)という記事を読みました。プロ棋士達がAWSのGPUインスタンスを使って囲碁AIを動かして研鑽のために使用しているということで、凄い時代が来たものだと感じました。

さて、記事ではAWSでは既に棋士達の間で共有される囲碁AIソフトウェアのインストール手順があるとあります。調べてみるとGCPについても[導入手順を詳しく説明する記事](https://qiita.com/miuraken/items/e151785bc1e7f1404035)がありました。

……Azureは？

……パブリッククラウドサービスの世界シェア、第2位[^1]であるところのAzureは？

# AzureにLeela Zeroを導入する

Azureも使ってねという気持ちを込めて、Azureを使って囲碁AIソフトウェア「Leela Zero」を動かす手順を紹介します。
とはいっても手順の大筋は先程も紹介した@miuraken氏による[「Leela Zero を GCE で動かす」](https://qiita.com/miuraken/items/e151785bc1e7f1404035)と大きな違いはありません。異なる点はインスタンスの作り方とbatファイルの細部ぐらいです。

今回は手元のWindows PCでLeela Zeroのインターフェースを提供するLizzieを動かし、Azure上のGPUインスタンスで動くLeela Zeroに接続するように設定していきます。

## 準備するもの
- Azureのサブスクリプション
- Windows 10（1803）がインストールされたPC

Windows 10のApril 2018 Update（1803）からOpenSSHが正式に組み込まれました。これにより特別に何かインストールすることもなくSSHコマンドを使用できるようになります。ということで、Windows 10の1803以降を推奨バージョンとします。

## GPU搭載インスタンスの用意
AzureでGPUを搭載した仮想マシンを立てます。

### 事前準備：SSH公開鍵の作成

SSHにはパスワード認証と公開鍵認証がありますが、セキュリティの観点だけでなく今後の動作の都合で今回は公開鍵認証が必須です。

Windowsでコマンドプロンプトを開いて、SSHの鍵を作ります。

```
ssh-keygen
```

色々と聞いてきますが、全てそのままエンターを押して進めていきます。パスフレーズも空のままにしておいてください。セキュリティの観点からは駄目ですが、今回は動作の都合でパスフレーズを設定するとうまくいかなかったので苦肉の策です。

最終的には C:\Users\<username>\.ssh に id_rsa と id_rsa.pub という2つのファイルが出力されます。

id_rsa が秘密鍵というもので、その名の通り絶対秘密にしてください。id_rsa.pub は公開鍵ですから秘密にしなくても問題ありません。

### GPUインスタンスの作成

Azure Portalを開き、左のメニューから「リソースの作成」をクリックします。

![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/359618/9b7b23f6-9a8a-4b51-7267-9fefcb94b6f5.jpeg)

検索窓に「data science」と入力し、Data Science Virtual Machine for Linux (Ubuntu) を探します。2つ表示されますが、僕は（分析）となっている方を選択しました。（多分どっちでも大丈夫ですが未確認です）

作成をクリックし、VMの作成を開始します。

![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/359618/fe0d9ce4-3efb-0bd8-855d-7aa23abec782.jpeg)

リソースグループは新規作成するか、既存のリソースグループを選択してください。

今回はリソースグループ名を leelazero、仮想マシン名を leelazero-vm としました。

AzureにおけるGPUインスタンスは[Nシリーズ](https://azure.microsoft.com/ja-jp/pricing/details/virtual-machines/linux/#n-series)です。今回はTesla V100を搭載したNC6 v3を使います。

都合により記事中では米国東部リージョンを選択していますが、日本から最も近いNC6 v3が使えるリージョンは東南アジアリージョンですので、通信速度の観点からこちらを使うことを推奨します。

地域を選択した後、「サイズを変更します」をクリックしてNC6s_v3を探し、クリックして選択します。

管理者アカウントですが、最終的には公開鍵認証にしますが面倒を避けるために最初はパスワードにしておきます。好きなユーザー名とパスワードを入力します。パスワードはできるだけ強固なものを推奨します。

他の設定は変更する必要がないので、「確認および作成」をクリックし、「作成」を押してインスタンスをデプロイします。5分程度で完了します。

![3.jpg](https://qiita-image-store.s3.amazonaws.com/0/359618/ae5d0f5d-b158-e764-9d83-c3a1a066cd19.jpeg)

GPUインスタンスは利用料が比較的高額なため、サブスクリプションによっては利用が制限されて立てられない状態になっているかもしれません。もし制限に引っかかって立てられない場合は、[「Resource Manager の vCPU クォータを増やす要求」](https://docs.microsoft.com/ja-jp/azure/azure-supportability/resource-manager-core-quotas-request)を参考にMicrosoftに申請を出してください。申請通過まで、早ければ数分、遅いと日の単位でかかります。

### ネットワーク周りの設定

このままの設定だとIPアドレスが変動してしまい、接続先の指定を都度更新する必要が生じます。面倒ですのでDNS名を設定し、以後名前で接続できるようにします。

「DNS名：構成」と表示されているはずですので、「構成」をクリックして設定画面に入ります。

DNS名ラベル（オプション）に名前を入力します。今回は leelazero-vm と入力し、保存をクリックして設定を有効にしました。

![4.jpg](https://qiita-image-store.s3.amazonaws.com/0/359618/42c95cf6-8e63-182b-dfc1-81bb075081c7.jpeg)

「DNS名：leelazero-vm.eastus.cloudapp.azure.com」と表示が変わります。以後この名前を使ってインスタンスに接続します。

## Leela Zero のインストール

コマンドプロンプトを開き、以下のコマンドでインスタンスに接続します。

```
ssh <インスタンス作成時に設定したユーザー名>@leelazero-vm.eastus.cloudapp.azure.com
```

何かごちゃごちゃと出てきますが、Yesと入力するとパスワードを求められます。インスタンス作成時に設定したパスワードを入力し、ログインします。

ログイン後、以下のコマンドを実行します。

```
sudo apt install clinfo && clinfo && sudo apt install -y libboost-dev libboost-program-options-dev libboost-filesystem-dev opencl-headers ocl-icd-libopencl1 ocl-icd-opencl-dev zlib1g-dev libqt5core5a cmake && git clone https://github.com/gcp/leela-zero && cd leela-zero&&git submodule update --init --recursive&&mkdir build && cd build && cmake .. && cmake --build . && ./tests
```

このコマンドは@miuraken氏の[「Leela Zero を GCE で動かす 〜 その２ Leela Zero インストール編」](https://qiita.com/miuraken/items/0f9003e0161f8921ef61)からそのまま利用させて貰いました。記事ではこのコマンドの内容も説明されているので、気になる方は@miuraken氏の記事を参照してください。

しばらく色々と画面が変わり、最後に

```
 [  PASSED  ] 11 tests. 
```

と表示されれば成功です。

続いて以下のコマンドで学習済みモデルをダウンロードします。

```
curl https://zero.sjeng.org/best-network > ~/.local/share/leela-zero/best-network
```

以下のコマンドで実行できます。満足したらCtrl+Cで停止してください。

```
~/leela-zero/build/leelaz
```

### 公開鍵の転送と公開鍵認証の有効化

#### 公開鍵の転送

インスタンスに id_rsa.pub を転送します。転送にはコマンドを使ってもいいですが、WinSCPがWindowsユーザーの場合は直感的で良いかと思いますのでここではWinSCPを利用します。（Microsoft Store版は有料ですがインストール版は無料です）

ホスト名には先程DNS名の所に表示されていたアドレスを入力し、設定したユーザー名とパスワードでログインします。

![5.jpg](https://qiita-image-store.s3.amazonaws.com/0/359618/49aadc6e-abec-b8a2-dd83-5a985174c714.jpeg)

左側にローカルのWindowsの、右側が接続先のUbuntuのディレクトリが表示されています。

左側のWindowsのディレクトリを、「C:\Users\<username>\.ssh」まで辿っていき、id_rsa.pub をクリックして選択状態にした上で、アップロードをクリックして転送します。


#### 公開鍵認証の有効化

インスタンスに接続状態のコマンドプロンプトに戻ります。もし閉じてしまった場合は

```
ssh <インスタンス作成時に設定したユーザー名>@leelazero-vm.eastus.cloudapp.azure.com
```

で再接続します。

下記のコマンドを実行して公開鍵を登録します。

```
cat id_rsa.pub >> .ssh/authorized_keys
```

続いてSSHのパスワード認証を無効化します。

```
sudo vi /etc/ssh/sshd_config
```

```bash:変更前
PasswordAuthentication yes
```


```bash:変更後
PasswordAuthentication no
```

viによるテキスト編集に馴染みが無い人場合は、次の手順で編集してください。

1. キーボードの「i」を押下
2. 矢印キーを使って「PasswordAuthentication」の行にカーソルを移動
3. Back Spaceで「PasswordAuthentication」の後の「yes」を消し、代わりに「no」と入力
4.「Esc」を押下した後、「:wq」と入力してエンターを押下

一度SSH接続を切った後、再接続してみます。

```
exit
```

```
ssh <インスタンス作成時に設定したユーザー名>@leelazero-vm.eastus.cloudapp.azure.com
```

パスワードを入力せず接続できれば、公開鍵による認証がうまくいっています。

## Lizzieのインストール

Windows PCにLeela ZeroのインターフェースであるLizzieをインストールします。

事前にコマンドプロンプトで

```
java -version
```

と入力してJavaがインストールされているか確認します。バージョンが1.8より上であればOKですが、もし何も表示されないようならhttps://java.com/ja/download/win10.jspからJavaをダウンロード&インストールします。

GithubからLizzieをダウンロードします。GPUでもCPUでもどっちでも構いませんが、今回はLizzie.0.6.Windows.x64.CPU.zipを選びます。

https://github.com/featurecat/lizzie/releases/

ダウンロードした圧縮ファイルを解凍し、フォルダごとCドライブ直下（C:\）に設置します。

## batファイルの作成

C:\Lizzie\leela-zeroフォルダで右クリックして新規作成からテキストドキュメントを選択します。

新規作成したtxtファイルに下記の内容を入れて保存後、ファイル名を leelaz.batに変更します。拡張子が非表示の状態の場合は、拡張子を表示する設定に切り替えてからファイル名を変更してください。

```
@echo off
@set VM_DNS_NAME=leelazero-vm.eastus.cloudapp.azure.com
@set USER_NAME= <設定したユーザー名>

echo connecting to %VM_DNS_NAME%

@echo on 
ssh -l %USER_NAME% %VM_DNS_NAME% "~/leela-zero/build/leelaz -g -b 0"
```

できあがったleelaz.batをダブルクリックで実行して、コマンド画面が表示されてLeela Zeroが動いていれば成功です。

C:\Lizzieのconfig.txtを開き、以下のように変更します。

```bash:変更前
"engine-command": "./leela-zero/leelaz --gtp --lagbuffer 0 --weights %network-file",
```


```bash:変更後
"engine-command": "./leela-zero/leelaz.bat --gtp --lagbuffer 0 --weights %network-file",
```

何をしているかの説明は例によって[@miuraken氏の記事](https://qiita.com/miuraken/items/a910675ef173854dc1ad)が詳しいですが、シンプルに説明するとこの作業で作ったbatファイルはネットの先のLeela ZeroをLizzieに誤認させるためのファイルです。

C:\Lizzieのlizzie.jarをダブルクリックして、Lizzieを起動してみます。1分程度で使用可能な状態になるはずです。

![6.jpg](https://qiita-image-store.s3.amazonaws.com/0/359618/f091fa3f-ef23-e432-b71e-73f7c1d2944a.jpeg)



## 起動バッチと終了バッチの作成

ここまでの作業で既にLizzieは使用可能な状態ですが、裏で動くGPUインスタンスはいちいちAzure Portalにログインして停止する必要があります。（停止しないとめちゃくちゃ課金されます）

ということで、起動と停止をこなすbatファイルを作って、Lizzieの起動と同時にインスタンスを起動し、Lizzieを終了するときはインスタンスも停止するようにします。

### Azure CLIのインストール

コマンドでAzureの操作を可能にするために、Azure CLIをインストールします。Microsoftの公式ページを参考にインストールします。

https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-windows?view=azure-cli-latest

指示に従ってインストール後、コマンドプロンプトを一度閉じてもう一度起動します。

以下のコマンドを入力してAzureにログインします。ブラウザでAzureと紐付いているアカウントでログインするよう求められます。

```
az login
```

インスタンスの一覧を表示します。

```
az vm list
```

jsonの形で表示されているため馴染みがない人は見づらいかと思いますが、このコマンドでインスタンスの停止や開始に必要な情報を始め、様々なインスタンスに関する情報をコマンドでさっと確認することができます。

"name"と"resourceGroup"の値をこの後使いますが、この値はAzure Portalからでも確認できるので、どちらか好きな方で確認してください。


### batファイルの作成

C:\Lizzieに以下の内容でbatファイルを2個作成します。C:\Lizzie\lizzie.jarのショートカットと合わせて、デスクトップに3個のショートカットを並べておくと良いと思います。

--resource-groupはインスタンスを置いたリソースグループの名前です。

```bash:start.bat
az vm start --name leelazero-vm --resource-group leelazero
```

```bash:stop.bat
az vm stop --name leela-main-vm --resource-group leelazero
```

Lizzieを起動するときはまず事前にstart.batのショートカットをダブルクリックします。Azure CLIコマンドでインスタンスが起動します。

少し（1分程度？）待ってからlizzie.jarのショートカットをダブルクリックすればLizzieが起動します。

Lizzieを終了するときは、Lizzieのウィンドウを閉じた後、stop.batのショートカットをダブルクリックします。Azure CLIコマンドがインスタンスを停止させます。

少し面倒ですが、Azure CLIの仕様上単純にインスタンスの起動コマンドとjarの起動コマンドを並べても、そのままだとインスタンスの起動前にLizzieが起動してしまい、LizzieがLeela Zeroとの接続に失敗します。一定時間待機はあまりキレイではないので、今回は分けてしまいました。

batに関してはあまり詳しくないので、この辺りをもっとシンプルにできるような知恵をお持ちの方が居ましたら、是非ご教示願います。

## 最後に

AWSやGCPもいいけど、Azureも使ってね！


[^1]: https://www.srgresearch.com/articles/leading-cloud-providers-increase-their-market-share-again-third-quarter