RaspberryPiをMLflowサーバーにして実験管理する．

# はじめに

### モチベ
MLflowサーバーをラズパイ上に構築して，複数のPCの実験結果を1か所にまとめて管理したい．

### 構成
* 機械学習の実験環境: Ubuntu24.04 on WSL2
* MLflow サーバー： RaspberryPi 4 (RAM 4GB)

### version情報
* python=3.9.13
* mlflow=2.14.3
* PostgreSQL=15.7

# Raspberry Pi（MLflowサーバー）のsetup
### 1. ローカルIPアドレスの確認
まずは，ローカルIPアドレスを確認します．
```bash
 $ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether d8:3a:dd:78:0d:f4 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.18/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 240d:1a:cbd:f00:da3a:ddff:fe78:df4/64 scope global dynamic mngtmpaddr
       valid_lft 86132sec preferred_lft 86132sec
    inet6 fe80::da3a:ddff:fe78:df4/64 scope link
       valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether d8:3a:dd:78:0d:f6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.20/24 brd 192.168.1.255 scope global dynamic noprefixroute wlan0
       valid_lft 71853sec preferred_lft 71853sec
    inet6 240d:1a:cbd:f00:fa80:3bd7:e1f4:ab82/64 scope global dynamic noprefixroute
       valid_lft 86133sec preferred_lft 86133sec
    inet6 fe80::f4f9:cad8:4c71:4f8f/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
```
私の場合は`192.168.1.18`でした．

### 2. ローカルIPアドレスの固定
これは面倒な人はスキップして構いません．
`sudo vim /etc/network/interfaces`
して以下を追記してください．
覚えやすくするため，私はローカルIPを`192.168.1.100`に固定することにしました．
```
auto ethO

iface eth0 inet static
address 192.168.1.100 
network 192.168.1.1
netmask 255.255.255.0
broadcast 192.168.1.255
gateway 192.168.1.1
dns—nameservers 192.168.1.1
```

### 3. PostgreSQLのsetup
まずはPostgreSQLのインストールと起動を行います．
```bash
sudo apt install postgresql postgresql-contrib -y
sudo systemctl start postgresql
sudo systemctl enable postgresql
```
続いてPostgreSQLの設定を変更します．
* `sudo vim /etc/postgresql/15/main/postgresql.conf` で，`listen_addresses = "*"`と書き換えてください．
* `sudo vim /etc/postgresql/15/main/pg_hba.conf` で，ファイルの最後に`host    all             all             0.0.0.0/0               md5`と追記してください．
設定を反映させるためPostgreSQLの再起動をします．
```bash
sudo systemctl restart postgresql
```
### 4. PostgreSQLにユーザとDBを作成
権威ユーザのpostgresでPostgreSQLにアクセスします．
```bash
sudo -u postgres psql
```
以下の設定で作成します．
DB名，ユーザ，パスワードは任意に変更してください．
* DB名: mlflow_db
* ユーザ: mlflow_user
* パスワード: passML
```sql
-- データベースの作成
CREATE DATABASE mlflow_db;

-- ユーザーの作成
CREATE USER mlflow_user WITH PASSWORD 'passML';

-- ユーザーにデータベースへの権限を付与
GRANT ALL PRIVILEGES ON DATABASE mlflow_db TO mlflow_user;
GRANT USAGE ON SCHEMA public TO mlflow_user;
GRANT CREATE ON SCHEMA public TO mlflow_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO mlflow_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO mlflow_user;
GRANT ALL PRIVILEGES ON DATABASE mlflow_db TO mlflow_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO mlflow_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO mlflow_user;
```


### 5. MLflowのsetup
以下のライブラリをインストールする．
```bash
pip install mlflow psycopg2-binary
```
以下コマンドを実行してMLflowサーバーを起動させる．
```bash
mlflow server \
  --backend-store-uri postgresql://mlflow_user:passML@192.168.1.100:5432/mlflow_db \
  --host 192.168.1.100 \
  --port 5000
```

### 6. ファイアウォールの設定
外部から接続するためにポートを開放する．
PostgreSQL用の5432ポートと，MLflow用の5000ポートです．
```bash
sudo ufw enable
sudo ufw allow 5432
sudo ufw allow 5000
sudo ufw reload
```
※ Raspberry Piにsshで接続している人は22も開けておきましょう．


# 実験用PCでのMLflowサーバーの動作確認
以下のようなpythonスクリプトでMLflowの動作を確認してください．
```python
import mlflow

mlflow.set_tracking_uri("http://192.168.1.100:5000")

with mlflow.start_run():
    mlflow.log_param("param1", 5)
    mlflow.log_metric("metric1", 0.85)
```

その後，ブラウザで`http://192.168.1.100:5000`にアクセスできれば完了です．