Ray を Raspberry Pi で使う

分散アプリケーション向け Python ライブラリの [Ray](https://docs.ray.io/en/latest/index.html) を使ってみたくなり、インストールしました。

```bash
$ pip install -U ray
```

普通はこれで終わりですが、遊休の Raspberry Pi で動かしたいと思ったものだから一苦労でした。[See also](https://discuss.ray.io/t/ray-for-rapberry-pi-is-possible/451)

# スワップ領域を増やす

Raspberry Pi 向けにビルドされた ray のパッケージはありませんので、自分でビルドする必要があります。私が使ったのは Raspberry Pi 3 Model B+ なので、メモリが1Gしかありません。ビルドでメモリが足りなくなるので、[swap領域を増やします](https://qiita.com/nyas/items/f4d0675061ee8cdcc3e7)。2048 に設定しました。

```bash
$ uname -a
Linux ray1 5.10.17-v7+ #1403 SMP Mon Feb 22 11:29:51 GMT 2021 armv7l GNU/Linux
$ cat /proc/device-tree/model
Raspberry Pi 3 Model B Plus Rev 1.3
$ python3 --version
Python 3.7.3
$ swapon -s
Filename				Type		Size	Used	Priority
/var/swap                              	file    	2097148	1658320	-2
```

# Bazel をインストールする

ray のビルドに bazel が必要なのでインストールします。これもソースからビルドが必要らしく、尚且つ、ひと手間(と時間)かかります。

```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libatlas-base-dev libatomic-ops-dev
```

https://github.com/koenvervloesem/bazel-on-arm を使うと、ビルドに必要なパッチをやってくれるので便利でした。

```bash
git clone https://github.com/koenvervloesem/bazel-on-arm.git
cd bazel-on-arm
sudo make requirements
export BAZEL_JAVAC_OPTS="-J-Xmx512m"
make bazel
sudo make install
```

無事にインストールできました。

```bash
bazel version

Extracting Bazel installation...
Build label: 4.0.0- (@non-git)
Build target: bazel-out/arm-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar
Build time: 火 4月 6 03:57:30 2021 (1617681450)
Build timestamp: 1617681450
Build timestamp as int: 1617681450
```

# Ray のビルド

ようやく Ray のビルドができます。

```bash
git clone -b releases/1.2.0 https://github.com/ray-project/ray.git --single-branch
```

[このページ](https://github.com/PeterPirog/Raspberry_armv7_builds/blob/main/ray/How_to_build.txt)を参考にいろいろやりました。以下の変更を加えてビルドが通りました。

```bash
$ git diff
diff --git a/bazel/ray_deps_setup.bzl b/bazel/ray_deps_setup.bzl
index c398dd15d..f613b0fb6 100644
--- a/bazel/ray_deps_setup.bzl
+++ b/bazel/ray_deps_setup.bzl
@@ -243,6 +243,12 @@ def ray_deps_setup():
         sha256 = "781fa39693ec2984c71213cd633e9f6589eaaed75e3a9ac413237edec96fd3b9",
     )

+    http_archive(
+        name = "com_google_protobuf",
+        strip_prefix = "protobuf-3.15.6",
+        urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.15.6.tar.gz"],
+    )
+
     auto_http_archive(
         name = "rules_proto_grpc",
         url = "https://github.com/rules-proto-grpc/rules_proto_grpc/archive/a74fef39c5fe636580083545f76d1eab74f6450d.tar.gz",
diff --git a/python/setup.py b/python/setup.py
index a1542a7a2..b06456814 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -292,7 +292,8 @@ def build(build_python, build_java):
     bazel_targets += ["//java:ray_java_pkg"] if build_java else []
     return bazel_invoke(
         subprocess.check_call,
-        ["build", "--verbose_failures", "--"] + bazel_targets,
+#        ["build", "--verbose_failures", "--"] + bazel_targets,
+        ["build", "--action_env=LD_LIBRARY_PATH", "--linkopt=-latomic", "--"] + bazel_targets,
         env=bazel_env)


diff --git a/src/ray/common/ray_config_def.h b/src/ray/common/ray_config_def.h
index d06a1c358..6e574fcc8 100644
--- a/src/ray/common/ray_config_def.h
+++ b/src/ray/common/ray_config_def.h
@@ -197,7 +197,7 @@ RAY_CONFIG(uint64_t, object_manager_default_chunk_size, 5 * 1024 * 1024)

 /// The maximum number of outbound bytes to allow to be outstanding. This avoids
 /// excessive memory usage during object broadcast to many receivers.
-RAY_CONFIG(uint64_t, object_manager_max_bytes_in_flight, 2L * 1024 * 1024 * 1024)
+RAY_CONFIG(uint64_t, object_manager_max_bytes_in_flight, 2ULL * 1024 * 1024 * 1024)

 /// Maximum number of ids in one batch to send to GCS to delete keys.
 RAY_CONFIG(uint32_t, maximum_gcs_deletion_batch_size, 1000)
```

dashboard をビルドします。

```bash
cd python/ray/new_dashboard/client
export NODE_OPTIONS="--max-old-space-size=1024"
npm install
npm ci
npm run build
```

ray をビルドします。とてつもなく時間がかかります。夜寝る前にスタートして、朝起きたら出来てるくらい。気長に待とう。

```bash
export LD_LIBRARY_PATH=/usr/lib/arm-linux-gnueabihf:$LD_LIBRARY_PATH
bazel build --action_env=LD_LIBRARY_PATH --linkopt=-latomic -c opt //:ray_pkg
```

wheelの作成。

```bash
cd python
python3 setup.py bdist_wheel
```

dist にある whl ファイルを使ってインストール。

```bash
pip3 install ray-1.2.0-cp37-cp37m-linux_armv7l.whl
```

# Tensorflow をインストール

tensorflow も使いたいのでビルドします。こちらはパソコンで[クロスコンパイル](https://www.tensorflow.org/install/source_rpi?hl=ja)しました。

ray もこんな風にクロスコンパイルできたらいいのにな。

# Ray cluster on Raspberry Pi

ray, tensorflow をインストールした Raspberry Pi の SD カードをコピーして、それぞれ ray0, ray1, ray2 と名付けて3台の Raspberry Pi を起動します。

まず ray0 で head node を起動します。

```bash:ray0
ray start --head --port=6379 --dashboard-host 0.0.0.0
```

ray1, ray2 は、ray0 へ接続します。

```bash:ray1,ray2
ray start --address='192.168.0.13:6379' --redis-password='5241590000000000'
```
クラスターの状態を確認します。

```bash:ray0
ray status
======== Cluster status: 2021-04-11 13:55:59.022854 ========
Node status
------------------------------------------------------------
 1 node(s) with resources: {'CPU': 4.0, 'node:192.168.0.13': 1.0, 'object_store_memory': 3.0, 'memory': 10.0}
 1 node(s) with resources: {'object_store_memory': 3.0, 'node:192.168.0.8': 1.0, 'memory': 12.0, 'CPU': 4.0}
 1 node(s) with resources: {'object_store_memory': 3.0, 'node:192.168.0.10': 1.0, 'memory': 12.0, 'CPU': 4.0}

Resources
------------------------------------------------------------
Usage:
 0.0/12.0 CPU
 0.00/1.660 GiB memory
 0.00/0.439 GiB object_store_memory

Demands:
 (no resource demands)
```

ダッシュボードを確認しましょう。私の環境では `http://192.168.0.13:8265/`
![スクリーンショット 2021-04-11 14.02.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/40f54cc1-5910-0953-f6f4-b2527e7ace29.png)

# RLlib で分散強化学習

RLlib を使って、クラスター上で強化学習を動かしてみましょう。

```python:ray0
import ray
from ray import tune
from ray.rllib.agents.dqn import DQNTrainer

ray.init(address='auto')
tune.run(DQNTrainer, config={"env": "CartPole-v0", "num_workers": 11})
```
![スクリーンショット 2021-04-11 14.09.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/8f46cffa-27b5-3cc9-e1f4-372fb78a67bb.png)

![スクリーンショット 2021-04-11 14.09.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/53dd0448-68e2-7b65-9042-437ef12e0cbc.png)

tensorboard で確認。

```bash
tensorboard --logdir=DQN_2021-04-11_14-06-02 --bind_all
```
![スクリーンショット 2021-04-11 14.11.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42252/9df20fad-4926-4a04-7618-df65faa6df04.png)


ラズパイの Ray クラスターが、実用的な性能とは思えませんが、Ray の学習用として使おうと思います。