こんにちは。Optuna Dashboardというものがあると知り、それをDockerで環境構築しながら可視化を試みます。
やりたいこと
★Jupyterlab上でOptunaを用い最適化したモデルの学習過程をOptuna Dashboardで可視化するDocker環境を構築すること(GPU使用)
上記を実現しようとすると様々な工程があるので、細かく区切って考えていきます。
完成イメージ
このようなダッシュボードをWEBブラウザ上で見る
流れ
-
Docker関連
- ディレクトリを作成
- GPU環境を構築
- docker compose.ymlの作成
- Dockerfileの作成
- requirement.txtの作成
⇒ コンテナを構築・起動させる
-
学習関連
- データベースを作成
- jupyterlabでoptunaのstudyを作成する
- Optuna dashboardに接続
⇒ ダッシュボード完成!
Docker関連
ディレクトリを作成
このディレクトリがDocker Composeのプロジェクト名に使われます。このプロジェクト名によって、個々の環境が分離されますので、なんのコンテナか分かりやすく作ります。今後作るファイルはこのディレクトリに保存します。
project/
├── docker-compose.yaml
├── Dockerfile
├── requirements.txt
└── data/
GPU環境を作成
私はこのサイトを見ながら行い、無事コンテナ内にCUDA 12.1がインストールするところまでできました。
https://highreso.jp/edgehub/machinelearning/ubuntudocker.html#index_id5
docker compose.ymlの作成
コンテナを作成するには、どういうコンテナを作成するのかYAML(ヤムル)形式のファイルで定義します。
今回は以下4つのサービスを構築していきます。
- jupyterlab:機械学習のコードを書いて実行する開発環境
- PostgreSQL:Optunaの試行データを保存するデータベース
- pgAdmin:PostgreSQLを視覚的に管理するためのGUI
- Optuna Dashboard:Optunaの試行結果を可視化するためのウェブインターフェース
services:
gpu-container:
container_name: XX-gpu-container
build:
context: .
dockerfile: Dockerfile
runtime: nvidia
environment:
- NDIVIA_VISIBLE_DEVICES-all
- NDIVIA_DRIVER_CAPABILITIES=compute,utility
- JUPYTER_ENABLE_LAB=yes
restart: unless-stopped
stdin_open: true
tty: true
ports:
- "XXXX:8888" # JupyterLab
# Dockerコンテナとホストマシン(ローカルPC)の間でディレクトリを共有する設定
volumes:
- ./notebooks:/home/jovyan/notebooks
command: >
jupyter lab --allow-root --ip=0.0.0.0 --port=8888 --NotebookApp.token=''
networks:
- XX-network
postgres:
image: postgres:17-bullseye #イメージからコンテナを作成
container_name: XX-postgres
environment:
POSTGRES_USER: optuna_user
POSTGRES_PASSWORD: optuna_password
POSTGRES_DB: optuna_db
ports:
- "XXXX:5432" # 外部ポート XXXX -> 内部ポート 5432
volumes:
- postgres_data:/var/lib/postgresql/data # データを永続化するため
restart: always
networks:
- XX-network
pgadmin:
image: dpage/pgadmin4 # イメージからコンテナを作成
container_name: XX-pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: XXXXXXXX@XXXX.com # pgAdmin のログイン用メールアドレス(任意)
PGADMIN_DEFAULT_PASSWORD: XXXX # pgAdmin のログイン用パスワード(任意)
ports:
- "XXXX:80" # 外部ポート XXXX -> 内部ポート 80
depends_on:
- postgres # PostgreSQLサービスが起動していることを前提に動作
restart: always
networks:
- XX-network
optuna_dashboard:
image: ghcr.io/optuna/optuna-dashboard # イメージからコンテナを作成
container_name: XX-optuna_dashboard
ports:
- "XXXX:8080" # 外部ポート XXXX -> 内部ポート 8080
depends_on:
- postgres
restart: always
networks:
- XX-network
volumes:
postgres_data: # ホストにデータを保存
networks:
XX-network:
driver: bridge
コンテナ名とポート番号(外部)は任意です。今回はXXとして記載しているので適宜ご変更ください。
構成はこんな感じです。
services:
jupyter: # コンテナ名
image: # イメージ名
port: # ポート番号
environment: # 環境変数の設定
depends_on: # コンテナ間の依存関係
restart: # コンテナの再起動の設定
volumes: # コンテナに接続するボリューム
コンテナとは?イメージとは?
- コンテナは独立した実行環境
- イメージはコンテナを作成するための指示が記載された読み取り専用のテンプレート
⇒ 今回は、image
を指定しており、Docker Hub(公式のイメージリポジトリ)やGitHub Container Registry (GHCR)かを参照してダウンロードしています
Dockerfileの作成
# Stage 1: Build stage
# ビルド環境を作成し、必要なすべての依存関係をインストールするステージ
# ベースイメージを指定
FROM nvidia/cuda:12.1.1-base-ubuntu20.04 AS builder
# rootユーザーに切り替え
USER root
# 環境変数を定義
ENV NB_UID=1000
ENV NB_GID=100
ENV HOME=/home/jovyan
# システムパッケージの更新とインストール
RUN apt-get update && apt get install -y --no-install-recommends \
curl \
build-essential \
gcc \
libpq-dev \
python3 \
python3-pip \
python3-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# requirements.txtをコンテナ内にコピー
COPY requirements.txt /tmp/requirements.txt
# Pythonパッケージのインストール
RUN pip install --upgrade pip && \
pip install -r /tmp/requirements.txt && \
pip install jupyterlab && \
rm /tmp/requirements.txt
# $PATHにインストール先を追加
ENV PATH=$PATH:/usr/local/bin/:/root/.local/bin
# CUDA 12.1
RUN pip install torch=2.4.1 torchvision=0.19.1 torchaudio=2.4.1 --index-url https://download.pytorch.org/whl/cu121
# 必要なディレクトリを作成
RUN mkdir -p $HOME/.local/share/jupyter && \
mkdir -p $HOME/notebooks && \
chown -R $NB_UID:$NB_GID $HOME
# Stage 2: Final stage
# 実行環境用の軽量イメージを作成し、不要な開発ツールを排除
# ベースイメージを指定
FROM nvidia/cuda:12.1.1-base-ubuntu20.04
# rootユーザーに切り替え
USER root
# 環境変数を再定義
ENV NB_UID=1000
ENV NB_GID=100
ENV HOME=/home/jovyan
# Stage 1 から必要なファイルをコピー
COPY --from=builder /usr /usr
COPY --from=builder $HOME $HOME
# 作業ディレクトリの作成と所有権の付与
RUN mkdir -p /home/jovyan/notebooks && chown -R $NB_UID:$NB_GID /home/jovyan/notebooks
RUN mkdir -p /home/jovyan/.local/share/jupyter/runtime && \
chown -R $NB_UID:$NB_GID /home/jovyan/.local
# 必要に応じてJupyterのポートを開放
EXPOSE 8888
# デフォルトのユーザーに戻す
USER $NB_UID
# 作業ディレクトリを設定
WORKDIR /home/jovyan/notebooks
# jupyterlabの起動コマンドを設定
CMD ["jupyter". "lab", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root"]
上記は試行錯誤の上、できたコードであり、もっと簡潔に書けたり省略できるところもあると思います。
torch のバージョンによっては 異なる CUDA バージョンが必要になるので確認が必要です。
公式サイト: https://pytorch.org/get-started/previous-versions/
torch のバージョンに対応する CUDA を確認する方法:
python -c "import torch; print(torch.version.cuda)"
requirement.txtの作成
開発環境を管理するために使うライブラリを記載します。
あくまで例となりますので、ご自身が必要なものを入れてください。
numpy==1.26.4
pandas==2.1.4
seaborn==0.13.2
matplotlib==3.5.3
japanize-matplotlib==1.1.3
scikit-learn==1.5.2
sqlalchemy==2.0.37
psycopg2-binary==2.9.10
optuna==4.1.0
optuna-dashboard==0.17.0
ipywidgets==8.0.7
※ psycopg2もしくはpsycopg2-binaryのインストールは必ず必要です!
-
psycopg2 ⇒ 本番環境
PythonでPostgreSQLデータベースと接続するためのライブラリ。
SQLクエリの実行やデータベースの操作を簡単に行える。 -
psycopg2-binary ⇒ 開発環境
psycopg2 のバイナリパッケージ版。
ビルド済みのC拡張モジュールが含まれているため、依存ライブラリやコンパイルが不要で簡単にインストールできる。
コンテナを構築・起動させる
下準備ができました。
ここから、imageを実際に構築していきます。
まずは、ターミナル(Windowsの場合)を開いて、実行環境のディレクトリに移動します。
- コンテナを構築・起動させる
docker-compose up -d --build
今のままではrelation "version_info" does not exist
やFATAL: database "optuna_db" does not exist
などのエラーメッセージが出ると思いますが、次で対応していきます。
学習関連
データベースを作成
今回のoptuna dashboardはデータベースからデータを取ってくるような形になっています。
データベースはコマンドからも作れますが、pdadminにアクセスしてGUI操作をしていきます。
ログイン時はdocker_compose.ymlで指定したメールアドレスとパスワードを入力します。
PGADMIN_DEFAULT_EMAIL: XXXXXXXX@XXXX.com # pgAdmin のログイン用メールアドレス(任意)
PGADMIN_DEFAULT_PASSWORD: XXXX # pgAdmin のログイン用パスワード(任意)
-
Add New Server
をクリック -
General
タブ -
Conection
タブ- Host name/address:XX-postgres
- Port:5432
- Maintanance database:optuna_db
- Username:optuna_user
- Password:otpuna_password
※上記はDocker compose.ymlに書かれているものです
コマンド操作はこちら
docker exec -it XX-postgres psql -U optuna_user -d postgres
CREATE DATABASE optuna_db;
CREATE USER optuna_user WITH PASSWORD 'optuna_password';
GRANT ALL PRIVILEGES ON DATABASE optuna_db TO optuna_user;
データベースができたら確認してみます。
docker exec -it XX-postgres psql -U optuna_user -d optuna_db
optuna_dbの中に入れたら成功です!
jupyterlabでoptunaのstudyを作成する
まず、データベースに接続するために、先述したpsycopg2をインポートする必要があります。
import psycopg2
これを実行してImportError: libpq.so.5: cannot open shared object file: No such file or directory
になる場合は、portfolio3-jupyterコンテナに入ってから、を手動でインポートします。
docker exec -it --user root portfolio3-jupyter bash
apt-get update && apt-get install -y libpq-dev
ちなみに、ルートユーザーでない場合は権限がないと出力されインストールできませんでした。
docker exec -it XX-jupyter bash
apt-get update && apt-get install -y libpq-dev
# エラー表示
Reading package lists... Done
E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)
では、otpunaのstudyを作り、テーブルを作成します。
これを行わないまま次項に進むと、relation "version_info" does not exist
エラーが発生しました。
import optuna
storage_url = "postgresql+psycopg2://optuna_user:optuna_password@XX-postgres:5432/optuna_db"
study = optuna.create_study(storage=storage_url, study_name="example_study", load_if_exists=True)
print("Optuna storage connected!")
Optuna dashboardに接続
本来Docker compose.ymlのコマンドで指定するべきですが、私はコマンドの記載方法でエラーになってしまったので、ここでは手動でoptuna dashboardを起動させて、PostgreSQLのデータベースに接続します。
docker run -it --rm --network cpu-version_portfolio-network -p XXXX:8080 ghcr.io/optuna/optuna-dashboard postgresql+psycopg2://optuna_user:optuna_password@XX-postgres:5432/optuna_db --port 8080 --host 0.0.0.0
この後、実際にhttp://localhost:XXXX
にアクセスしてみるとこのような画面が出てきます。XXXXはホストのポートであり、ここからコンテナの 8080 に繋がることになります。
では実際に学習させてみましょう。
def objective(trial):
x = trial.suggest_float("x", -100, 100)
y = trial.suggest_categorical("y", [-1, 0, 1])
return x**2 + y
if __name__ == "__main__":
# OptunaのStudyを作成
study = optuna.create_study(
storage=storage_url,
study_name="example_study",
load_if_exists=True # Studyが既に存在する場合はロード
)
study.optimize(objective, n_trials=100)
print(f"Best value: {study.best_value} (params: {study.best_params})")
Best value: -0.7740110290467385 (params: {'x': -0.4753829729315739, 'y': -1})
が出力されました。
optuna dashboardものぞいてみると、きちんと出力されています!
番外編
今回GPUを使用する前提で書きましたが、GPUがないPCを使う場合は、gpu-countainerが必要ありません。
参考までに、CPU版のコードも記載します。コンテナの構成は同様ですが、コンテナの作り方が異なってきます。
Dockerfile
# ベースイメージを指定
FROM jupyter/base-notebook:python-3.11 AS builder
ベースがjupyterになります。
Docker compose.yml
services:
jupyter:
build: # Dockerfile を利用する設定を追加
context: .
dockerfile: Dockerfile
container_name: portfolio3-jupyter
ports:
- "XXXX:8888" # JupyterLab
# Docker コンテナとホストマシン(ローカルPC)の間でディレクトリを共有する設定
volumes:
- ./notebooks:/home/jovyan/work/notebooks
environment:
- JUPYTER_ENABLE_LAB=yes
restart: unless-stopped
command: >
jupyter lab --ip=0.0.0.0 --no-browser --NotebookApp.token='' --NotebookApp.password=''
networks:
- XX-network
以上です、読んでいただきありがとうございました。
参考