aiaccelドキュメント

本ソフトウェアは、AI Bridging Cloud Infrastructure (ABCI)`_ のためのハイパーパラメータ最適化ライブラリです。 ディープラーニングやマルチエージェントシミュレーションなどのAI技術に関連するハイパーパラメータ最適化を解決します。 現在、ランダムサーチ、グリッドサーチ、ソボルシーケンス、ネルダーミード法、TPEの5つの最適化アルゴリズムに対応しています。

aiaccel概要

AI橋渡しクラウドABCI向けハイパーパラメータ最適化ライブラリ。 ランダムサーチ、グリッドサーチ、Sobol列、Nelder-Mead法、およびベイズ最適化法 (TPE)をサポートしています。

クイックインストール

本ソフトウェアは下記コマンドでインストールできます。

pip install git+https://github.com/aistairc/aiaccel.git

実行例

ローカル環境で実行する場合

  1. (オプション) Virtualenvをインストールし、仮想環境を作成します。

    > pip install virtualenv
    > virtualenv venv
    > source venv/bin/activate
    
  2. aiaccelをインストールします

    pip install git+https://github.com/aistairc/aiaccel.git 
    
  3. ワークスペースを作成し、sphereディレクトリをコピーします。

    > mkdir your_workspace_directory
    > cd your_workspace_directory
    > git clone https://github.com/aistairc/aiaccel.git 
    > cp -R ./aiaccel/examples .
    > cd examples
    > ls
    sphere
    
    > cd sphere
    > ls
    config.yaml         job_script_preamble.sh         user.py
    
  4. パラメータ最適化を実行します。

    > python -m aiaccel.start --config config.yaml
    

    Tips: ワークスペースは --clean を付加することで実行前に初期化できます。

    > python -m aiaccel.start --config config.yaml --clean
    
  5. 結果を確認する。

    > ls ./work
    abci_output         alive               hp                  lock
    log                 result              runner              state
    verification
    
    > cat ./work/result/final_result.result
    
  6. 設定を変更したい場合は、config.yamlファイルを編集してください。

    vi config.yaml
    

ABCI上で実行する

  1. まず、ABCIユーザーズガイドに従って、pythonの環境を構築してください。

    module load python/3.8/3.8.13
    python3 -m venv optenv
    source work/bin/activate
    
  2. config.yamlのresourceをABCIに変更します。

    resource:
        type: "ABCI"
        num_node: 4
    
  3. ワークスペースを用意します.ここからの作業は、ローカル環境で実行する場合の2および3と同じです。

  4. 実行

    > python -m aiaccel.start --config config.yaml
    
  5. 実行中のジョブを確認したい場合は、ABCIユーザーズガイドを参照してください。

インストールガイド (WIP)

Linux 向けインストールガイド

Python-venv による仮想環境の作成

venv 環境での使用を推奨いたします. 仮想環境を作成するには,下記のコマンドを実行します.

python3 -m venv optenv

ここでは仮想環境の名前を「optenv」とし,以後も当仮想環境を「optenv」と表記します. 仮想環境の名前は任意の名前を設定できます.

アクティベート

仮想環境を利用するには,下記のコマンドを実行します.

source optenv/bin/activate

以後の作業はアクティベート済みのものとして進めます.

(参考)仮想環境の終了

仮想環境を終了するには,下記のコマンドを実行します.

deactivate

インストール

Note

事前に pip をアップグレードすることを推奨いたします.

python3 -m pip install --upgrade pip

aiaccel は下記コマンドでインストールできます.

python3 -m pip install git+https://github.com/aistairc/aiaccel.git

aiaccel がインポートできることを確認します.

python3
import aiaccel
(参考)ローカルからのインストール

aiaccel をダウンロードし,ローカルからインストールすることもできます.

まず,aiaccel をダウンロードします.

git clone https://github.com/aistairc/aiaccel.git

ダウンロード完了後,aiaccel フォルダに移動します.

cd aiaccel

依存環境をインストールします.

python3 -m pip install -r requirements.txt

setup.py を実行し,aiaccel をインストールします.

python3 setup.py install

ABCI 向けインストールガイド

Python 環境の構築

まず,ABCIユーザーズガイドに従って,python の環境を構築してください.

module load gcc/11.2.0
module load python/3.8/3.8.13
python3 -m venv optenv
source optenv/bin/activate

Python-venv による仮想環境の作成

venv 環境での使用を推奨いたします. 仮想環境を作成するには,下記のコマンドを実行します.

python3 -m venv optenv

ここでは仮想環境の名前を「optenv」とし,以後も当仮想環境を「optenv」と表記します. 仮想環境の名前は任意の名前を設定できます.

アクティベート

仮想環境を利用するには,下記のコマンドを実行します.

source optenv/bin/activate

以後の作業はアクティベート済みのものとして進めます.

(参考)仮想環境の終了

仮想環境を終了するには,下記のコマンドを実行します.

deactivate

インストール

Note

事前に pip をアップグレードすることを推奨いたします.

python3 -m pip install --upgrade pip

aiaccel は下記コマンドでインストールできます.

python3 -m pip install git+https://github.com/aistairc/aiaccel.git

aiaccel がインポートできることを確認します.

python3
import aiaccel
(参考)ローカルからのインストール

aiaccel をダウンロードし,ローカルからインストールすることもできます.

まず,aiaccel をダウンロードします.

git clone https://github.com/aistairc/aiaccel.git

ダウンロード完了後,aiaccel フォルダに移動します.

cd aiaccel

依存環境をインストールします.

python3 -m pip install -r requirements.txt

setup.py を実行し,aiaccel をインストールします.

python3 setup.py install

Windows 向けインストールガイド

準備1: Git のインストール

GitHub 経由で aiaccel をインストールする場合,git がインストールされている必要があります. あらかじめインストールしてください.

準備2: Execution Polisy の設定

PowerShell を使用して仮想環境を作る場合,セキュリティ設定によって仮想環境をアクティベートするスクリプトが実行できないことがあります. 以下の手順でセキュリティ設定を変更することが可能ですが,セキュリティリスクが上がることに十分注意してください.詳細はこちらをご確認ください.

以下のコマンドを実行して,PowerShell の設定を確認します.

> Get-ExecutionPolicy
Restricted

この例のように Restricted と表示された場合,以下のコマンドを実行し,設定を変更します.

> Set-ExecutionPolicy RemoteSigned

実行後,コマンド Get-ExecutionPolicy を実行して,RemoteSigned と表示されれば設定完了です.

> Get-ExecutionPolicy
RemoteSigned

使用中の PowerShell ウィンドウのみに変更を適用したい場合,以下のようにオプションを追加して設定します.

> Set-ExecutionPolicy RemoteSigned -Scope Process

Python-venv による仮想環境の作成

venv 環境での使用を推奨いたします. 仮想環境を作成するには,下記のコマンドを実行します.

> python -m venv optenv

ここでは仮想環境の名前を「optenv」とし,以後も当仮想環境を「optenv」と表記します. 仮想環境の名前は任意の名前を設定できます.

アクティベート

仮想環境を利用するには,下記のコマンドを実行します.

> .\optenv\Scripts\activate

以後の作業はアクティベート済みのものとして進めます.

(参考)仮想環境の終了

仮想環境を終了するには,下記のコマンドを実行します.

deactivate

インストール

Note

事前に pip をアップグレードすることを推奨いたします.

> python -m pip install --upgrade pip

以下のコマンドを実行します.

> python -m pip install git+https://github.com/aistairc/aiaccel.git
(参考)ローカルからのインストール

aiaccel をダウンロードし,ローカルからインストールすることもできます.

まず,aiaccel をダウンロードします.

> git clone https://github.com/aistairc/aiaccel.git

ダウンロード完了後,aiaccel フォルダに移動します.

> cd aiaccel

依存環境をインストールします.

> python -m pip install -r requirements.txt

setup.py を実行し,aiaccel をインストールします.

> python setup.py install

aiaccel がインポートできることを確認します.

> python
>>> import aiaccel
>>>

MacOS 向けインストールガイド (WIP)

作業ファイルの準備

ワークスペースを作成し,移動します.

> mkdir your_workspace_directory
> cd your_workspace_directory

リポジトリのクローンを取得し,ディレクトリ examles のコピーを作成します.

> git clone https://github.com/aistairc/aiaccel.git 
> cp -R your_workspace_directory/aiaccel/examples .

examples 下には以下のフォルダが存在します.

  • benchmark

  • resnet50_cifar10

  • schwefel

  • sphere

  • styblinski-tang

  • wrapper_sample

使用するフォルダに移動して設定を行い, aiaccel を実行します. 例えば sphere に移動するには,以下のようにします.

> cd examples/sphere

ランダムオプティマイザのローカル環境での実行例

ここでは,ランダムオプティマイザをローカルで実行する方法を説明します. 例として,ベンチマーク関数の一つである sphere の最適化を行います.

以下の説明では aiaccel/examples/sphere に保存されているファイルを編集して使用します.

1. ファイル構成

config.yaml

  • 最適化およびソフトウェアの設定ファイルです.

user.py

  • 与えられたパラメータからベンチマーク関数 sphere の値を計算し,aiaccel の Storage に保存するユーザプログラムです.


2. ファイル作成手順

config.yaml の作成

generic
generic:
  workspace: "./work"
  job_command: "python user.py"
  batch_job_timeout: 600
  • workspace - aiaccel の実行に必要な一時ファイルを保存するディレクトリを指定します.

  • job_command - ユーザープログラムを実行するためのコマンドです.

  • batch_job_timeout - ジョブのタイムアウト時間を設定します.[単位: 秒]

Note

Windows では,仮想環境の python で実行するためには job_command の欄を "optenv/Scripts/python.exe" のように設定する必要があります.

resource
resource:
  type: "local"
  num_node: 4
  • type - 実行環境を指定します.ローカル環境で実行するためには "local" で設定します.

  • num_node - 使用するノード数を指定します.

optimize
optimize:
  search_algorithm: 'aiaccel.optimizer.RandomOptimizer'
  goal: "minimize"
  trial_number: 100
  rand_seed: 42
  parameters:
    -
      name: "x1"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: -5.0
    -
      name: "x2"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: -5.0
    -
      name: "x3"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: -5.0
    -
      name: "x4"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: -5.0
    -
      name: "x5"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
  • search_algorithm - 最適化アルゴリズムを設定します.この例ではランダムオプティマイザを設定しています.

  • goal - 最適化の方向を設定します.

    • 関数 sphere を最小化することが目的であるため,"minimize" を設定しています.

  • trial_number - 試行回数を設定します.

  • rand_seed - 乱数の生成に使用するシードを設定します.

  • parameters - ハイパパラメータの各種項目を設定します.ここでは 5 次元の spehre の最適化を行うため,5 種類のパラメータを用意しています.5 つのパラメータに対して,以下の項目をそれぞれ設定する必要があります.パラメータの範囲や初期値を,全て同じにする必要はありません.

    • name - ハイパパラメータの名前を設定します.

    • type - ハイパパラメータのデータ型を設定します.ここでは例として "uniform_float" に設定していますが,ランダムオプティマイザでは,以下の 4 つから選択することができます.

      • uniform_float - 浮動小数点数

      • uniform_int - 整数

      • categorical - カテゴリカル変数

      • ordinal - オーディナル変数

    • lower / upper - ハイパパラメータ最小値 / 最大値を設定します.

    • initial - ハイパパラメータの初期値を設定します.上の例の "x5" の場合のように initial の項目がない場合,実行時にランダムな初期値が自動で設定されます.

user.py の作成

user.py は以下のように記述します.

import numpy as np
from aiaccel.util import aiaccel


def main(p):
    x = np.array([p["x1"], p["x2"], p["x3"], p["x4"], p["x5"]])
    y = np.sum(x ** 2)
    return float(y)


if __name__ == "__main__":
    run = aiaccel.Run()
    run.execute_and_report(main)

モジュール
import numpy as np
from aiaccel.util import aiaccel

必要なモジュールをインポートします.

  • numpy - 関数 sphere を計算するために使用します.

  • aiaccel.util.aiaccel - ユーザープログラム内で定義される関数 main() と aiaccelとの間のインターフェイスを提供します.

main
def main(p):
    x = np.array([p["x1"], p["x2"], p["x3"], p["x4"], p["x5"]])
    y = np.sum(x ** 2)
    return float(y)

最適化対象の関数で,aiaccel はこの関数の return 値を最小化します. 引数にハイパパラメータの辞書型オブジェクトを取り,ハイパパラメータの二乗和を返却します.

実行部分
if __name__ == "__main__":
    run = aiaccel.Run()
    run.execute_and_report(main)

aiaccel から関数 main() にハイパパラメータを渡し,main() の返却値を Storage に保存します. run はそのインターフェイスとなるインスタンスです. メソッド execute_and_report() の内部で main() が値を計算し,Storage に計算結果が保存されます.


3. 実行

作成した config.yaml と user.py が保存されているディレクトリに移動し,下記のコマンドで aiaccel を起動してください.

> aiaccel-start --config config.yaml --clean
  • コマンドラインオプション引数

    • --config - 設定ファイルを読み込むためのオプション引数です.読み込むコンフィグのパスを記述します.

    • --clean - aiaccel の起動ディレクトリ内に config.yaml の workspace で指定したディレクトリが存在する場合,削除してから実行するためのオプション引数です.


4. 結果の確認

aiaccel の正常終了後,最適化の結果は以下の 2 か所に保存されます.

  • ./work/results.csv

  • ./work/result/{trial_id}.hp

ここで,./work はコンフィグファイルの workspace に設定したディレクトリです.

results.csv には,それぞれの試行でのパラメータの値と,そのパラメータに対する目的関数の値が保存されています. result/{trial_id}.hp は,{trial_id} 回目の試行のパラメータと関数の値が YAML 形式で保存されています. さらに,同じフォルダには final_result.result というファイルが作成され,全試行中で最良のパラメータと目的関数の値が YAML 形式で保存されます.

上で実行した最適化の結果は以下のようになります.

  • ハイパパラメータ

    • x1

    • x2

    • x3

    • x4

    • x5

  • 評価値

    • sphere

  • 最適化手法

    • Random

  • 結果比較

    • デフォルトパラメータ

      x1 = -5.0
      x2 = -5.0
      x3 = -5.0
      x4 = -5.0
      x5 = -1.254598811526375 (自動生成)
      
      sphere = 101.57401817788339
      
    • 最適化結果

      x1 = -1.9575775704046228
      x2 =  0.24756431632237863
      x3 = -0.6805498135788426
      x4 = -2.0877085980195806
      x5 =  1.118528947223795
      
      sphere = 9.966180279652084
      

グリッドオプティマイザのローカル環境での実行例

ここでは,グリッドオプティマイザをローカルで実行する方法を説明します. 例として,ベンチマーク関数の一つである Schwefel の最適化を行います.

以下の説明では aiaccel/examples/schwefel に保存されているファイルを編集して使用します.

1. ファイル構成

config.yaml

  • 最適化およびソフトウェアの設定ファイルです.

user.py

  • 与えられたパラメータからベンチマーク関数 Schwefel の値を計算し,aiaccel の Storage に保存するユーザプログラムです.


2. ファイル作成手順

config.yaml の作成

generic
generic:
  workspace: "./work"
  job_command: "python user.py"
  batch_job_timeout: 600
  • workspace - aiaccel の実行に必要な一時ファイルを保存するディレクトリを指定します.

  • job_command - ユーザープログラムを実行するためのコマンドです.

  • batch_job_timeout - ジョブのタイムアウト時間を設定します.[単位: 秒]

Note

Windows では,仮想環境の python で実行するためには job_command の欄を "optenv/Scripts/python.exe" のように設定する必要があります.

resource
resource:
  type: "local"
  num_node: 4
  • type - 実行環境を指定します.ローカル環境で実行するためには "local" で設定します.

  • num_node - 使用するノード数を指定します.

optimize
optimize:
  search_algorithm: 'aiaccel.optimizer.GridOptimizer'
  goal: "minimize"
  trial_number: 30
  rand_seed: 42
  parameters:
    -
      name: "x1"
      type: "uniform_float"
      lower: -500.0
      upper: 500.0
      step: 10
      log: false
      base: 10
    -
      name: "x2"
      type: "uniform_float"
      lower: -500.0
      upper: 500.0
      step: 10
      log: false
      base: 10
    -
      name: "x3"
      type: "uniform_float"
      lower: -500.0
      upper: 500.0
      step: 10
      log: false
      base: 10
    -
      name: "x4"
      type: "uniform_float"
      lower: -500.0
      upper: 500.0
      step: 10
      log: false
      base: 10
    -
      name: "x5"
      type: "uniform_float"
      lower: -500.0
      upper: 500.0
      step: 10
      log: false
      base: 10
  • search_algorithm - 最適化アルゴリズムを設定します.この例ではグリッドオプティマイザを設定しています.

  • goal - 最適化の方向を設定します.

    • 関数 Schwefel を最小化することが目的であるため,"minimize" を設定しています.

  • trial_number - 試行回数を設定します.

  • rand_seed - 乱数の生成に使用するシードを設定します.

  • parameters - ハイパパラメータの各種項目を設定します.ここでは 5 次元の Schwefel の最適化を行うため,5 種類のパラメータを用意しています.5 つのパラメータに対して,以下の項目をそれぞれ設定する必要があります.パラメータの範囲や初期値を,全て同じにする必要はありません.

    • name - ハイパパラメータの名前を設定します.

    • type - ハイパパラメータのデータ型を設定します.ここでは例として "uniform_float" に設定していますが,グリッドオプティマイザでは,以下の 4 つから選択することができます.

      • uniform_float - 浮動小数点数

      • uniform_int - 整数

      • categorical - カテゴリカル変数

      • ordinal - オーディナル変数

    • lower / upper - ハイパパラメータ最小値 / 最大値を設定します.

    • step - パラメータ空間を分割するステップサイズを設定します.

    • log - 対数スケールでパラメータ空間を分割するかを true または false で設定します.

    • base - パラメータ空間を対数スケールで分割する際に使用する基数を設定します.対数スケールでパラメータ空間を分割しない場合は使用されませんが,必ず値を設定してください.設定されていない場合エラーになりまず.

注意: グリッドオプティマイザを使用する際は,パラメータの初期値を設定することができません.

user.py の作成

user.py は以下のように記述します.

import numpy as np
from aiaccel.util import aiaccel


def main(p):
    x = np.array([p["x1"], p["x2"], p["x3"], p["x4"], p["x5"]])
    y = -np.sum(x * np.sin(np.sqrt(np.abs(x))))
    return float(y)


if __name__ == "__main__":
    run = aiaccel.Run()
    run.execute_and_report(main)

モジュール
import numpy as np
from aiaccel.util import aiaccel

必要なモジュールをインポートします.

  • numpy - 関数 Schwefel を計算するために使用します.

  • aiaccel.util.aiaccel - ユーザープログラム内で定義される関数 main() と aiaccelとの間のインターフェイスを提供します.

main
def main(p):
    x = np.array([p["x1"], p["x2"], p["x3"], p["x4"], p["x5"]])
    y = -np.sum(x * np.sin(np.sqrt(np.abs(x))))
    return float(y)

最適化対象の関数で,aiaccel はこの関数の return 値を最小化します. 引数にハイパパラメータの辞書型オブジェクトを取ります, この例では,関数 Schwefel の値を計算し,返却します.

実行部分
if __name__ == "__main__":
    run = aiaccel.Run()
    run.execute_and_report(main)

aiaccel から関数 main() にハイパパラメータを渡し,main() の返却値を Storage に保存します. run はそのインターフェイスとなるインスタンスです. メソッド execute_and_report() の内部で main() が値を計算し,Storage に計算結果が保存されます.


3. 実行

作成した config.yaml と user.py が保存されているディレクトリに移動し,下記のコマンドで aiaccel を起動してください.

> aiaccel-start --config config.yaml --clean
  • コマンドラインオプション引数

    • --config - 設定ファイルを読み込むためのオプション引数です.読み込むコンフィグのパスを記述します.

    • --clean - aiaccel の起動ディレクトリ内に config.yaml の workspace で指定したディレクトリが存在する場合,削除してから実行するためのオプション引数です.


4. 結果の確認

aiaccel の正常終了後,最適化の結果は以下の 2 か所に保存されます.

  • ./work/results.csv

  • ./work/result/{trial_id}.hp

ここで,./work はコンフィグファイルの workspace に設定したディレクトリです.

results.csv には,それぞれの試行でのパラメータの値と,そのパラメータに対する目的関数の値が保存されています. result/{trial_id}.hp は,{trial_id} 回目の試行のパラメータと関数の値が YAML 形式で保存されています. さらに,同じフォルダには final_result.result というファイルが作成され,全試行中で最良のパラメータと目的関数の値が YAML 形式で保存されます.

上で実行した最適化の結果は以下のようになります.

  • ハイパパラメータ

    • x1

    • x2

    • x3

    • x4

    • x5

  • 評価値

    • Schwefel

  • 最適化手法

    • Grid

  • 結果比較

    • 最適化結果

      x1 = -500.0
      x2 = -500.0
      x3 = -500.0
      x4 = -500.0
      x5 = -300.0
      
      results = -1022.0952317469887
      

TPE オプティマイザのローカル環境 (python_local モード) での実行例

ここでは,TPE オプティマイザを python_local モードを用いてローカルで実行する方法を説明します. 例として,ベンチマーク関数の一つである Styblinski-Tang の最適化を行います.

以下の説明では aiaccel/examples/styblinski-tang に保存されているファイルを編集して使用します.

1. ファイル構成

config.yaml

  • 最適化およびソフトウェアの設定ファイルです.

user.py

  • 与えられたパラメータからベンチマーク関数 Styblinski-Tang の値を計算し,aiaccel の Storage に保存するユーザプログラムです.


2. ファイル作成手順

config.yaml の作成

generic
generic:
  workspace: "./work"
  job_command: "python user.py"
  python_file: "./user.py"
  function: "main"
batch_job_timeout: 600
  • workspace - aiaccel の実行に必要な一時ファイルを保存するディレクトリを設定します.

  • job_command - ユーザープログラムを実行するためのコマンドです.python_local モードでは使用されませんが,実行時に読み込むため,記述します.

  • python_file - python で実装された最適化対象の関数のファイルパスを設定します.

  • function - 最適化対象の関数名を設定します.

  • batch_job_timeout - ジョブのタイムアウト時間を設定します.[単位: 秒]

resource
resource:
  type: "python_local"
  num_node: 4
  • type - 実行環境を指定します.python_local モードを使用してローカルで実行するためには "python_local" と設定します.

  • num_node - 使用するノード数を指定します.

optimize
optimize:
  search_algorithm: 'aiaccel.optimizer.TpeOptimizer'
  goal: "minimize"
  trial_number: 30
  rand_seed: 42
  parameters:
    -
      name: "x1"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: 0.0
    -
      name: "x2"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: 0.0
    -
      name: "x3"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: 0.0
    -
      name: "x4"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: 0.0
    -
      name: "x5"
      type: "uniform_float"
      lower: -5.0
      upper: 5.0
      initial: 0.0
  • search_algorithm - 最適化アルゴリズムを設定します.この例では TPE オプティマイザを設定しています.

  • goal - 最適化の方向を設定します.

    • ベンチマーク関数 Styblinski-Tang を最小化することが目的であるため,"minimize" を設定しています.

  • trial_number - 試行回数を設定します.

  • rand_seed - 乱数の生成に使用するシードを設定します.

  • parameters - ハイパパラメータの各種項目を設定します.ここでは 5 次元の Styblinski-Tang の最適化を行うため,5 種類のパラメータを用意しています.5 つのパラメータに対して,以下の項目をそれぞれ設定する必要があります.パラメータの範囲や初期値を,全て同じにする必要はありません.

    • name - ハイパパラメータの名前を設定します.

    • type - ハイパパラメータのデータ型を設定します.ここでは例として "uniform_float" に設定していますが,TPE オプティマイザでは,以下の 3 つのタイプから選択することができます.

      • uniform_float - 浮動小数点数

      • uniform_int - 整数

      • categorical - カテゴリカル変数

    • lower / upper - ハイパパラメータ最小値 / 最大値を設定します.

    • initial - ハイパパラメータの初期値を設定します.

user.py の作成

user.py は以下のように記述します.

import numpy as np


def main(p):
    x = np.array([p["x1"], p["x2"], p["x3"], p["x4"], p["x5"]])
    t1 = np.sum(x ** 4)
    t2 = -16 * np.sum(x ** 2)
    t3 = 5 * np.sum(x)
    y = 0.5 * (t1 + t2 + t3)
    return float(y)

モジュール
import numpy as np

必要なモジュールをインポートします.

  • numpy - 関数 Styblinski-Tang を計算するために使用します.

main
def main(p):
    x = np.array([p["x1"], p["x2"], p["x3"], p["x4"], p["x5"]])
    t1 = np.sum(x ** 4)
    t2 = -16 * np.sum(x ** 2)
    t3 = 5 * np.sum(x)
    y = 0.5 * (t1 + t2 + t3)
    return float(y)

最適化対象の関数で,aiaccel はこの関数の return 値を最小化します. 引数にハイパパラメータの辞書型オブジェクトを取ります. この例では,与えられたパラメータに対してベンチマーク関数 Styblinski-Tang の値を計算し,返却します.

注意

python_local モードで実行する場合,aiaccel は user.py から main() をインポートして使用します. そのため,localabci の場合のように,user.py の内部で aiaccel.util.aiaccel.Run などを用いて関数の実行と Storage への結果の保存を行う必要はありません.


3. 実行

作成した config.yaml と user.py が保存されているディレクトリに移動し,下記のコマンドで aiaccel を起動してください.

> aiaccel-start --config config.yaml --clean
  • コマンドラインオプション引数

    • --config - 設定ファイルを読み込むためのオプション引数です.読み込むコンフィグのパスを記述します.

    • --clean - aiaccel の起動ディレクトリ内に config.yaml の workspace で指定したディレクトリが存在する場合,削除してから実行するためのオプション引数です.


4. 結果の確認

aiaccel の正常終了後,最適化の結果は以下の 2 か所に保存されます.

  • ./work/results.csv

  • ./work/result/{trial_id}.hp

ここで,./work はコンフィグファイルの workspace に設定したディレクトリです.

results.csv には,それぞれの試行でのパラメータの値と,そのパラメータに対する目的関数の値が保存されています. result/{trial_id}.hp は,{trial_id} 回目の試行のパラメータと関数の値が YAML 形式で保存されています. さらに,同じフォルダには final_result.result というファイルが作成され,全試行中で最良のパラメータと目的関数の値が YAML 形式で保存されます.

上で実行した最適化の結果は以下のようになります.

  • ハイパパラメータ

    • x1

    • x2

    • x3

    • x4

    • x5

  • 評価値

    • Styblinski-Tang

  • 最適化手法

    • TPE

  • 結果比較

    • デフォルトパラメータ

      x1 = 0.0
      x2 = 0.0
      x3 = 0.0
      x4 = 0.0
      x5 = 0.0
      
      result = 0.0
      
    • 最適化結果

      x1 = -3.930303675338723
      x2 =  2.640453540706446
      x3 = -2.954080362853035
      x4 = -2.359296335376299
      x5 =  2.690131733893075
      
      result = -138.00660281690844
      

ソボルオプティマイザの ABCI 環境での実行例

ここでは,ソボルオプティマイザを ABCI 環境で実行する方法を説明します.例として,以下 user.py の main() 内で定義されている多項式をベンチマーク関数として最適化を行います.

以下の説明では aiaccel/examples/benchmark に保存されているファイルを編集して使用します.

1. ファイル構成

config.yaml

  • 最適化およびソフトウェアの設定ファイルです.

user.py

  • 与えられたパラメータからベンチマーク関数の値を計算し,aiaccel の Storage に保存するユーザプログラムです.

job_script_preamble.sh

  • ABCI で使用するモジュール指定やジョブ設定を行うためのシェルスクリプトファイルです.


2. ファイル作成手順

config.yaml の作成

generic
generic:
  workspace: "./work"
  job_command: "python user.py"
  batch_job_timeout: 600
  • workspace - aiaccel の実行に必要な一時ファイルを保存するディレクトリを指定します.

  • job_command - ユーザープログラムを実行するためのコマンドです.

  • batch_job_timeout - ジョブのタイムアウト時間を設定します.[単位: 秒]

resource
resource:
  type: "abci"
  num_node: 4
  • type - 実行環境を指定します.ABCI 環境で実行するためには "abci" で設定します.

  • num_node - 使用するノード数を指定します.

ABCI
ABCI:
  group: "[group]"
  job_script_preamble: "./job_script_preamble.sh"
  job_execution_options: ""
  • group - 所属している ABCI グループを指定します.

  • job_script_preamble - ABCI の設定を記述したシェルスクリプトのファイルを指定します.

optimize
optimize:
  search_algorithm: 'aiaccel.optimizer.SobolOptimizer'
  goal: "minimize"
  trial_number: 100
  rand_seed: 42
  parameters:
    -
      name: "x1"
      type: "uniform_float"
      lower: 0.0
      upper: 5.0
    -
      name: "x2"
      type: "uniform_float"
      lower: 0.0
      upper: 5.0
  • search_algorithm - 最適化アルゴリズムを設定します.この例ではソボルオプティマイザを設定しています.

  • goal - 最適化の方向を設定します.

    • ベンチマーク関数を最小化することが目的であるため,"minimize" を設定しています.

  • trial_number - 試行回数を設定します.

  • rand_seed - 乱数の生成に使用するシードを設定します.

  • parameters - ハイパパラメータの各種項目を設定します.ここでは 2 次元のベンチマーク関数の最適化を行うため,2 種類のパラメータを用意しています.2 つのパラメータに対して,以下の項目をそれぞれ設定する必要があります.パラメータの範囲や初期値を,全て同じにする必要はありません.

    • name - ハイパパラメータの名前を設定します.

    • type - ハイパパラメータのデータ型を設定します.

    • lower / upper - ハイパパラメータ最小値 / 最大値を設定します.

注意: ソボルオプティマイザを使用する際は,パラメータの初期値を設定することができません.

user.py の作成

user.py は以下のように記述します.

from aiaccel.util import aiaccel


def main(p):
    y = (p["x1"]**2) - (4.0 * p["x1"]) + (p["x2"]**2) - p["x2"] - (p["x1"] * p["x2"])

    return float(y)


if __name__ == "__main__":
    run = aiaccel.Run()
    run.execute_and_report(main)

モジュール
from aiaccel.util import aiaccel

必要なモジュールをインポートします.

  • aiaccel.util.aiaccel - ユーザープログラム内で定義される関数 main() と aiaccelとの間のインターフェイスを提供します.

main
def main(p):
    y = (p["x1"]**2) - (4.0 * p["x1"]) + (p["x2"]**2) - p["x2"] - (p["x1"] * p["x2"])

    return float(y)

最適化対象のメイン関数で,aiaccel はこの関数の return 値を最小化します. 引数にハイパパラメータの辞書型オブジェクトを取り,多項式の計算結果を返却します.

実行部分
if __name__ == "__main__":
    run = aiaccel.Run()
    run.execute_and_report(main)

aiaccel から関数 main() にハイパーパラメータを渡し,main() の返却値を Storage に保存します.run はそのインターフェイスとなるインスタンスです.メソッド execute_and_report() の内部で main() が呼ばれ,目的関数の値を計算し,Storage に計算結果が保存されます.

job_script_preamble.shの作成

job_script_preamble.sh は、ABCI にジョブを投入するためのバッチファイルのベースファイルです. このファイルには事前設定を記述します. ここに記述した設定が全てのジョブに適用されます.

#!/bin/bash

#$-l rt_C.small=1
#$-j y
#$-cwd
  • ABCI のバッチジョブ実行オプションを指定しています.

    • 参考: https://docs.abci.ai/ja/job-execution/#job-execution-options

source /etc/profile.d/modules.sh
module load gcc/11.2.0
module load python/3.8/3.8.13
source ~/optenv/bin/activate
  • ユーザプログラム実行に必要なモジュールの読み込みと仮想環境のactivateを行います.

  • ~/optenv には aiaccel をインストールした仮想環境のパスを設定します.


3. 実行

作成した config.yaml と user.py が保存されているディレクトリに移動し,下記のコマンドで aiaccel を起動してください.

aiaccel-start --config config.yaml --clean
  • コマンドラインオプション引数

    • --config - 設定ファイルを読み込むためのオプション引数です.読み込むコンフィグのパスを記述します.

    • --clean - aiaccel の起動ディレクトリ内に config.yaml の workspace で指定したディレクトリが存在する場合,削除してから実行するためのオプション引数です.


4. 結果の確認

aiaccel の正常終了後,最適化の結果は以下の 2 か所に保存されます.

  • ./work/results.csv

  • ./work/result/{trial_id}.hp

ここで,./work はコンフィグファイルの workspace に設定したディレクトリです.

results.csv には,それぞれの試行でのパラメータの値と,そのパラメータに対する目的関数の値が保存されています. result/{trial_id}.hp は,{trial_id} 回目の試行のパラメータと関数の値が YAML 形式で保存されています. さらに,同じフォルダには final_result.result というファイルが作成され,全試行中で最良のパラメータと目的関数の値が YAML 形式で保存されます.

上で実行した最適化の結果は以下のようになります.

  • ハイパパラメータ

    • x1

    • x2

  • 評価値

    • polynomial

  • 最適化手法

    • Sobol

  • 結果比較

    • 最適化結果

      x1 = 3.134656548500061
      x2 = 1.9281481206417084
      
      polynomial = -6.967029595301102
      

ネルダーミードオプティマイザの ABCI 環境での実行例

ここでは,ネルダーミードオプティマイザを ABCI 環境で実行する方法を説明します.例として,モデル ResNET50 に データセット CIFAR10 を学習させる際のハイパパラメータの最適化を行います.

以下の説明では aiaccel/examples/resnet50_cifar10 に保存されているファイルを編集して使用します.

1. ファイル構成

config.yaml

  • 最適化およびソフトウェアの設定ファイルです.

user.py

  • 与えられたパラメータから目的関数の値を計算し,aiaccel の Storage に保存するユーザプログラムです.今回の例では,モデル ResNET50 にデータセット CIFAR10 を学習させるユーザプログラムです.

job_script_preamble.sh

  • ABCI で使用するモジュール指定やジョブ設定を行うためのシェルスクリプトファイルです.

setup_dataset.py

  • データセット CIFAR10 ダウンロード用プログラムです.


2. ファイル作成手順

config.yaml の作成

generic
generic:
  workspace: "./work"
  job_command: "python user.py"
  batch_job_timeout: 7200
  • workspace - aiaccel の実行に必要な一時ファイルを保存するディレクトリを指定します.

  • job_command - ユーザープログラムを実行するためのコマンドです.

  • batch_job_timeout - ジョブのタイムアウト時間を設定します.[単位: 秒]

    • 参考 - 100 epoch の学習に最長 60 分程かかるため,7200 と長めに設定します.

resource
resource:
  type: "abci"
  num_node: 6
  • type - 実行環境を指定します.ABCI 環境で実行するためには "abci" で設定します.

  • num_node - 使用するノード数を指定します.

    • 参考 - 今回の例では,最適化アルゴリズムが NelderMeadOptimizer,パラメータ数が 5 のため, 同時に計算されるシンプレックス頂点の最大数である 6 にノード数を設定します.

ABCI
ABCI:
  group: "[group]"
  job_script_preamble: "./job_script_preamble.sh"
  job_execution_options: ""
  • group - 所属している ABCI グループを指定します.

  • job_script_preamble - ABCI の設定を記述したシェルスクリプトのファイルを指定します.

optimize
optimize:
  search_algorithm: 'aiaccel.optimizer.NelderMeadOptimizer'
  goal: "minimize"
  trial_number: 100
  rand_seed: 42
  parameters:
    -
      name: "batch_size"
      type: "uniform_int"
      lower: 64
      upper: 256
      initial: 256
    -
      name: "lr"
      type: "uniform_float"
      lower: 1.0e-4
      upper: 1.0
      initial: 0.1
    -
      name: "momentum"
      type: "uniform_float"
      lower: 0.8
      upper: 1.0
      initial: 0.9
    -
      name: "weight_decay"
      type: "uniform_float"
      lower: 5.0e-6
      upper: 5.0e-2
      initial: 5.0e-4
    -
      name: "lr_decay"
      type: "uniform_float"
      lower: 0.0
      upper: 1.0
      initial: 1.0e-3
  • search_algorithm - 最適化アルゴリズムを設定します.この例ではネルダーミードオプティマイザを設定しています.

  • goal - 最適化の方向を設定します.

    • 参考 - Validation Error Rate を最小化することが目的であるため,"minimize" と設定します.

  • trial_number - 試行回数を設定します.

  • rand_seed - 乱数の生成に使用するシードを設定します.

  • parameters - ハイパパラメータの各種項目を設定します.ここでは,5 種類のハイパパラメータを用意しています.5 つのパラメータに対して,以下の項目をそれぞれ設定する必要があります.

    • name - ハイパパラメータの名前を設定します.

    • type - ハイパパラメータのデータ型を設定します.

    • lower / upper - ハイパパラメータ最小値 / 最大値を設定します.

    • initial - ハイパパラメータの初期値を設定します.NelderMeadOptimizer の場合は,シンプレックスの頂点数 (=パラメータ数 + 1) と要素数が同じリストを設定します.頂点数未満の数値リストが与えられた場合,足りない初期値は aiaccel によってランダムに設定されます.今回の例では,各ハイパパラメータに 1 個の初期値しか与えていないため,足りない 5 個の初期値は aiaccel によって設定されます.

user.py の作成

user.py は以下のような構成になっています.

train_func
  • main 内で用いられる訓練用関数です.

val_test_func
  • main 内で用いられる評価・汎化性能検証用関数です.

main
  • 最適化対象のメイン関数です.この関数の return 値を最適化します.Validation Error Rate で設定しています.

job_script_preamble.shの作成

job_script_preamble.sh は、ABCI にジョブを投入するためのバッチファイルのベースファイルです. このファイルには事前設定を記述します. ここに記述した設定が全てのジョブに適用されます.

#!/bin/bash

#$-l rt_F=1
#$-j y
#$-cwd
#$ -l h_rt=2:00:00
  • ABCIのバッチジョブ実行オプションを指定しています.#$-l rt_F=1でFullノードを利用するように設定しています.

    • 参考: https://docs.abci.ai/ja/job-execution/#job-execution-options

source /etc/profile.d/modules.sh
module load gcc/11.2.0 python/3.8/3.8.13 cuda/10.1/10.1.243 cudnn/7.6/7.6.5
source ~/optenv/bin/activate
  • ユーザプログラム実行に必要なモジュールの読み込みと仮想環境の activate を行います.

  • ~/optenv には aiaccel をインストールした仮想環境のパスを設定します.


3. 動作説明

  • aiaccel と PyTorch 動作する環境が必要です.

    • ABCIにおけるPyTorch導入手順(出典:https://docs.abci.ai/ja/apps/pytorch/)

      • aiaccelの仮想環境作成・activate後、下記コマンドを実行してください.

        pip3 install --upgrade pip setuptools
        pip3 install filelock torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
        
  • config.yaml の [ABCI][group] は,所属しているABCIグループ名に変更してください.

    ABCI:
        group: "[group]"
        job_script_preamble: "./job_script_preamble.sh"
        job_execution_options: ""
    
  • 事前に python3 setup_dataset.py を実行し,データセットのダウンロードを行ってください.

  • 上記準備を終えたら,下記のコマンドで aiaccel を起動してください.

aiaccel-start --config config.yaml --clean
  • コマンドラインオプション引数

    • --config - 設定ファイルを読み込むためのオプション引数です.読み込むコンフィグのパスを記述します.

    • --clean - aiaccel の起動ディレクトリ内に config.yaml の workspace で指定したディレクトリが存在する場合,削除してから実行するためのオプション引数です.


4. 結果の確認

aiaccel の正常終了後,最適化の結果は以下の 2 か所に保存されます.

  • ./work/results.csv

  • ./work/result/{trial_id}.hp

ここで,./work はコンフィグファイルの workspace に設定したディレクトリです.

results.csv には,それぞれの試行でのパラメータの値と,そのパラメータに対する目的関数の値が保存されています. result/{trial_id}.hp は,{trial_id} 回目の試行のパラメータと関数の値が YAML 形式で保存されています. さらに,同じフォルダには final_result.result というファイルが作成され,全試行中で最良のパラメータと目的関数の値が YAML 形式で保存されます.

上で実行した最適化の結果は以下のようになります.

  • ハイパパラメータ

    • batch_size

    • lr

    • momentum

    • weight_decay

    • lr_decay

  • 評価値

    • Validation Error Rate

  • 最適化アルゴリズム

    • NelderMeadOptimizer

  • 結果比較

    • デフォルトパラメータ

      batch_size = 256,
      lr = 0.1,
      momentum = 0.9,
      weight_decay = 5.0e-4,
      lr_decay = 1.0e-3
      
      EvalLoss = 0.9949815124511718, evalAcc = 79.86
      
      TestLoss = 0.9659099947929383, TestAcc = 80.95
      
    • 最適化結果

      batch_size = 226,
      lr = 0.036964256184365454,
      momentum = 0.8899804003224022,
      weight_decay = 0.0027056323588476026,
      lr_decay = 0.03683728125425209
      
      EvalLoss = 0.7713460917830467, evalAcc = 83.27
      
      TestLoss = 0.7550274838387966, TestAcc = 83.59
      

5. 注意

  • 上記設定で最適化を実行すると,ABCIポイントを約50ポイント消費します.

Wrapper の作成例

必要に応じて wrapper プログラムを作成します. aiaccel はユーザーが作成した最適化対象の関数の値を計算するプログラムの wrapper を作成するための API を提供します.

1. ファイル構成

ユーザープログラム

  • 与えられたパラメータから最適化したい目的関数の値を計算し,標準出力に出力します.

wrapper.py

  • aiaccel からパラメータをユーザープログラムに渡し,計算結果を aiaccel に返却します.

config.yaml

  • 最適化およびソフトウェアの設定ファイルです.

2. ファイル作成手順

関数プログラムの作成

以下のようなコマンドを実行した際に,最適化対象すべき値が標準出力に出力されるようなプログラムを作成します.

> {cmd} --config={config} --trial_id={trial_id} --x1={x1} --x2={x2}
  • cmd - ユーザープログラムを起動するコマンドです.

  • config - コンフィグファイルのパスです.

  • trial_id - aiaccel のジョブ ID です.

  • x1, x2, … - 最適化するパラメータです.ここでは例として 2 つのパラメータに x1, x2 という名前を付けましたが,任意の名前のパラメータを必要な数だけ設定することができます.

標準出力に出力される値は,以下のような形式である必要があります.

objective_y:{y}
  • y - 最適化対象の計算結果です,

ユーザープログラムの例

ここでは例として,python で最適化対象の関数を実装する場合を確認します.

import argparse


def main(x1, x2):
    y = (x1 ** 2) - (4.0 * x1) + (x2 ** 2) - x2 - (x1 * x2)
    return y


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--x1', type=float)
    parser.add_argument('--x2', type=float)
    args = vars(parser.parse_known_args()[0])

    y = main(args["x1"], args["x2"])

    print(f"objective_y:{y}")
モジュール
import argparse

必要なモジュールをインポートします.

  • argparse - コマンドライン引数を取得するために使用するモジュールです.

最適化対象の関数
def main(x1, x2):
    y = (x1 ** 2) - (4.0 * x1) + (x2 ** 2) - x2 - (x1 * x2)
    return y

最適化対象の関数を定義します.

実行部分
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--x1', type=float)
    parser.add_argument('--x2', type=float)
    args = vars(parser.parse_known_args()[0])

    y = main(args["x1"], args["x2"])

    print(f"objective_y:{y}")

以下の部分でパーサを作成し,コマンドライン引数を受け取ります.

    parser = argparse.ArgumentParser()
    parser.add_argument('--x1', type=float)
    parser.add_argument('--x2', type=float)
    args = vars(parser.parse_known_args()[0])

この例にある最適化対象の関数では,コンフィグのパスとジョブの ID は使用しないため,パラメータ (x1x2) のみを取得するような処理が行われています.

パラメータを最適化対象の関数 (main()) に渡し,値を計算します.

    y = main(args["x1"], args["x2"])

計算結果を標準出力に出力します. このとき,計算された値の前に “objective_y:” を付け加えます.

    print(f"objective_y:{y}")

この python で実装されたプログラムの名前を user.py とすると,ユーザープログラムの起動コマンドは,python user.py となります. 例えばコンフィグのパスが config.yaml,ジョブの ID が 0,パラメータ x1 が 1, パラメータ x2 が 2 の場合,実行コマンドは次の通りです.

> python user.py --config=condig.yaml --trial_id=0 --x1=1 --x2=2

このときの出力は以下のようになります.

objective_y:-3.0

wrapper.py の作成

以下のような wrapper プログラムを python で実装します.

from aiaccel.util import aiaccel

run = aiaccel.Run()
run.execute_and_report("python user.py")
モジュール
from aiaccel.util import aiaccel
  • aiaccel.util.aiaccel - wrapper オブジェクトを作成するためのモジュールです.

Wrapper オブジェクトの作成
run = aiaccel.Run()

aiaccel が提供する wrapper オブジェクトを作成します.

ユーザープログラムの実行
run.execute_and_report("python user.py")

ユーザープログラムを実行します.

  • "python user.py" の部分は,自身のプログラムを実行するためのコマンドを記述してください.

  • コマンドライン引数として渡される config, trial_id, パラメータは, run.execute_and_report() の内部で自動的に追加されます.そのため,ここに記述する必要はありません.

config.yaml の作成

generic
generic:
    workspace: "./work"
    job_command: "python wrapper.py"
    batch_job_timeout: 600

aiaccel で wrapper プログラムを最適化させる場合は,job_command に作成した wrapper の実行コマンドを設定します. 作成した python ファイルの名前が wrapper.py であれば,実行コマンドは python wrapper.py です.

resource
resource:
  type: "local"
  num_node: 4

wrapper プログラムを最適化する場合,指定可能な実行タイプは "local" または "ABCI" です. "python_local" は選べません.

基本的な使い方

ABCIのセットアップ

ABCIのセットアップは下記資料を参考ください。

https://docs.abci.ai/ja/

Python-venvによる仮想環境の作成

venv環境での使用を推奨いたします。このチュートリアルはvenv環境で動作させることを前提としています。

python3 -m venv optenv

ここでは仮想環境の名前を「optenv」とし、以後も当仮想環境を「optenv」と表記します。 仮想環境の名前は任意の名前を設定できます。

アクティベート

仮想環境を利用するには下記コマンドを実施します。

source optenv/bin/activate

以後の作業はアクティベート済みのものとして進めます

インストール

aiaccelをダウンロードします。

git clone https://github.com/aistairc/aiaccel.git

ダウンロード完了後、aiaccelフォルダに移動します。

cd aiaccel

依存環境をインストールします.

python -m pip install -r requirements.txt

Note

事前にpipをアップグレードすることを推奨いたします。

python -m pip install --upgrade pip

setup.pyを実行し、aiaccelをインストールします。

python setup.py install

または、

python -m pip install git+https://github.com/aistairc/aiaccel.git

aiaccelがインポートできることを確認します。

python
import aiaccel

チュートリアル

  1. プロジェクトファイルの構成

コンフィグファイル、ユーザープログラム、ABCI実行用シェルスクリプトを用意し、一つのフォルダに格納します。 以後、この一式を含んだフォルダを「プロジェクトフォルダ」とします。 プロジェクトフォルダは任意の場所に作成してください。

├── config.yaml
├── user.py
└── job_script_preamble.sh

Note

  • config.yaml - 最適化の設定ファイルです。

  • user.py - 最適化対象のプログラムです。詳細は後述します。

  • job_script_preamble.sh - ABCIにジョブを投入するためのスクリプトです。このファイルにはスクリプトの共通部分のみを記述します。このファイルをベースに、バッチジョブファイルを生成します。

Note

config.yamluser.pyjob_script_preamble.sh は任意のファイル名に変更可能です。

  1. コンフィグファイルの作成

generic

サンプル

generic:
    workspace: "./work"
    job_command: "python user.py"
    batch_job_timeout: 600
  • workspace - 途中経過の保存先を指定します。

  • job_command - ユーザプログラムを実行するコマンドを記述します。

  • batch_job_timeout - jobのタイムアウト時間を設定します。[単位: 秒]

resource

サンプル

resource:
    type: "ABCI"
    num_node: 4
  • type - 実行環境を指定します。 ABCI 、または local を指定します。

  • num_node - 使用するノード数を指定します。ローカルの場合はCPUコア数を指定してください。

ABCI

サンプル

ABCI:
    group: "[group]"
    job_script_preamble: "./job_script_preamble.sh"
    job_execution_options: ""
  • job_script_preamble - ABCI上でソフトウェアを実行するためのラッパーシェルスクリプトです。詳細は後述します。

  • group - 自分が所属しているABCIグループ名を指定します。([]は記述不要です。)

optimize

サンプル

optimize:
    search_algorithm: "aiaccel.optimizer.NelderMeadOptimizer"
    goal: "minimize"
    trial_number: 30
    rand_seed: 42
    parameters:
        -
            name: "x1"
            type: "uniform_float"
            lower: 0.0
            upper: 5.0
            initial: 1.0
        -
            name: "x2"
            type: "uniform_float"
            lower: 0.0
            upper: 5.0
            initial: 1.0
  • search_algorithm - 最適化アルゴリズムを指定します。

  • goal - 最適化の方向を設定します。[minimize | maximize]

  • trial_number - 試行回数を設定します。

  • parameters

  • name - ハイパーパラメータの名前を設定します。

  • type - ハイパーパタメータのデータ型を設定します。

    • データ型一覧

      • uniform_float

      • uniform_int

      • categorical

      • ordinal

  • lower - ハイパーパラメータ最小値を設定します。

  • upper - ハイパーパラメータ最大値を設定します。

  • initial - ハイパーパラメータの初期値を設定します。

  • step - ハイパーパラメータの分解能を設定します(最適化アルゴリズムがgridの場合は必ず指定してください。)。

  • log - 対数設定用の項目です(最適化アルゴリズムがgridの場合は必ず指定してください。)。

  • base - 対数設定用の項目です(最適化アルゴリズムがgridの場合は必ず指定してください。)。

  • comment - 自由記述欄。

Note

aiaccelは、次の最適化アルゴリズムをサポートしています。

  • random - ハイパーパラメータの値をランダムに生成します。

  • grid - ハイパーパラメータの値を一定間隔でサンプリングします。

  • sobol - Sobol列を用いてハイパーパラメータの値を生成します。

  • nelder-mead - ヒューリスティクスな最適化アルゴリズムです.

  • tpe - ベイズ最適化による最適化アルゴリズムです。

parametersの記述例

Type: uniform_intの記述例
parameters:
    -
        name: "x1"
        type: "uniform_int"
        lower: 0
        upper: 5
        initial: 1
    -
        name: "x2"
        type: "uniform_int"
        lower: 0
        upper: 5
        initial: 1

Note

  • initialを指定しない場合は、項目を削除します。

-
    name: "x1"
    type: "uniform_int"
    lower: 0
    upper: 5
Type: uniform_floatの記述例
parameters:
    -
        name: "x1"
        type: "uniform_float"
        lower: 0.0
        upper: 5.0
        initial: 0.0
    -
        name: "x2"
        type: "uniform_float"
        lower: 0.0
        upper: 5.0
        initial: 0.0
Type: categoricalの記述例
parameters:
    -
        name: "x1"
        type: "categorical"
        choices: ['green', 'red', 'yellow', 'blue']
    -
        name: "x2"
        type: "categorical"
        choices: ['green', 'red', 'yellow', 'blue']

Note

  • categorial使用時は choices 項目を使用します. choices は配列で指定する必要があります。

  • catogoricalを使用できるのは、最適化アルゴリズムが Random, Grid', および TPE` の場合のみです。

Type: ordinalの記述例
parameters:
    -
        name: "x1"
        type: "ordinal"
        sequence: [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
        lower: 0
        upper: 1024
    -
        name: "x2"
        type: "ordinal"
        sequence: [1024, 512, 256, 128, 64, 32, 16, 8, 4, 2]
        lower: 0
        upper: 1024

Note

  • ordinal使用時は sequence 項目を使用します. sequence は配列で指定する必要があります。

  • ordinal使用時は initial の設定はできません。

  • ordinalを使用できるのは、最適化アルゴリズムが RandomGrid の場合のみです。

grid使用時の注意事項

最適化アルゴリズムで grid を使用する場合、 parameters の設定に logstepbase を指定してください。

parameters:
    -
        name: "x1"
        type: "uniform_int"
        lower: 0
        upper: 5
        step: 1
        log: false
        base: 10
        initial: 0.0
    -
        name: "x2"
        type: "uniform_int"
        lower: 0
        upper: 5
        step: 1
        log: false
        base: 10
        initial: 0.0

Nelder-Mead使用時の注意事項

Nelder-Meadを使用する場合、 initial を配列で指定する必要があります。

parameters:
    -
        name: "x1"
        type: "uniform_int"
        lower: 0
        upper: 5
        initial: [0, 5, 3]
    -
        name: "x2"
        type: "uniform_int"
        lower: 0
        upper: 5
        initial: [2, 4, 1]

また、 initial を使用しない場合は、空のリストを指定します.

parameters:
    -
        name: "x1"
        type: "uniform_int"
        log: False
        lower: 0
        upper: 5
        initial: []
    -
        name: "x2"
        type: "uniform_int"
        log: False
        lower: 0
        upper: 5
        initial: []

あるいは、 initial 項目そのものを削除します。

parameters:
    -
        name": "x1"
        type": "uniform_int"
        log": False
        lower": 0
        upper": 5
    -
        name: "x2"
        type: "uniform_int"
        log: False
        lower: 0
        upper: 5

コンフィグファイル サンプル

config.yaml

generic:
    workspace: "./work"
    job_command: "python user.py"
    batch_job_timeout: 600

resource:
    type: "local"
    num_node: 4

ABCI:
    group: "[group]"
    job_script_preamble: "./job_script_preamble.sh"
    job_execution_options: ""

optimize:
    search_algorithm: "aiaccel.optimizer.NelderMeadOptimizer"
    goal: "minimize"
    trial_number: 30
    rand_seed: 42
    parameters:
        -
            name: "x1"
            type: "uniform_float"
            lower: 0.0
            upper: 5.0
            initial: [0.0, 5.0, 3.0]
        -
            name: "x2"
            type: "uniform_float"
            lower: 0.0
            upper: 5.0
            initial: [2.0, 4.0, 1.0]
  1. ユーザープログラムの作成

最適化対象の処理を作成します。ここでは、作成済みモデルをaiaccelで最適化するための変更方法を記述します。

次の関数を最適化させる場合の例を示します。


    def func(x1, x2):
        y = (x1**2) - (4.0 * x1) + (x2**2) - x2 - (x1 * x2)
        return y

これを、aiaccelで最適化させるには次のように変更します。

    from aiaccel.util import aiaccel

    def func(p):
        x1 = p["x1"]
        x2 = p["x2"]
        y = (x1**2) - (4.0 * x1) + (x2**2) - x2 - (x1 * x2)
        return y

    if __name__ == "__main__":

        run = aiaccel.Run()
        run.execute_and_report(func)
  1. Wrapperの作成

必要に応じてwrapperプログラムを作成します。aiaccelはユーザープログラムのwrapperを作成するためのAPIを提供します。

サンプル

wrapper.py(任意の名前に変更可能)

    from aiaccel.util import aiaccel

    # Wrapperオブジェクトの生成
    run = aiaccel.Run()

    # ユーザープログラムを実行します。
    # commandにユーザープログラムを実行するためのコマンドを記述してください。
    # コマンドライン引数は自動で生成します。
    #  --config
    #  --index
    #  --x1 (例)
    #  --・・・
    run.execute_and_report("python user.py")

aiaccelでwrapperプログラムを最適化させる場合はコンフィグファイルのjob_commandを変更します。

    generic:
        workspace: "./work"
        job_command: "python wrapper.py"
        batch_job_timeout: 600
  1. job_script_preamble.shの作成

job_script_preamble.sh は、ABCIにジョブを投入するためのバッチファイルのベースファイルです。 このファイルには事前設定を記述します。ここに記述した設定が全てのジョブに適用されます。

サンプル

    #!/bin/bash

    #$-l rt_C.small=1
    #$-j y
    #$-cwd

    source /etc/profile.d/modules.sh
    module load gcc/11.2.0
    module load python/3.8/3.8.13
    module load cuda/10.2
    module load cudnn/8.0/8.0.5
    module load nccl/2.8/2.8.4-1
    source ~/optenv/bin/activate

    AIACCELPATH=$HOME/local/aiaccel-dev
    export PYTHONPATH=$AIACCELPATH:$AIACCELPATH/lib
  1. 最適化実行

プロジェクトフォルダに移動し、次のコマンドを実行します。

python -m aiaccel.cli.start --config config.yaml

Note

コンフィグファイル名 `config.yaml` は適切な文字列に変更してください。

実行するとターミナルに進捗状況を出力します。

オプション付きの実行

start コマンドの後に、追加オプションを指定できます。

python -m aiaccel.cli.start
  • –clean : workspaceが既に存在する場合、最適化実行前にworkspaceを削除します。

  • –resume : workspaceが既に存在する場合、保存データが存在するトライアルを指定することで、指定のトライアルから再開することができます。

python -m aiaccel.cli.start --config config.yaml --clean

ローカル環境での実行方法

ローカル環境でaiaccelを使用する場合は、次のように設定を変更します。

resourceの設定

コンフィグファイルの resourcetypelocal を指定します。

resource:
    type: "local"
    num_node: 4
ABCIの設定

ローカル環境で実施する場合, ABCI の設定は動作に反映されません。

ABCI:
    group: "[group]"
    job_script_preamble: "./job_script_preamble.sh"
    job_execution_options: ""
job_script_preamble.sh

ローカル環境で実施する場合、 job_script_preamble.sh は不要です。 記述した内容は動作に反映されません。

コンフィグレーションの設定ガイド (WIP)

generic:

workspace (str, optional):

aiaccel の実行に必要な一時ファイルを保存するディレクトリを指定します. デフォルトでは “./work” に設定されています.

job_command (str):

ユーザープログラムを実行するためのコマンドです.

python_file (str, optional):

ローカル実行のモードの一つである python_local モードを用いる場合に,最適化対象の関数が実装されている python のファイルパスを指定します. 実行モードが ABCI または通常の Local の場合には指定する必要はありません.

function (str, optional):

ローカル実行のモードの一つである python_local モードを用いる場合に,最適化対象の関数名を指定します. aiaccel は実行時,python_file に書かれたファイルから,ここで指定された名前の関数をインポートします. 実行モードが ABCI または通常の Local の場合には指定する必要はありません.

batch_job_timeout (int, optional):

ジョブのタイムアウト時間を秒単位で設定します. デフォルトでは 600 (秒) に設定されています.

sleep_time (float, optional):

最適化実行のメインループ 1 周あたりのスリープ時間を秒単位で指定します. デフォルトでは 0.01 (秒) に設定されています.


resource:

type (str):

実行環境を指定します. aiaccel は以下の 3 つの環境での実行をサポートしています.

  • “abci” - ABCI 上で最適化を実行します.

  • “local” - ローカル環境で最適化を実行します.

  • “python_local” - ローカル環境で最適化を実行します.最適化対象の関数が python で実装されている必要がありますが,通常のローカル実行よりも高速に最適化を実行することが可能です. デフォルトでは “local” に設定されています.

num_node (int):

使用するノード数を指定します. デフォルトでは 1 に設定されています.


ABCI:

group (str):

ユーザーが所属する ABCI のグループを指定します.

job_script_preamble (str):

ABCI の設定を記述したシェルスクリプトのファイルを指定します.

job_execution_options (str | list[str], optional):

aiaccel が ABCI の計算ノード上にジョブを投入する際に付加されるオプションのコマンドです. デフォルトでは “” (空の文字列) が設定されています.


optimize:

search_algorithm (str, optional):

最適化アルゴリズムを設定します. aiaccel では以下のアルゴリズムをサポートしています.

  • “aiaccel.optimizer.NelderMeadOptimizer” - Nelder-Mead 法でパラメータの探索を行います.

  • “aiaccel.optimizer.RandomOptimizer” - パラメータをランダムに生成します,

  • “aiaccel.optimizer.SobolOptimizer” - Sobol’ 列を用いてパラメータを生成します.

  • “aiaccel.optimizer.GridOptimizer” - 分割した探索空間からパラメータを選びます.

  • “aiaccel.optimizer.TpeOptimizer” - ベイズ最適化を用いてパラメータの探索を行います.

デフォルトでは “aiaccel.optimizer.NelderMeadOptimizer” に設定されています.

goal (str, optional):

最適化の向きを決定します.

  • “minimize” - 目的関数が小さくなるようにパラメータを最適化します.

  • “maximize” - 目的関数が大きくなるようにパラメータを最適化します.

デフォルトでは “minimize” に設定されています.

trial_number (int):

試行回数を設定します.

rand_seed (int, optional):

乱数生成に用いるシードを設定します.設定可能な値の範囲は numpy.random.default_rng が取り得る範囲に一致します. デフォルトでは None に設定されています.

sobol_scramble (bool, optional):

ソボルオプティマイザを使用する際に,スクランブルを使用するかを指定します. デフォルトでは true に設定されています.

parameters (list):

パラメータの探索条件をまとめたリストを設定します. 最適化アルゴルズムとパラメータのデータ型に応じて,各要素には以下の項目が含まれます.

  • name - パラメータの名前を設定します.

  • type - パラメータのデータ型を設定します.aiaccel は次のデータ型をサポートします.

    • “uniform_float” - 浮動小数点数型

    • “uniform_int” - 整数型

    • “categorical” - カテゴリカル型

    • “ordinal” - オーディナル型

  • lower - パラメータの最小値を設定します.

  • upper - パラメータの最大値を設定します.

  • initial - パラメータの初期値を設定します.

  • step - パラメータの分解能を設定します.

  • log - パラメータの探索空間を対数スケールで分割するかを指定します.対数スケールを使用する場合は true を,使用しない場合は false を設定します.

  • base - 対数スケールでパラメータの探索空間を分割する場合の対数の基数を指定します.

  • choices - データ型が categorical の場合に,選択肢のリストを設定します.

  • sequence - データ型が ordinal の場合に,選択肢のリストを設定します.

  • comment - コメントを設定します.


それぞれのアルゴリズムとデータ型で必要なパラメータは以下の通りです.

Nelder-Mead 法 (“aiaccel.optimizer.NelderMeadOptimizer”)

設定可能なデータ型は “uniform_float”,”uniform_int”,および “ordinal” です.

“uniform_float” または “uniform_int” の場合

  • name

  • type (“uniform_float”, “uniform_int”)

  • lower

  • upper

  • initial - 要素数が パラメータ数 + 1 の配列を設定します.initial の項目が存在しない場合,aiaccel はランダムに初期値の配列を設定します.また,設定された配列の要素数が パラメータ数 + 1 より少ない場合,aiaccel は足りない初期値をランダムに生成し補います.

“ordinal” の場合

  • name

  • type (“ordinal”)

  • sequence - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

  • initial - 要素数が パラメータ数 + 1 の配列を設定します.initial の項目が存在しない場合,aiaccel はランダムに初期値の配列を設定します.また,設定された配列の要素数が パラメータ数 + 1 より少ない場合,aiaccel は足りない初期値をランダムに生成し補います.

ランダムオプティマイザ (“aiaccel.optimizer.RandomOptimizer”)

設定可能なデータ型は “uniform_float”, “uniform_int”, “categorical”, および “ordinal” です.

“uniform_float” または “uniform_int” の場合

  • name

  • type (“uniform_float”, “uniform_int”)

  • lower

  • upper

  • initial

“categorical” の場合

  • name

  • type (“categorical”)

  • choices - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

  • initial

“ordinal” の場合

  • name

  • type (“ordinal”)

  • sequence - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

  • initial

ソボルオプティマイザ (“aiaccel.optimizer.SobolOptimizer”)

設定可能なデータ型は “uniform_float” と “uniform_int” です. データ型に依らず,初期値は設定できません.

  • name

  • type (“uniform_float”, “uniform_int”)

  • lower

  • upper

グリッドオプティマイザ (“aiaccel.optimizer.GridOptimizer”)

設定可能なデータ型は “uniform_float”, “uniform_int”, “categorical”, および “ordinal” です. データ型に依らず,初期値は設定できません.

“uniform_float” または “uniform_int” の場合

  • name

  • type (“uniform_float”, “uniform_int”)

  • lower

  • upper

  • step

  • log

  • base

(注意) logtrue の場合,lowerupper,および step は対数スケールでの値として参照されます. 即ち,探索の下限は \({base}^{lower}\),上限は \({base}^{upper}\) と解釈され, \(n\ (=0, 1, \cdots)\) 番目の点は \({base}^{lower} {base}^{n \times step}\) で与えられます. 一方で logfalse の場合,lowerupper,および step は,それぞれ探索の下限,上限,およびステップに直接対応します. この場合,base の値は使用されませんが,何も値を設定していないとエラーが生じます.

“categorical” の場合

  • name

  • type (“categorical”)

  • choices - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

“ordinal” の場合

  • name

  • type (“ordinal”)

  • sequence - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

TPE オプティマイザ (“aiaccel.optimizer.TpeOptimizer”)

設定可能なデータ型は “uniform_float”, “uniform_int”, “categorical”, および “ordinal” です.

“uniform_float” または “uniform_int” の場合

  • name

  • type (“unform_float”, “uniform_int”)

  • lower

  • upper

  • initial

  • log

“categorical” の場合

  • name

  • type (“categorical”)

  • choices - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

  • initial

“ordinal” の場合

  • name

  • type (“ordinal”)

  • sequence - 選択肢の配列を設定します.配列の要素は float, int, または str 型です.

  • initial


job_setting:

cancel_retry (int, optional):

Max retry counts to transit the state from HpCancelFailed to HpCancelFailure. Defaults to 3.

cancel_timeout (int, optional):

Timeout seconds to transit the state from HpCancelChecking to HpCancelFailed. Defaults to 60.

expire_retry (int, optional):

Max retry counts to transit the state from HpExpireFailed to HpExpireFailure. Defaults to 3.

expire_timeout (int, optional):

Timeout seconds to transit the state from HpExpireChecking to HpExpireFailed. Defaults to 60.

finished_retry (int, optional):

Max retry counts to transit the state from HpFinishedFailed to HpFinishedFailure. Defaults to 3.

finished_timeout (int, optional):

Timeout seconds to transit the state from HpFinishedChecking to HpFinishedFailed. Defaults to 60.

job_loop_duration (float, optional):

スケジューラジョブスレッドのループ 1 周あたりのスリープ時間を秒単位で指定します. デフォルトでは 0.5 (秒) に設定されています.

A sleep time each job loop. Defaults to 0.5.

job_retry (int, optional):

Max retry counts to transit the state from HpCancelFailed to HpCancelFailure. Defaults to 2.

job_timeout (int, optional):

Timeout seconds to transit the state from JobChecking to JobFailed. Defaults to 60.

kill_retry (int, optional):

Max retry counts to transit the state from KillFailed to KillFailure. Defaults to 3.

kill_timeout (int, optional):

Timeout seconds to transit the state from KillChecking to KillFailed. Defaults to 60.

result_retry (int, optional):

Max retry counts to transit the state from RunnerFailed to RunnerFailure. Defaults to 1.

runner_retry (int, optional):

Max retry counts to transit the state from RunnerFailed to RunnerFailure. Defaults to 3.

runner_timeout (int, optional):

Timeout seconds to transit the state from RunnerChecking to RunnerFailed. Defaults to 60.

running_retry (int, optional):

Max retry counts to transit the state from HpRunningFailed to HpRunningFailure. Defaults to 3.

running_timeout (int, optional):

Timeout seconds to transit the state from HpRunningChecking to HpRunningFailed. Defaults to 60.

init_fail_count (int, optional):

Defaults to 100.

name_length (int, optional):

文字列としてのジョブ ID の長さです. この文字列は,結果を .hp ファイルに保存する際にファイル名として使用されます. デフォルトでは 6 に設定されています.


logger:

file:

実行ログの保存先を設定します.

master (str, optional):

マスターモジュールのログの保存先を設定します. デフォルトでは “master.log” に設定されています.

optimizer (str, optional):

オプティマイザモジュールのログの保存先を設定します. デフォルトでは “optimizer.log” に設定されています.

scheduler (str, optional):

スケジューラモジュールのログの保存先を設定します. デフォルトでは “scheduler.log” に設定されています.

log_level:

master (str):

マスターモジュールからのログファイル出力のログレベルを設定します. 以下の文字列が設定可能です.

  • ‘DEBUG’

  • ‘INFO’

  • ‘WARNING’

  • ‘WARN’

  • ‘ERROR’

  • ‘CRITICAL

デフォルトでは “DEBUG” に設定されています.

A logging level for a log file output of master module. Following strings are available;

  • ‘DEBUG’

  • ‘INFO’

  • ‘WARNING’

  • ‘WARN’

  • ‘ERROR’

  • ‘CRITICAL

Defaults to “DEBUG”.

optimizer (str, optional):

オプティマイザモジュールからのログファイル出力のログレベルを設定します. デフォルトでは “DEBUG” に設定されています.

A logging level for a log file output of optimizer module. Defaults to “DEBUG”.

scheduler (str, optional):

オプティマイザモジュールからのログファイル出力のログレベルを設定します. デフォルトでは “DEBUG” に設定されています.

A logging level for a log file output of scheduler module. Defaults to “DEBUG”.

stream_level:

master (str, optional):

マスターモジュールからのストリーム出力のログレベルを設定します. デフォルトでは “DEBUG” に設定されています.

A logging level for a stream output of master module. Defaults to “DEBUG”.

optimizer (str, optional):

オプティマイザモジュールからのストリーム出力のログレベルを設定します. デフォルトでは “DEBUG” に設定されています.

A logging level for a stream output of optimizer module. Defaults to “DEBUG”.

scheduler (str, optional):

スケジューラモジュールからのストリーム出力のログレベルを設定します. デフォルトでは “DEBUG” に設定されています.

A logging level for a stream output of scheduler module. Defaults to “DEBUG”.


verification:

is_verified (bool, optional):

最適化結果の verification を行うかを設定します. デフォルトでは flase が設定されています.

Defaults to false.

condition (list, optional):

Verification の条件の配列を設定します. 配列の各要素には,以下の項目が設定されている必要があります.

  • loop - Verification 対象となるジョブの ID です.

  • minimum - 試行回数 loop 回までに計算された最も良い目的関数の値として許容される値の下限です.

  • maximum - 試行回数 loop 回までに計算された最も良い目的関数の値として許容される値の下限です.

デフォルトでは,[] (空の配列) が設定されています.

Defaults to [] (an empty list).

aiaccelアーキテクチャ

aiaccelは,与えられた入力ハイパーパラメータ群から最適なハイパーパラメータを出力するハイパーパラメータ最適化ライブラリです.

本章は,開発者に向けたドキュメントです. aiaccelのアーキテクチャやトピックごとにaiaccelの機能を解説し,aiaccelに関する開発の一助となることを目的としています.

aiaccelのシステム概要

aiaccelのシステムについて概説します. aiaccelは,ABCI上で実行することを想定したハイパーパラメータ最適化ライブラリです. ローカルコンピュータでも動作はしますが,その機能を最大限に発揮するためにはABCIを利用することが推奨されます. ABCIについては,ABCI User Guideを参照してください. aiaccelは,ABCIのインタラクティブノード上で実行されることを想定されます. Configを入力として,aiaccelは内部でMaster, Optimizer, Scheduler を起動し,Storage(ファイルシステムやデータベース)に状態を保存しながら,最適化対象であるユーザープログラムをABCI計算ノードにてジョブとして実行します. ABCI計算ノードで実行されたユーザープログラムは,結果をStorageに保存します.

aiaccel_system

aiaccelの入出力

aiaccelの入出力をもう少しく詳しくみてみます.

  • 入力

    • Config: コンフィグレーションファイルです. examples/sphere/config.yaml などが該当します. 上記のシステム概要のConfigの一部です.

    • User Program: ユーザープログラムです. examples/sphere/user.py などが該当します. user.py は上記のコンフィグレーションファイル内で指定します. user.pyである必要はありませんが,aiaccelがユーザープログラムを実行するためのインタフェースが user.py に記述されていますので user.py に該当するファイルは必要となります. Java, C++ などの実行ファイルを利用する場合は user.py に該当するファイルから呼び出して実行してください. 上記のシステム概要の<user program>.pyです.

    • Job Script: ジョブスクリプトファイルです. examples/sphere/job_script_preamble.sh などが該当します. ジョブスクリプトファイルは,ABCIを利用する際に必要となるファイルです. 役割は,aiaccelがABCI上でuser.pyをジョブとして実行するためのスクリプトとなります. 詳しくはABCIのバッチジョブに関するドキュメントの記法を参照してください. 上記のシステム概要のConfigの一部です.

  • 出力

    • Work Directory: aiaccelを実行した際生成されるワークディレクトリです. aiaccelを実行した際 work という名前のディレクトリが生成されます. 上記のシステム概要のStorageの一部です.

    • Result Directory: aiaccelを実行した際,実行結果を保存するリザルトディレクトリです. ワークディレクトリは,現在実行中・実行した状態を保存するディレクトリであるのに対し,リザルトディレクトリは過去に実行した結果を全て保存するディレクトリです. ただし,実行したディレクトリ内に生成されるため,実行するディレクトリを変更するとまた新しいリザルトディレクトリが生成されます. 上記のシステム概要のStorageの一部です.

    • Database: aiaccelの実行中の状態・実行結果を保存するデータベースです. work/storage/storage.db が該当します. work はワークディレクトリです. データベースはsqlite3を採用しています. 上記のシステム概要のStorageの一部です.

aiaccel_input_output

aiaccelの構成モジュール

aiaccelは,内部で3つのモジュールが連携しながら実行されます. 本節ではaiaccelの3つのモジュールの役割について説明します.

  • マスター

    • スケジューラ・オプティマイザを管理します. 開始時に起動され,オプティマイザ・スケジューラを起動し,これら2つのモジュールの死活監視をします. オプティマイザ(またはスケジューラ)が停止すると実行中のスケジューラ(またはオプティマイザ)を停止させ,自身も終了します.

  • オプティマイザ

    • どのハイパーパラメータを次に実行するかを計算します.5つの最適化アルゴリズムをサポートしており,コンフィグに記述することで実行するアルゴリズムを選択します.

  • スケジューラ

    • オプティマイザが選択したハイパーパラメータをジョブとして実行し,そのジョブを管理します. ジョブは,ハイパーパラメータごとに生成されローカルコンピュータまたはABCI上で実行されます.

aiaccel_overview

aiaccelの処理フロー

aiaccelが内部でどのように実行されるかを別の視点から見てみます. 以下の図でもマスター・オプティマイザ・スケジューラの3つのモジュールを軸に構成されています.

  1. aiaccel-startコマンドからコンフィグを入力として指定して実行します.

  2. start.pyがコンフィグをロードし,Masterを起動します.

  3. MasterがOptimizerを起動します.

  4. MasterがSchedulerを起動します.

  5. Optimizerはコンフィグからハイパーパラメータを読み込み,最適化アルゴリズムに基づきハイパーパラメータを生成しStorageに保存します.

  6. SchedulerはStorageから新しいハイパーパラメータを読み込み,コンフィグに基づき指定の計算ノードでユーザープログラムをジョブとして実行します.

  7. aiaccelのラッパーにより実行されたユーザープログラムが終了すると,aiaccelラッパーがユーザープログラムの結果をStorageに保存します.

  8. 5-7 が指定のトライアル数まで繰り返されます.ハイパーパラメータの生成数や同時に実行できる計算ノード数などは全てコンフィグに記述します.

  9. 全てのトライアル数分のハイパーパラメータが完了する,または停止命令を受けるとMaster, Optimizer, Scheduler は停止します.

aiaccel_flow

コードから見るaiaccelの処理フロー

aiaccelの処理フローでは,大まかにaiaccelではMaster, Optimizer, Schedulerが協調し,それぞれの役割を果たしていることについて述べた. では実際にコードレベルで,それらのフローを追ってみよう.

  1. start.py

aiaccelはaiaccel-startスクリプトにより実行を開始する.aiaccel/cli/start.py を見てみるとまずMaster, Optimizer, Schedulerが初期化される

    Master = create_master(args.config)
    Optimizer = create_optimizer(args.config)
    Scheduler = create_scheduler(args.config)

初期化されたモジュールは,以下のコードで実行される. pre_processメソッドの後メインループが周り,メインループ後にpost_processメソッドが実行される. シンプルに表せば基本的にMasterもOptimizerもSchedulerは,これらの処理で説明できる.

    for module in modules:
        module.pre_process()

    while True:
        for module in modules:
            if not module.inner_loop_main_process():
                break
            if not module.check_error():
                break
            module.loop_count += 1
        else:
            time.sleep(sleep_time)
            continue
        break

    for module in modules:
        module.post_process()
  1. module.py

pre_processメソッド・メインループ・post_processメソッドの基本的な記述は aiaccel/module.py にある. module.py は,Master, Optimizer, Scheduler のスーパークラスにあたる AbstractModule クラスが定義されている.

  1. Master

再度 aiaccel/cli/start.py を見てみる. Masterモジュールは create_master メソッドにより初期化されている. aiaccel/master/create.py を見てみると,コンフィグに記述されたresource_typeに基づき異なるMasterクラスが実行される.

簡単のため,ここでは LocalMaster クラスを見てみる. aiaccel/master/local_master.py を見てみると,AbstractMasterクラスを継承しており特に追記はない.

では更に aiaccel/master/abstract_master.py の AbstractMaster クラスを見てみる. 時間に関するコードや Evaluator などがあるが,inner_loop_main_process メソッド内の以下のコードが終了判定をしている.

        if self.hp_finished >= self.trial_number:
            return False

AbstractMaster クラスにおいては,ここで False が返る,つまり終了したハイパーパラメータ数がトライアル数以上になるとMasterが終了する.

  1. Optimizer

Optimizerモジュールも,Master同様 start.py にて create_optimizer メソッドにより初期化されている. aiaccel/optimizer/create.py を見てみると,コンフィグに記述された最適化アルゴリズム名に基づきOptimizerを初期化している.

ここでは簡単のため RandomOptimizer クラス を見てみる. aiaccel/optimizer/random_optimizer.py を見てみると,AbstractOptimzier クラスを継承しており,generate_parameter メソッドのみオーバーライドされている.

RandomOptimizer クラスの generate_parameter メソッドは,以下のコードでランダムなハイパーパラメータを生成する.

        sample = self.params.sample(rng=self._rng)

では更に aiaccel/optimizer/abstract_optimizer.py の AbstractOptimizer クラスを見てみる. メインループである inner_loop_main_process メソッドを見ると,以下のコードで新しいハイパーパラメータを生成している.

        for _ in range(pool_size):
            new_params = self.generate_new_parameter()

pool_size 変数は,計算ノードがどの程度空いているかに基づいた数値である.

  1. Scheduler

Schedulerモジュールも,Master, Optimizer 同様のアーキテクチャとなっている. ここでは LocalScheduler クラスを見てみる.

aiaccel/scheduler/local_scheduler.py は,AbstractScheduler クラスを継承している. get_stats メソッドは,現在のジョブの状態を取得する役割を担う. LocalSchedulerクラスでは,ps コマンドをパースしてジョブの状態を取得していることが分かる.

inner_loop_main_process メソッドはメインループであり,ジョブをプロセスとして実行する. その際の execute メソッドが実行コマンドを生成し実行する.

カスタムオプティマイザー作成ガイド

オプティマイザは,ハイパーパラメータを生成する機能を担うためどのハイパーパラメータの組を選択するかのアルゴリズムにより,最適化のパフォーマンスは大きく変わってきます. 本稿では,ユーザーがaiaccelを用いた独自のオプティマイザを開発するための方法について解説します.

カスタムオプティマイザの実行確認

それでは,まずカスタムオプティマイザを実行するための動作を確かめてみましょう. 所謂Hello, Worldの位置づけです. ここで解説する内容は簡単にまとめると下記のようになります.

  • カスタムオプティマイザのソースファイルを作成する

  • カスタムオプティマイザのソースファイルをaiaccelが読み込めるようにする

  • コンフィグレーションファイルを編集し,カスタムオプティマイザを実行できるようにする

カスタムオプティマイザをどのように実行するかは環境に依存しますが,今回は自分で作成したワークスペースディレクトリに追加して実行してみます. その他にはソースコードに追加するなど,環境次第でやり方は異なりますので各自の環境に合わせて設定してください.

  1. 開発環境の確認

まず環境の確認からします. 本ガイドでは,各種インストールは終了しaiaccelが実行できる状態から始めます. インストールが未だの方はインストールガイドを参照してください. 各ディレクトリ・ファイルは以下のとおりとします. 皆さんの環境に読み替えて参考にしてください.

  • aiaccelのソースディレクトリ: /workspace/aiaccel

  • ワークスペースディレクトリ: /workspace/aiaccel/work

  • 例えばランダムオプティマイザのファイル: /workspace/aiaccel/aiaccel/optimizer/random_optimizer.py

  1. カスタムオプティマイザファイルの作成

カスタムオプティマイザのソースファイルを作成します. 今回はランダムオプティマイザをコピーします.

> pwd
/workspace/aiaccel

> mkdir -p work/lib/my_optimizer

> cp aiaccel/optimizer/random_optimizer.py work/lib/my_optimizer/custom_optimizer.py

これでcustom_optimizer.pyが作成されました.

  1. ファイルの編集

このままではcustom_optimizer.pyの内容はランダムオプティマイザと同じですので,少しだけ編集します.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

from aiaccel.optimizer.abstract_optimizer import AbstractOptimizer


- class RandomOptimizer(AbstractOptimizer):
+ class CustomOptimizer(AbstractOptimizer):
    """An optimizer class with a random algorithm.

    """

上記はdiff表記で削除された行頭に - 追加された行頭に + が付いています. クラス名をRandomOptimizerからCustomOptimizerに変更しました. 変更したファイルは保存します.

  1. パスの設定

今custom_optimizer.pyにはランダムオプティマイザを全く同じ動作をするCustomOptimizerを定義しました. aiaccelから作成したCustomOptimizerクラスを実行する必要があるので,まず__init__.pyファイルを作成します. ここではaiaccel/optimizerにある__init__.pyを編集して利用します.

> pwd
/workspace/aiaccel

> cp aiaccel/optimizer/__init__.py work/lib/my_optimizer/

追加したCustomOptimizerを読み込むように編集します.

/workspace/aiaccel/work/lib/my_optimizer/init.py

- from .grid_optimizer import GridOptimizer
- from .nelder_mead_optimizer import NelderMeadOptimizer
- from .random_optimizer import RandomOptimizer
- from .sobol_optimizer import SobolOptimizer
- from .tpe_optimizer import TpeOptimizer
+ from .custom_optimizer import CustomOptimizer

__all__ = [
-    GridOptimizer,
-    RandomOptimizer,
-    SobolOptimizer,
-    NelderMeadOptimizer,
-    TpeOptimizer
+    CustomOptimizer
]

次にパスの設定を行います. PYTHONPATHに,aiaccelと追加したcustom_optimizer.pyのディレクトリを追加します.

> echo $PYTHONPATH

> export PYTHONPATH=/workspace/aiaccel:/workspace/aiaccel/work/lib

> echo $PYTHONPATH
/workspace/aiaccel:/workspace/aiaccel/work/lib
  1. ユーザーファイルの作成

カスタムオプティマイザを作成したので,実際に実行するユーザーファイルを作成します. 今回は/workspace/aiaccel/examples/sphereディレクトリをコピーして作成します.

> pwd
/workspace/aiaccel

> cp -R examples/sphere work/

> cd work/sphere

> pwd
/workspace/aiaccel/work/sphere

> ls
config.yaml       user.py

examples/sphereディレクトリをコピーし,sphereディレクトリに移動しました. 次にコンフィグレーションファイルを編集します. オプティマイザに今回作成したカスタムオプティマイザを利用したいのでconfig.yamlを編集します.

/workspace/aiaccel/work/sphere/config.yaml

optimize:
- search_algorithm: "aiaccel.optimizer.NelderMeadOptimizer"
+ search_algorithm: "my_optimizer.CustomOptimizer"
  goal: "minimize"
  trial_number: 30
  rand_seed: 42
  parameters:

これでコンフィグレーションファイルの編集は一旦終了です. 編集したファイルを保存します.

  1. 実行の確認

それでは現在のディレクトリで実行してみます.

> pwd
/workspace/aiaccel/work/sphere

> aiaccel-start --config config.yaml --clean

正常に実行できれば成功です. このカスタムオプティマイザの中身はランダムオプティマイザと同じなので,ランダムにハイパーパラメータが選択されます.

ここまででカスタムオプティマイザが実行できることが確認できたので,次節ではオプティマイザのソースコードを編集して実行する点を解説します.

カスタムオプティマイザの編集

前節でカスタムオプティマイザの実行確認を行いました. 本節では,前節で作成したカスタムオプティマイザを編集しシンプルなアルゴリズムを実装します. 簡単のため前節で作成したワークスペースを流用し5つのfloat型のハイパーパラメータに対し正規分布でハイパーパラメータを生成するオプティマイザを作成してみましょう.

既存のオプティマイザには,ランダム・Sobol’列・グリッド・NelderMead・TPEがサポートされていますが,ランダムオプティマイザをコピーしたソースファイルから編集を始めます.

  1. ランダムオプティマイザの確認

前節でコピーしたカスタムオプティマイザのファイルを見てみましょう.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

from __future__ import annotations
from aiaccel.optimizer.abstract_optimizer import AbstractOptimizer


class CustomOptimizer(AbstractOptimizer):
    """An optimizer class with a random algorithm.

    """

    def generate_parameter(self) -> list[dict[str, float | int | str]]:
        """Generate parameters.

        Returns:
            list[dict[str, float | int | str]]: A list of created parameters.
        """
        new_params = []
        sample = self.params.sample(rng=self._rng)

        for s in sample:
            new_param = {
                'parameter_name': s['name'],
                'type': s['type'],
                'value': s['value']
            }
            new_params.append(new_param)

        return new_params

CustomOptimizer クラスは AbstractOptimizer を継承し,generate_parameter メソッドのみを実装しています. generate_parameter 以外のオプティマイザとしての機能は AbstractOptimizer に実装されているので,generate_parameter メソッドを実装すれば簡単なオプティマイザなら実装することができます.

  1. ハイパーパラメータのソースコードの確認

generate_parameter メソッドを見てみましょう. self.params.sample というメソッドを実行しています. このメソッドは,aiaccel/parameter.py の HyperParameterConfiguration インスタンスである self.paramssample メソッドです. 引数として与えられている self._rng は 継承元の AbstractOptimizer が持つ numpy.random.RandomState オブジェクトです. sample メソッド内では,さらに HyperParameter インスタンスである value から更に sample メソッドが呼ばれています. この2度目に呼ばれた sample メソッドは HyperParameter クラスのメソッドであり,中身を見てみるとハイパーパラメータのタイプごとに処理が分かれていますが,例えば FLOAT 型の場合 numpy.random.RandomState.uniform が実行されます.

/workspace/aiaccel/aiaccel/parameter.py

        elif self.type.lower() == 'float':
            value = rng.uniform(self.lower, self.upper)

こうして生成されたランダムなハイパーパラメータを返すことが generate_parameter メソッドの役割となります.

  1. 正規分布オプティマイザの作成

では,aiaccel/parameter.py の HyperParameterConfiguration クラスをもう少し詳しく見てみましょう. sample メソッドの他に,get_parameter_list というメソッドがあります. このメソッドは,sample メソッドでハイパーパラメータをランダムに選択する前のハイパーパラメータのリストを返します.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

        new_params = []
+       hp_list = self.params.get_parameter_list()
-       sample = self.params.sample(rng=self._rng)

        for s in sample:

次に正規分布を用いてハイパーパラメータを生成します. aiaccel/parameter.py の HyperParameter クラスでは numpy の random.RandomState.uniform を実行していましたが,今回は正規分布なので numpy の random.RandomState.normal を利用します.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

from __future__ import annotations
from aiaccel.optimizer.abstract_optimizer import AbstractOptimizer


class CustomOptimizer(AbstractOptimizer):
    """An optimizer class with a random algorithm.

    """

    def generate_parameter(self) -> list[dict[str, float | int | str]]:
        """Generate parameters.

        Returns:
            list[dict[str, float | int | str]]: A list of created parameters.
        """
        new_params = []
        hp_list = self.params.get_parameter_list()

        for hp in hp_list:
            value = self._rng.normal(0, 0.1)
            value = min(max(value, hp.lower), hp.upper)
            new_param = {
                'parameter_name': hp.name,
                'type': hp.type,
                'value': value
            }
            new_params.append(new_param)

        return new_params

正規分布で生成したハイパーパラメータが,最大値・最小値を超えないよう修正を加えています.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

            value = min(max(value, hp.lower), hp.upper)
  1. 正規分布オプティマイザの実行確認

それでは現在のディレクトリで実行してみます.

> pwd
/workspace/aiaccel/work/sphere

> aiaccel-start --config config.yaml --clean

正常に終了すれば成功です.

  1. オプティマイザへの変数の導入

正規分布のオプティマイザの平均と分散の値はハードコーディングしていました. このようなオプティマイザに利用する変数はコンフィグレーションファイルや引数として渡したい値です.

ここでは平均と分散をコンフィグレーションファイルから与える方法について解説します.

まずコンフィグレーションファイルに以下の追加をします.

/workspace/aiaccel/work/sphere/config.yaml

optimize:
  search_algorithm: "my_optimizer.CustomOptimizer"
  goal: "minimize"
  trial_number: 30
  rand_seed: 42
+ mu: 3
+ sigma: 0.1

mu と sigma が追加されました. 次に custom_optimizer.py を編集して,mu と sigma を取得できるようにします.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

from aiaccel.optimizer.abstract_optimizer import AbstractOptimizer
import numpy as np


class CustomOptimizer(AbstractOptimizer):
    """An optimizer class with a random algorithm.

    """

    def __init__(self, options: dict) -> None:
        super().__init__(options)
        self.mu = self.config.config.get('optimize', 'mu')
        self.sigma = self.config.config.get('optimize', 'sigma')

init メソッドを追加し,コンフィグレーションから mu と sigma を取得し変数として保持しました. あとは self._rng.normal を呼ぶ際に mu と sigma を渡します.

/workspace/aiaccel/work/lib/my_optimizer/custom_optimizer.py

from aiaccel.optimizer.abstract_optimizer import AbstractOptimizer
import numpy as np


class CustomOptimizer(AbstractOptimizer):
    """An optimizer class with a random algorithm.

    """

    def __init__(self, options: dict) -> None:
        super().__init__(options)
        self.mu = self.config.config.get('optimize', 'mu')
        self.sigma = self.config.config.get('optimize', 'sigma')

    def generate_parameter(self) -> None:
        """Generate parameters.

        Args:
            number (int | None): A number of generating parameters.

        Returns:
            None
        """

        new_params = []
        hp_list = self.params.get_parameter_list()

        for hp in hp_list:
            value = value = self._rng.normal(self.mu, self.sigma)
            value = min(max(value, hp.lower), hp.upper)
            new_param = {
                'parameter_name': hp.name,
                'type': hp.type,
                'value': value
            }
            new_params.append(new_param)

        return new_params

  1. 正規分布オプティマイザの実行確認

それでは現在のディレクトリで実行してみます.

> pwd
/workspace/aiaccel/work/sphere

> aiaccel-start --config config.yaml --clean

/workspace/aiaccel/work/sphere/workディレクトリに実行結果が保存されます. 前回事項した結果と異なることを確認してみてください.

オプティマイザ内部からの目的関数の値の参照

この節では,オプティマイザの内部から過去に計算した目的関数の値を参照して,次のパラメータを決定する方法を確認します. aiaccel 上のジョブの ID が n のときの目的関数の値は,AbstractOptimizer を継承して作成したカスタムオプティマイザの内部から,次のようにして取得できます.

objective_value =  self.storage.result.get_any_trial_objective(n)

この処理の後,objective_valuen で指定した目的関数の値か None を保持します. None が保持されるのは,self.storage.result.get_any_trial_objective() が呼ばれた時点で,目的関数の値を計算する user program が Storage に 計算結果を保存していない場合です.

例: 勾配降下法による最適化

勾配降下法では,着目する試行におけるパラメータが与える目的関数の勾配を元に,次のパラメータを決定します. 一次元の場合, \(n\) 試行目のパラメータを \(W_n\) とし,目的関数を \(f(W_n)\) と書くと, \(n+1\) 試行目のパラメータは

\[ W_{n+1} = W_n + \gamma f'(W_{n}) \]

となります.ここで, \(\gamma\) は学習率 (パラメータの更新をどの程度行うかの指標), \(f'(W_n)\)\(W_n\) における目的関数の勾配です.

ここでは \(f\) の解析的な形が分からない場合に,勾配を差分で置き換えることを考えます. 簡単のため,前進差分のみを考えると,差分を用いた勾配の近似式は

\[f'(W_n) \approx \frac{f(W_n + \delta) - f(W_n) } { \delta }\]

となります. 従って \(n + 1\) 試行目におけるパラメータは

\[W_{n + 1} \approx W_n + \gamma \frac{f(W_n + \delta) - f(W_n) } { \delta }\]

と近似できます.

オプティマイザの実装

上の例では \(n + 1\) 試行目のパラメータを決定するために, \(f(W_n)\)\(f(W_{n+1})\) という 2 つの目的関数の値を使用しました. カスタムオプティマイザでは,これらをメソッド generate_parameter() 内で取得する必要があります. 以下に,前進差分を用いたオプティマイザの例を示します.

from __future__ import annotations
from enum import Enum, auto
import copy

from aiaccel.optimizer.abstract_optimizer import AbstractOptimizer


class SearchState(Enum):
    PREPARE = auto()
    CALC_FORWARD = auto()
    WAIT_CURRENT_OBJECTIVE = auto()
    WAIT_FORWARD_OBJECTIVE = auto()
    CALC_NEXT_PARAM = auto()


class GradientDescent(AbstractOptimizer):
    def __init__(self, options: dict) -> None:
        super().__init__(options)

        self.learning_rate = self.config.config.get(
            'optimize', 'learning_rate')
        self.delta: float = 1e-03

        self.current_id: int = 0
        self.current_params: list[dict[str, str | float]
                                  ] = self.generate_initial_parameter()
        self.num_parameters = len(self.current_params)
        self.forward_objectives: list[float] = []
        self.num_generated_forwards: int = 0
        self.num_calculated_forward_objectives: int = 0
        self.forward_ids: list[int] = []
        self.state: SearchState = SearchState.CALC_FORWARD

    def generate_parameter(self
                           ) -> list[dict[str, str | float]] | None:
        if self.state == SearchState.PREPARE:
            self.current_id = self.current_trial_id - 1
            self.forward_objectives = []
            self.num_generated_forwards = 0
            self.num_calculated_forward_objectives = 0
            self.forward_ids = []

            self.state = SearchState.CALC_FORWARD
            return None

        if self.state == SearchState.CALC_FORWARD:
            new_params = copy.deepcopy(self.current_params)
            param = self.current_params[self.num_generated_forwards]
            forward = {
                'parameter_name': param['parameter_name'],
                'type': param['type'],
                'value': param['value'] + self.delta
            }
            new_params[self.num_generated_forwards] = forward
            self.forward_ids.append(self.current_trial_id)
            self.num_generated_forwards += 1
            if self.num_generated_forwards == self.num_parameters:
                self.state = SearchState.WAIT_CURRENT_OBJECTIVE
            return new_params

        if self.state == SearchState.WAIT_CURRENT_OBJECTIVE:
            self.current_objective = self._get_objective(self.current_id)
            if self.current_objective is not None:
                self.state = SearchState.WAIT_FORWARD_OBJECTIVE
            return None

        if self.state == SearchState.WAIT_FORWARD_OBJECTIVE:
            forward_id = self.forward_ids[
                self.num_calculated_forward_objectives]
            forward_objective = self._get_objective(forward_id)
            if forward_objective is not None:
                self.forward_objectives.append(forward_objective)
                self.num_calculated_forward_objectives += 1
                if (self.num_calculated_forward_objectives ==
                        self.num_parameters):
                    self.state = SearchState.CALC_NEXT_PARAM
            return None

        if self.state == SearchState.CALC_NEXT_PARAM:
            new_params: list[dict[str, str | float]] = []
            for param, forward_objective in zip(self.current_params,
                                                self.forward_objectives):
                grad = (forward_objective - self.current_objective
                        ) / self.delta
                value = param['value'] - self.learning_rate * grad
                new_param = {
                    'parameter_name': param['parameter_name'],
                    'type': param['type'],
                    'value': value
                }
                new_params.append(new_param)
            self.current_params = new_params

            self.state = SearchState.PREPARE
            return new_params

    def _get_objective(self, index):
        return self.storage.result.get_any_trial_objective(index)

    @property
    def current_trial_id(self):
        return self.trial_id.integer

このオプティマイザは以下で説明する 4 つの状態を取ります.

  1. PREPARE: オプティマイザが保持する変数やリストの初期化を行います.

  2. CALC_FORWARD: \(W_n + \delta\) を計算します.

  3. WAIT_CURRENT_OBJECTIVE: Storage に \(W_n\) のときの目的関数の値が保存されるまで待機します.

  4. WAIT_FORWARD_OBJECTIVE: Storage に \(W_n + \delta\) のときの目的関数の値が保存されるまで待機します.

  5. CALC_NEXT_PARAM: \(n+1\) 試行目のパラメータを計算します.

これらの状態を Enum モジュールを用いて実装しています.

class SearchState(Enum):
    PREPARE = auto()
    CALC_FORWARD = auto()
    WAIT_CURRENT_OBJECTIVE = auto()
    WAIT_FORWARD_OBJECTIVE = auto()
    CALC_NEXT_PARAM = auto()

オプティマイザが保持する変数は以下の通りです.

  • learning_rate: 学習率.

  • delta: 目的関数の前進値を計算するための変分 \(\delta\).

  • current_params: 現在 ( \(n\) 試行目) のパラメータ \(W_n\)

  • num_parameters: 最適化するパラメータの数.

  • forward_objectives: \(W_n + \delta\) における目的関数の値 \(f(W_n + \delta)\)

  • num_generated_forwards: 既に生成された \(W_n + \delta\) の数.

  • num_calculated_forward_objectives: 計算が完了した \(f(W_n + \delta)\) の数.

  • forward_ids: \(f(W_n + \delta)\) の計算が実行される aiaccel 上のジョブ ID (trial_id).

generate_parameter() 内の処理の流れ

状態: PREPARE
        if self.state == SearchState.PREPARE:
            self.current_id = self.current_trial_id - 1
            self.forward_objectives = []
            self.num_generated_forwards = 0
            self.num_calculated_forward_objectives = 0
            self.forward_ids = []

            self.state = SearchState.CALC_FORWARD
            return None

オプティマイザが保持する変数やリストの初期化を行います. 初期化を行った後,オプティマイザの状態を PREPARE から CALC_FORWARD に変更します. この状態では,メソッド self.generate_parameters() は必ず None を返却します.

状態: CALC_FORWARD
        if self.state == SearchState.CALC_FORWARD:
            new_params = copy.deepcopy(self.current_params)
            param = self.current_params[self.num_generated_forwards]
            forward = {
                'parameter_name': param['parameter_name'],
                'type': param['type'],
                'value': param['value'] + self.delta
            }
            new_params[self.num_generated_forwards] = forward
            self.forward_ids.append(self.current_trial_id)
            self.num_generated_forwards += 1
            if self.num_generated_forwards == self.num_parameters:
                self.state = SearchState.WAIT_CURRENT_OBJECTIVE
            return new_params

パラメータの前進値 \(W_n + \delta\)1 回の呼び出しで 1 つだけ計算し,aiaccel のメインループに値を返却します.

まず,パラメータのリストから前進値を計算するパラメータを一つずつ取り出します.

            new_params = copy.deepcopy(self.current_params)
            param = self.current_params[self.num_generated_forwards]

ここで self.num_generated_forwards は,既に生成されたパラメータの前進値の総数を表します.

続いて,項目 value\(W_n + \delta\) で置き換えます.

            forward = {
                'parameter_name': param['parameter_name'],
                'type': param['type'],
                'value': param['value'] + self.delta
            }
            new_params[self.num_generated_forwards] = forward

同時に,返却するパラメータの前進値を計算する aiaccel 上のジョブ ID (trial_id) を保持します.

            self.forward_ids.append(self.current_trial_id)

self.current_id は,このカスタムオプティマイザ内で以下のように定義されるプロパティです.

    @property
    def current_trial_id(self):
        return self.trial_id.integer

計算された前進値の数 self.num_generated_forwards をインクリメントします.

            self.num_generated_forwards += 1

全てのパラメータについて,その前進値が計算されたとき,オプティマイザの状態を CALC_FORWARD から WAIT_CURRENT_OBJECTIVE に変更します.

            if self.num_generated_forwards == self.num_parameters:
                self.state = SearchState.WAIT_CURRENT_OBJECTIVE
            return new_params

注意: オプティマイザの状態が CALC_FORWARD のとき,メソッド generate_parameters() は最適化するパラメータの数と同じ回数だけ aiaccel のメインループに呼ばれます.

状態: WAIT_CURRENT_OBJECTIVE
        if self.state == SearchState.WAIT_CURRENT_OBJECTIVE:
            self.current_objective = self._get_objective(self.current_id)
            if self.current_objective is not None:
                self.state = SearchState.WAIT_FORWARD_OBJECTIVE
            return None

現在のパラメータ \(W_n\) における目的関数の値 \(f(W_n)\) が Storage に保存されるまで待ち,その値を取得します.

            self.current_objective = self._get_objective(self.current_id)

self._get_objective()カスタムオプティマイザ内で以下のように定義されるメソッドです.

    def _get_objective(self, index):
        return self.storage.result.get_any_trial_objective(index)

このメソッドは,取得したい目的関数の値の trial_id (aiaccel 上のジョブ ID) を引数に取り,Storage から値を読み出します. ただし,呼び出された時点で Storage に値が保存されていなければ,None を返却します.

メソッド self._get_objective() が目的関数の値を返した場合,オプティマイザの状態を WAIT_CURRENT_OBJECTIVE から WAIR_FORWARD_OBJECTIVE に変更します. この時点で, \(f(W_n)\) の値はメンバ変数 self.current_objective に保持されています.

            if self.current_objective is not None:
                self.state = SearchState.WAIT_FORWARD_OBJECTIVE

注意: オプティマイザが状態 WAIT_CURRENT_OBJECTIVE のとき,メソッド self.generate_parameters() は 1 回以上,Storage に対象とする目的関数の値が保存されるまで呼ばれます. また,Storage から目的関数の値を読み出せたか否かに関わらず,WAIT_CURRENT_OBJECTIVE 状態の self.generate_parameters()None をメインループに返します.

状態: WAIT_FORWARD_OBJECTIVE
        if self.state == SearchState.WAIT_FORWARD_OBJECTIVE:
            forward_id = self.forward_ids[
                self.num_calculated_forward_objectives]
            forward_objective = self._get_objective(forward_id)
            if forward_objective is not None:
                self.forward_objectives.append(forward_objective)
                self.num_calculated_forward_objectives += 1
                if (self.num_calculated_forward_objectives ==
                        self.num_parameters):
                    self.state = SearchState.CALC_NEXT_PARAM
            return None

パラメータの前進値 \(W_{n} + \delta\) における目的関数の値 \(f(W_n + \delta)\) が Storage に保存されるのを待ち,その値を取得します.

まず,取得する目的関数の aiaccel 上のジョブ ID (trial_id) をリストから読み出します.

            forward_id = self.forward_ids[
                self.num_calculated_forward_objectives]

ここで,self.num_calculated_forward_objectives は取得済みの前進値に対する目的関数の値の総数です.

続いて,メソッド self._get_objective() に読み出した ID を渡して,Storage から目的関数の値を読み出します.

            forward_objective = self._get_objective(forward_id)

正常な値が返却された場合,返却された値をリストに保持し,取得済みの値の総数 self.num_calculated_forward_objectives をインクリメントします.

            if forward_objective is not None:
                self.forward_objectives.append(forward_objective)
                self.num_calculated_forward_objectives += 1

このとき,すべての目的関数の値が取得できていれば,オプティマイザの状態を WAIT_FORWARD_OBJECTIVE から CALC_NEXT_PARAM に変更します.

                if (self.num_calculated_forward_objectives ==
                        self.num_parameters):
                    self.state = SearchState.CALC_NEXT_PARAM

注意: オプティマイザが状態 WAIT_FORWARD_OBJECTIVE のとき,メソッド self.generate_parameters() は少なくとも最適化対象のパラメータの総数以上,Storage にすべての目的関数の値が保存されるまで呼ばれます.また,Storage から目的関数の値が読み出せたか否かや,すべての値の読み出しが完了したか否かに依らず,WAIT_FORWARD_OBJECTIVE 状態の self.generate_parameters()None をメインループに返します.

状態: CALC_NEXT_PARAM
        if self.state == SearchState.CALC_NEXT_PARAM:
            new_params: list[dict[str, str | float]] = []
            for param, forward_objective in zip(self.current_params,
                                                self.forward_objectives):
                grad = (forward_objective - self.current_objective
                        ) / self.delta
                value = param['value'] - self.learning_rate * grad
                new_param = {
                    'parameter_name': param['parameter_name'],
                    'type': param['type'],
                    'value': value
                }
                new_params.append(new_param)
            self.current_params = new_params

            self.state = SearchState.PREPARE
            return new_params

Storage から読み出した \(W_n\) における目的関数の値 \(f(W_n)\) (self.current_params) と \(W_{n+1}\) における目的関数の値 \(f(W_{n+1})\) (self.forward_objectives) を用いて勾配を計算します.

            new_params: list[dict[str, str | float]] = []
            for param, forward_objective in zip(self.current_params,
                                                self.forward_objectives):
                grad = (forward_objective - self.current_objective
                        ) / self.delta

計算した勾配を用いて次のパラメータ \(W_{n+1}\) を計算して dict 型オブジェクトを作成し,リストに保持します.

                value = param['value'] - self.learning_rate * grad
                new_param = {
                    'parameter_name': param['parameter_name'],
                    'type': param['type'],
                    'value': value
                }
                new_params.append(new_param)

オプティマイザの状態を CALC_NEXT_PARAM から PREPARE に変更し,作成した次のパラメータをメインループに返却します.

            self.state = SearchState.PREPARE
            return new_params

注意事項

一般に,パラメータの更新ステップ数 \(n\) と aiaccel 上のジョブ ID (trial_id) は一致しないことに注意してください. 例えば上の例において,最適化したいパラメータの数が 5 個の場合,パラメータを1度更新するために目的関数を 5 回計算する必要があります. この場合は 1 回のパラメータ更新で aiaccel の trial_id は 5 増加することになります. 従って,config.yaml で指定した trial_number が,例えば 30 回の場合,初期値を除いて 4 回しかパラメータは更新されません.

同様な ID の不一致は NelderMeadOptimizer を用いた際にも起こります. Nelder-Mead 法の 1 ステップに相当する処理が終了したとき,aiaccel 上では trial_idパラメータ数 + 1 だけ増加します.

Issues

問題を発見した場合や追加機能の要望がある場合,すでに同様の issue が投稿されていないかの確認をお願いします. 同様のテーマが話し合われていない場合,新しい issue を作成してください.

バグの報告 (Bug report)

バグの報告では,以下の内容についての明確かつ簡潔な説明を含めてください.

  • バグの内容

  • バグを再現する手順

  • あなたが起こると期待したこと

  • 実行環境

機能リクエスト (Feature request)

機能リクエストを行う際には,以下の内容についての明確かつ簡潔な説明を含めることを推奨します.

  • バグが関連する場合,バグの内容

  • 実現したい機能の説明

  • 検討した実装の説明

Pull request

aiaccel のコードを修正しリポジトリに反映して欲しい場合,pull request を実行してください. Pull request を行う際には,以下に注意してください.

手順

初めて開発に参加する場合

  • まず,GitHub 上で aiaccel をフォークします.

  • フォークした後,aiaccel のリポジトリを clone します.

    git clone https://github.com/[YOUR USERNAME]/aiaccel.git
    

開発

  • ローカルのリポジトリを最新の状態に更新します.

    git checkout main
    git pull upstream main
    
  • ブランチを作成します.

    git checkout -b feature/add-new-feature
    
  • git add および git commit を使用し,進行に合わせてローカルでコミットします.

    • コミットメッセージでは,変更の動機,バグの性質,または拡張機能の詳細を説明します.

    • メッセージは,コードを見なくても内容を理解できるように記述する必要があります.

投稿

Pull request を行う前に,以下を確認してください

  • 事前に issue などで他の開発者と議論したか?

  • MIT ライセンスで配布できるか?

  • 適切なユニットテストは存在するか?

  • ユニットテストをローカル環境で実行できたか?

  • パブリックな関数は docstring を持っているか?

  • ドキュメンテーションは正しくレンダリングされるか?

  • コーディングスタイルは適切か?

  • コミットメッセージは適切か?

  • 大規模な追加の場合,例 (docs/source/examples) やモジュールレベルの説明はあるか?

  • コンパイル済みのコードを追加する場合,setup.py を変更したか?

上記を確認した後:

  • GitHub 上のフォークに変更をプッシュします.

    git push origin feature/add-new-optimizer
    
  • GitHub のユーザーネームとパスワードを入力します.

  • GitHub に移動します.以下に注意しながらタイトルとメッセージを記述します.

    • タイトル

      • 変更を反映した簡単な説明を行うこと.

      • コードはバックフォートでラップすること.

      • ピリオドで終了しないこと.

    • 説明

      • 動機を書くこと.

      • 変更点を書くこと.

      • 関連する issue を閉じることができる場合,Close #N で issue を閉じること.

      • 作業が進行中 (work-in-progress) であるなら,残りのタスクを書くこと.

  • Pull request を送信します.

レビュープロセス

  • 他の開発者は,pull request の実装,ドキュメント,コーディングスタイルを改善するためのコメントを投稿します.

  • Pull request したコードの更新を行う際は,ローカルリポジトリで変更をコミットし,ローカル環境でのテストが成功した場合にのみフォークへプッシュします.

  • aiaccel の開発チームのメンバー 1 人以上が pull request を検証し,承認された場合に main ブランチへマージされます.

ドキュメンテーション (WIP)

docstrings

  • 実装した関数の基本的な説明,パラメータや返却値の型と意味,使用例を docstrings として記述します.

  • Google Python Style Guide に準拠する形で記述してください.

  • コーディング規約 も参考にしてください.

ドキュメント

  • ドキュメントのソースファイルは docs の下のディレクトリに作成します.

  • ドキュメントのファイル形式はマークダウン形式を推奨しています.

  • 大規模な機能の追加があった場合,ドキュメントを作成してください.

レンダリングの確認

ドキュメントの追加や変更・修正があった場合には,ローカル環境でレンダリングが正常に行われるかを確認してください.

API リファレンスの生成を行うには,aiaccel に移動し,以下のコマンドを実行します.

cd aiaccel
sphinx-apidoc -f -o docs/source/api_reference aiaccel

ドキュメンテーションのレンダリングを確認するには,aiaccel/docs に移動し,HTML ファイルのビルドを行います.

cd docs
make html

ビルドされた HTML 形式のファイルは docs/build/html の下に生成されます.

多言語ドキュメントの生成を行うには,aiaccel/docs で以下のコマンドを実行します.

make gettext
sphinx-intl update -p build/gettext -l en -l ja

テスト

テストの追加

  • aiaccel では pytest を用いてテストを行います.

  • ユニットテストは tests の下のディレクトリに作成します.

    • aiaccel/tests/unit 以下のディレクトリ構造は,config.py などの一部のモジュールを除いて,aiaccel/aiaccel 以下の構造に対応します. 例えば,aiaccel/aiaccel/optimizer/abstract_optimizer.py のテストは aiaccel/tests/unit/optimzier_test/test_abstract_optimizer.py です.

  • 新たな機能の追加,またはバグの修正を行った場合,テストコードを作成してください.

テストの実行 (WIP)

ローカル環境ですべてのテストコードを実行するには,aiaccel に移動し,以下のコマンドを実行します.

cd aiaccel
pytest

特定のテストコードのみを実行したい場合には,ファイル名を引数として指定します.

pytest tests/unit/optimizer_test/test_abstract_optimizer.py

さらに,コーディングスタイルのチェックを行うため,以下のコマンドを実行します.

pycodestyle aiaccel examples
flake8 aiaccel examples 

追加コードに対するカバレッジ

コードカバレッジの厳密な基準は設定されていませんが,テストを設計する際にはこの値を十分に考慮します. 特に,以下のような場合は注意が必要です.

  • 全体的なスコアが大幅に低下する場合.

  • あるクラスやモジュールのカバレッジが異常に低い場合.

  • テストが if 文の特定の分岐をカバーしていない場合.

カバレッジの測定

C0 カバレッジを測定するには,オプション --cov を使用して pytest を実行します.

pytest --cov=aiaccel

特定のテストコードのみのカバレッジを測定するには,aiaccel の部分を適切なパスに置き換えます.

C1 カバレッジを測定するには,オプション --cov に加えて --cov-branch を使用して pytest を実行します.

pytest --cov=aiaccel --cov-branch

コーディング規約

基本的なルール

  • aiaccel のソースコードは Python で作成します.

  • コーディングスタイルは PEP8 に従います.

    • aiaccel では pycodestyle と flake8 を用いてコーディングスタイルの検証を行います.

    • 下記の Docstrings についても確認してください.

  • aiaccel では型ヒントの検証は行いませんが,できる限り型ヒントを記述してください.

    • aiaccel ではバージョン 3.8 の Python をサポートするため,ビルトインな “list” などを型ヒントに使用する際は,future-import を行ってください.

  • ランダムな値の生成には numpy.random.RandomState を使用して下さい.これは aiaccel が利用しているライブラリ optuna との互換性を保つためです.

Docstrings

基本的には Google Python Style Guide に準拠する形で docstrings を記述します. ただし,以下の例外についても注意してください.

  • 各モジュールの docstrings は必須ではありません.

  • Args: セクションでは,パラメータ名の後ろにパラメータの型を括弧で括って記述します.

  • 必要に応じて Example: セクションを追加します.

  • __init__ メソッドはクラスの docstring に含めます.__init__ メソッドには記述しません.

  • Python オブジェクトへのリンクは sphinx-style なリンクを使用します.

  • エディタとして vscode を利用する場合,autoDocstring が docstring 生成の役に立ちます.

Example

class ExampleClass:
    """Summary of class.

    There can be additional description(s) of this class.

    Args:
        param1 (type_of_param1): Description of `param1` which
            is given when __init__ method is called.
        param2 (type_of_param2): Description of `param2`.

    Attributions:
        param1 (type_of_param1): Description of `param1`.
        param2 (type_of_param2): Description of `param2`.
        param3 (type_of_param3): Description of 'param3`. 
    """

    def __init__(self, param1: type_of_param1, param2: type_of_param2):
        self.param1 = param1
        self.param2 = param2
        self.param3 = generate_param3()

    def method(self, arg1: type_of_arg1) -> type_of_return:
        """Recieves `type_of_arg1` object and returns return_of_method. 

        Args:
            arg1 (type_of_arg1): Description of `arg1`.
        
        Returns:
            type_of_return: Description of return value. If this method
            returns nothing, this section can be omitted.
        
        Raise:
            TypeOfException: Description of Exception.

        """
        ...
        return return_of_method

qsubで実行中の計算ノードでコマンドを実行する方法

qsubで実行中の計算ノードでコマンドを実行する方法を説明します。

参照資料
インタラクティブノードからのqrsh -inherit

テスト時のqsub.sh

#!/bin/bash

#$ -l rt_C.small=1
#$ -l h_rt=1:00:00
#$ -j y
#$ -cwd

sleep 3600

テスト時のコマンド

> qsub -g your_group_id qsub.sh
Your job 10607396 ("qsub.sh") has been submitted

> qstat  # with some omissions
job-ID    prior  name     user  state  submit/start at  queue
10608572  prior  qsub.sh  user  r      submit/start at  gpu@g0001

> JOB_ID=10608572 SGE_TASK_ID=undefined qrsh -inherit g0001 /bin/bash

promptが表示されませんが、例えば、

> ls

とコマンドを入力すると、結果が出力されます。

終了時は必ず

> exit

/bin/bashなどのshellの場合の注意事項

  1. キーボードからのControl-Cで、job自体の実行が停止されるようです。
    そのため、終了には、exitコマンドを使用して下さい。

  2. コマンドプロンプトが出ないようです。
    違和感が有りますが、コマンド-Enterでコマンドを実行できます。

  3. 使用できないコマンド、出力が通常と違うコマンドが有ります。

SGE_LOCALDIRを定期的にHOMEなどにrsyncする方法

qsubで実行中の計算ノードの\(SGE_LOCALDIRの内容を\)HOMEなどに定期的にrsyncする方法を説明します。

ユーザプログラムが終了した後に、再度1度だけrsyncしています。

テスト時のqsub.sh

#!/bin/bash

#$ -l rt_C.small=1
#$ -l h_rt=1:00:00
#$ -j y
#$ -cwd

source /etc/profile.d/modules.sh
module load gcc/11.2.0
module load python/3.8/3.8.13

python3 rsync.py loop &
python3 test.py
kill $!
sleep 1
python3 rsync.py

テスト時のrsync.py

import os
import subprocess
import sys
import signal
import time

sleep_time = 15
src_dir = os.environ['SGE_LOCALDIR']
dst_dir = '~/test_rsync_dir'
proc = None


def do_rsync():
    global proc
    proc = subprocess.Popen(f'exec rsync -avh {src_dir}/ {dst_dir}', shell=True)
    proc.wait()


def handler(signum, frame):
    if proc is not None:
        proc.terminate()
    sys.exit()


signal.signal(signal.SIGTERM, handler)
a = sys.argv
if len(a) == 2 and a[1] == 'loop':
    while True:
        time.sleep(sleep_time)
        do_rsync()
else:
    do_rsync()

テスト時のユーザプログラムtest.py

import os
import pathlib
import time

sleep_time = 5
src_path = pathlib.Path(os.environ['SGE_LOCALDIR'])


for i in range(10):
    (src_path/f'{i}-touch.txt').touch()
    time.sleep(sleep_time)

テスト時のコマンド

> cd your_directory  # with the above three files

> qsub -g your_group_id qsub.sh

# After the end

> ls ~/test_rsync_dir
0-touch.txt  2-touch.txt  4-touch.txt  6-touch.txt  8-touch.txt
1-touch.txt  3-touch.txt  5-touch.txt  7-touch.txt  9-touch.txt

> vi your_qsub_output_file

テスト時のvi your_qsub_output_fileの表示結果

sending incremental file list
created directory /your_home_directory/test_rsync_dir
./
0-touch.txt
1-touch.txt
2-touch.txt
3-touch.txt

sent 347 bytes  received 149 bytes  992.00 bytes/sec
total size is 0  speedup is 0.00
sending incremental file list
./
4-touch.txt
5-touch.txt
6-touch.txt

sent 386 bytes  received 76 bytes  924.00 bytes/sec
total size is 0  speedup is 0.00
sending incremental file list
./
7-touch.txt
8-touch.txt
9-touch.txt

sent 464 bytes  received 76 bytes  360.00 bytes/sec
total size is 0  speedup is 0.00
sending incremental file list

sent 340 bytes  received 12 bytes  704.00 bytes/sec
total size is 0  speedup is 0.00

リファレンス(WIP)

参考文献(WIP)

参照(WIP)

引用(WIP)

aiaccel

aiaccel package

Subpackages

aiaccel.abci package
Submodules
aiaccel.abci.batch module
aiaccel.abci.batch.create_abci_batch_file(batch_file: pathlib.Path, wrapper_file: str, commands: list, dict_lock: pathlib.Path) None

Create a ABCI batch file.

The ‘wrapper_file’ is a base of the ABCI batch file. At first, loads ‘wrapper_file’, and adds the ‘commands’ to the loaded contents. Finally, writes the contents to ‘batch_file’.

Parameters
  • batch_file (Path) – A path of a creating file.

  • wrapper_file (str) – A wrapper file of ABCI batch file.

  • commands (list) – Commands to write in a batch file.

  • dict_lock (Path) – A directory to store lock files.

Returns

None

aiaccel.abci.qstat module
aiaccel.abci.qstat.parse_job_list(config: Config, job_list: Element) list[dict]

Parse from XML element of ‘qstat’ to a job list.

Parameters
  • config (Config) – A Config object.

  • job_list (Element) – A XML element of ‘qstat’ command.

Returns

A job list converted from a XML element of ‘qstat’ command.

Return type

list

aiaccel.abci.qstat.parse_qstat(config: Config, qstat: str) list[dict]

Parse ABCI ‘qstat’ command result.

Parameters
  • config (Config) – A Config object.

  • qstat (str) – A ‘qstat’ result.

Returns

A parsed job list from ABCI ‘qstat’ command.

Return type

list[dict]

aiaccel.abci.qsub module
aiaccel.abci.qsub.create_qsub_command(config: Config, runner_file: Path) list[str]

Create ABCI ‘qsub’ command.

Parameters
  • config (Config) – A Config object.

  • runner_file (Path) – A path of ‘qsub’ batch file.

Returns

A list to run ‘qsub’ command.

Return type

list

Module contents
aiaccel.cli package
Submodules
aiaccel.cli.plot module
aiaccel.cli.report module
aiaccel.cli.start module
aiaccel.cli.view module
Module contents
aiaccel.master package
Subpackages
aiaccel.master.evaluator package
Submodules
aiaccel.master.evaluator.abstract_evaluator module
aiaccel.master.evaluator.maximize_evaluator module
aiaccel.master.evaluator.minimize_evaluator module
Module contents
aiaccel.master.verification package
Submodules
aiaccel.master.verification.abstract_verification module
Module contents
Submodules
aiaccel.master.abci_master module
aiaccel.master.abstract_master module
aiaccel.master.create module
aiaccel.master.local_master module
aiaccel.master.pylocal_master module
Module contents
aiaccel.optimizer package
Submodules
aiaccel.optimizer.abstract_optimizer module
aiaccel.optimizer.create module
aiaccel.optimizer.grid_optimizer module
aiaccel.optimizer.nelder_mead_optimizer module
aiaccel.optimizer.random_optimizer module
aiaccel.optimizer.sobol_optimizer module
aiaccel.optimizer.tpe_optimizer module
Module contents
aiaccel.storage package
Submodules
aiaccel.storage.abstract module
class aiaccel.storage.abstract.Abstract(file_name: pathlib.Path)

Bases: object

create_session() Generator[sqlalchemy.orm.session.Session, None, None]
aiaccel.storage.error module
class aiaccel.storage.error.Error(file_name: pathlib.Path)

Bases: aiaccel.storage.abstract.Abstract

all_delete() None

Clear table

Returns

None

delete_any_trial_error(trial_id: int) None
Returns

None

get_any_trial_error(trial_id: int) str | None

Get error messages for any trial.

Parameters

trial_id (int) – Any trial id

Returns

Return type

str | None

get_error_trial_id() list

Obtain a list of trial ids in which an error occurred.

Returns

trial id list

Return type

trial_ids(list)

set_any_trial_error(trial_id: int, error_message: str) None

Set any error message for any trial.

Parameters
  • trial_id (int) – Any trial id

  • error_message (str) – Any error message

Returns

None

aiaccel.storage.hp module
class aiaccel.storage.hp.Hp(file_name: pathlib.Path)

Bases: aiaccel.storage.abstract.Abstract

all_delete() None

Clear table

Returns

None

delete_any_trial_params(trial_id: int) None
Returns

None

get_any_trial_params(trial_id: int) list[HpTable] | None

Obtain the set parameter information for any given trial.

Parameters

trial_id (int) – Any trial id.

Returns

Return type

list[HpTable] | None

set_any_trial_param(trial_id: int, param_name: str, param_value: Any, param_type: str) None

Set the specified parameter information for an any trial.

Parameters
  • trial_id (int) – Any trial id

  • param_name (str) – Hyperparameter name.

  • param_value (Any) – Hyperparameter value

  • param_type (str) – Hyperparameter data type

Returns

TrialTable | None

set_any_trial_params(trial_id: int, params: list) None
aiaccel.storage.jobstate module
class aiaccel.storage.jobstate.JobState(file_name: pathlib.Path)

Bases: aiaccel.storage.abstract.Abstract

delete_any_trial_jobstate(trial_id: int) None
Returns

None

get_all_trial_jobstate() list
get_any_trial_jobstate(trial_id: int) str | None

Get the job status of any trial.

Parameters

trial_id (int) – Any trial id

Returns

Some kind of jobstate

Return type

str | None

is_failure(trial_id: int) bool

Whether the jobstate of the specified trial is Failuer or not.

Parameters

trial_id (int) – Any trial id

Returns

bool

set_any_trial_jobstate(trial_id: int, state: str) None

Set the specified jobstate to the specified trial.

Parameters
  • trial_id (int) – Any trial id

  • state (str) – Any jobstate

Returns

None

set_any_trial_jobstates(states: list) None

Set the specified jobstate to the specified trial.

Parameters
  • trial_id (int) – Any trial id

  • state (str) – Any jobstate

Returns

None

aiaccel.storage.model module
class aiaccel.storage.model.ErrorTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

error
trial_id
class aiaccel.storage.model.HpTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

param_id
param_name
param_type
param_value
trial_id
class aiaccel.storage.model.JobStateTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

state
trial_id
class aiaccel.storage.model.ResultTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

data_type
objective
trial_id
class aiaccel.storage.model.TimestampTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

end_time
start_time
trial_id
class aiaccel.storage.model.TrialTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

state
trial_id
class aiaccel.storage.model.VariableTable(**kwargs)

Bases: sqlalchemy.orm.decl_api.Base

data_id
label
process_name
trial_id
value
aiaccel.storage.result module
class aiaccel.storage.result.Result(file_name: pathlib.Path)

Bases: aiaccel.storage.abstract.Abstract

all_delete() None

Clear table

Returns

None

delete_any_trial_objective(trial_id: int) None

_summary_

Parameters

trial_id (int) – _description_

Raises

e – _description_

get_all_result() list

Get all results

Returns

list

get_any_trial_objective(trial_id: int) int | float | None

Obtain the results of an arbitrary trial.

Parameters

trial_id (int) – Any trial id

Returns

Return type

int | float | None

get_bests(goal: str) list

Obtains the sorted result.

Returns

result values

Return type

list

get_objectives() list

Get all results in list.

Returns

result values

Return type

list

get_result_trial_id_list() list | None

Obtains the sorted result.

Returns

result values

Return type

list | None

set_any_trial_objective(trial_id: int, objective: Any) None

Set any trial result value.

Parameters
  • trial_id (int) – Any trial id

  • objective (Any) – ready, running, finished

Returns

None

aiaccel.storage.storage module
aiaccel.storage.timestamp module
class aiaccel.storage.timestamp.TimeStamp(file_name: pathlib.Path)

Bases: aiaccel.storage.abstract.Abstract

all_delete() None

Clear table

Returns

None

delete_any_trial_timestamp(trial_id) None
get_any_trial_end_time(trial_id: int) str | None

Obtains the end time of the specified trial.

Parameters

trial_id (int) – Any trial id

Returns

“MM/DD/YYYY hh:mm:ss”

Return type

end_time(str)

get_any_trial_start_time(trial_id: int) str | None

Obtains the start time of the specified trial.

Parameters

trial_id (int) – Any trial id

Returns

“MM/DD/YYYY hh:mm:ss”

Return type

start_time(str)

set_any_trial_end_time(trial_id: int, end_time: str) None

Set the specified end time for the specified trial.

Parameters
  • trial_id (int) – Any trial id

  • end_time (str) – “MM/DD/YYYY hh:mm:ss”

Returns

None

set_any_trial_start_time(trial_id: int, start_time: str) None

Set the specified start time for the specified trial.

Parameters
  • trial_id (int) – Any trial id

  • start_time (str) – “MM/DD/YYYY hh:mm:ss”

Returns

None

aiaccel.storage.trial module
aiaccel.storage.variable module
class aiaccel.storage.variable.Serializer(file_name: pathlib.Path)

Bases: object

delete_any_trial_variable(trial_id) None
register(process_name: str, labels: list) None
class aiaccel.storage.variable.Value(file_name: pathlib.Path, label: str)

Bases: aiaccel.storage.variable.Variable

delete(trial_id: int) None
get(trial_id: int) Any | None
set(trial_id: int, value: Any, update_allow: bool = True) None
set_process_name(process_name: str) None
class aiaccel.storage.variable.Variable(file_name: pathlib.Path)

Bases: aiaccel.storage.abstract.Abstract

all_delete() None

Clear table

Returns

None

delete_any_trial_variable(trial_id: int, process_name: str, label: str) None
get_any_trial_variable(trial_id: int, process_name: str, label: str)
set_any_trial_variable(trial_id: int, process_name: str, label: str, value: Any, update_allow: bool)
Module contents

Submodules

aiaccel.common module

Common variables and methods.

  • Import this as follows:

  • import aiaccel

aiaccel.config module

class aiaccel.config.BaseConfig

Bases: object

An interface for all config classes.

Fork by confile: https://github.com/777nancy/confile

abstract get_property(key, *keys)
abstract to_dict()
class aiaccel.config.Config(config_path: str | Path, warn: bool = False, format_check: bool = False)

Bases: object

Defines the configuration of a configuration file.

Parameters
  • config_path (str | Path) – A path of configuration file.

  • warn (bool, optional) – A flag of print a warning or not. Defaults to False.

  • format_check (bool, optional) – A flag of do tha check format or not. Defaults to None.

config_path

Path to the configuration file.

Type

Path

config
Type

ConfileWrapper

workspace
Type

ConfigEntry

define_items(config: aiaccel.config.ConfileWrapper, warn: bool) None

Define the configuration of the configuration file

Parameters
  • config (ConfileWrapper) –

  • warn (bool) – A flag of print a warning or not. Defaults to False.

class aiaccel.config.ConfigEntry(config: ConfileWrapper, type: list, default: Any, warning: bool, group: str, keys: list | tuple | str)

Bases: object

A class for defining values in a configuration file or for holding read values.

Parameters
  • config_path (str) – A path of configuration file.

  • type (list) – A data type.

  • default (Any) – A default value.

  • warning (bool) – A flag of print a warning or not.

  • group (str) – A name of the group to which the parameter belongs.

  • keys (tuple) – A key to access the value For example, a parameter under ‘generic’ would be written as (‘generic’)

Example

workspace = ConfigEntry(
    config=config,
    type=[str],
    default=_DEFAULT_WORKSPACE,
    warning=warn,
    group="generic",
    keys=("workspace")
)
workspace.get()
property Value
empty_if_error()

If the value is not set, it will force an error to occur.

get() Any
Returns

self._value

load_config_values()

Reads values from the configuration file.

set(value) None
Args

value (any)

show_warning() None

If the default value is used, a warning is displayed.

class aiaccel.config.ConfileWrapper(config: Any, config_type: str)

Bases: object

A wrapper class for confile library.

Thins wrapper class supports to load a configuration file in JSON object, JSON file and YAML format. It provides a simple method ‘get’ to get a property for the specified keys.

Parameters
  • config (Any) – A file path to configuration file.

  • config_type (str) – A file path to default configuration file.

get(key: str, *keys: str) str | list | dict | None

Get a property with specified keys.

Parameters
  • key (str) – A key for the property

  • *keys (list) – Nested eys for the property

Returns

A property for the specified keys.

Return type

str | list | dict | None

class aiaccel.config.JsonOrYamlObjectConfig(config: dict, file_type: str)

Bases: aiaccel.config.BaseConfig

A wrapper for confile to support json, yaml object.

Fork by confile: https://github.com/777nancy/confile

Parameters
  • config (dict) – A json or yaml object

  • file_type (str) – ‘json_object’ or ‘yaml_object’.

get_property(key: str, *keys: str) str | list | dict | None

Get a property for specified keys.

Parameters
  • key (str) – A key to get a property.

  • *keys (str) – Keys to get a property.

Returns

A property for the keys.

Return type

str | list | dict | None

to_dict() dict

Convert the configuration to a dictionary object.

Returns

The dictionary object of the configuration.

Return type

dict

aiaccel.config.load_config(config_path: str) aiaccel.config.ConfileWrapper

Load any configuration files, return the ConfileWrapper object. :param config_path: A path to a configuration file. :type config_path: str

Returns

A wrapper object of the configuration.

Return type

ConfileWrapper

aiaccel.module module

aiaccel.parameter module

class aiaccel.parameter.HyperParameter(parameter: dict[str, bool | int | float | list])

Bases: object

A hyper parameter class.

Parameters

parameter (dict) – A parameter dictionary in a configuration file.

_raw_dict

A parameter dictionary in a configuration file.

Type

dict

name

A parameter name.

Type

str

type

A parameter type any of ‘INT’, ‘FLOAT’, ‘CATEGORICAL’ and ‘ORDINAL’.

Type

str

log

A parameter is logarithm or not.

Type

bool

lower

A lower value of a parameter.

Type

float | int

upper

A upper value of a parameter.

Type

float | int

choices

This is set as a list of a parameter, when a parameter type is ‘CATEGORICAL’.

Type

list[float, int, str]

sequence

This is set as a list of a parameter, when a parameter type is ‘ORDINAL’.

Type

list[float, int, str]

initial

A initial value. If this is set, this value is evaluated at first run.

Type

float | int | str

q

A quantization factor.

Type

float | int

sample(initial: bool = False, rng: Optional[numpy.random.mtrand.RandomState] = None) dict

Sample a parameter.

Parameters
  • initial (bool) – This is set, when a initial value is required.

  • rng (np.random.RandomState) – A reference to a random generator.

Returns

A parameter dictionary.

Return type

dict

Raises

TypeError – Causes when an invalid type is set.

class aiaccel.parameter.HyperParameterConfiguration(json_string: dict)

Bases: object

A configuration of hyper parameters.

Parameters

json_string (dict) – A configuration dictionary of hyper parameters.

json_string

A configuration dictionary of hyper parameters.

Type

dict

hps

Hyper parameters.

Type

dict

get_hyperparameter(name: str) aiaccel.parameter.HyperParameter

Get a hyper parameter with a name.

Parameters

name (str) – A hyper parameter name.

Returns

A matched hyper parameter object.

Return type

HyperParameter

Raises

KeyError – Causes when no matched hyper parameter is.

get_parameter_dict() dict

Get a dictionary of hyper parameters.

Returns

A hyper parameter dictionary.

Return type

dict

get_parameter_list() list[HyperParameter]

Get a list of hyper parameter objects.

Returns

A list of hyper parameter objects.

Return type

list[HyperParameter]

sample(initial: bool = False, rng: np.random.RandomState = None) list[dict]

Sample a hyper parameters set.

Parameters
  • initial (bool, optional) – This is set, when a initial value is required.

  • rng (np.random.RandomState) – A reference to a random generator.

Returns

A hyper parameters set.

Return type

list[dict]

aiaccel.parameter.get_best_parameter(files: list[Path], goal: str, dict_lock: Path) tuple[float | None, Path | None]

Get a best parameter in specified files.

Parameters
  • files (list[Path]) – A list of files to find a best.

  • goal (str) – Maximize or Minimize.

  • dict_lock (Path) – A directory to store lock files.

Returns

A best result value and a file path. It returns None if a number of files is less than one.

Return type

tuple[float | None, Path | None]

Raises

ValueError – Causes when an invalid goal is set.

aiaccel.parameter.get_type(parameter: dict) str

Get a type of a specified parameter.

Parameters

parameter (dict) – A parameter dictionary in a configuration file.

Returns

A parameter type any of ‘INT’, ‘FLOAT’, ‘CATEGORICAL’ and ‘ORDINAL’.

Return type

str

aiaccel.parameter.load_parameter(json_string: dict) aiaccel.parameter.HyperParameterConfiguration

Load HyperParameterConfiguration object from a configuration file.

Parameters

json_string (dict) – A hyper parameter configuration.

Returns

A hyper parameter configuration.

Return type

HyperParameterConfiguration

aiaccel.workspace module

class aiaccel.workspace.Workspace(base_path: str)

Bases: object

Provides interface to workspace.

Parameters

base_path (str) – Path to the workspace.

path

Path to the workspace.

Type

Path

alive

Path to “alive”, i.e. path/alive.

Type

Path

error

Path to “error”, i.e. ‘path`/error.

Type

Path

hp

Path to “hp”, i.e. path/hp.

Type

Path

hp_ready

Path to “ready”, i.e. path/hp/ready.

Type

Path

hp_running

Path to “running”, i.e. path/hp/running.

Type

Path

hp_finished

Path to “finished”, i.e. path/hp/finished.

Type

Path

jobstate

Path to “jobstate”, i.e. path/jobstate.

Type

Path

lock

Path to “lock”, i.e. path/lock.

Type

Path

log

Path to “log”, i.e. path/log.

Type

Path

output

Path to “abci_output”, i.e. path/abci_output.

Type

Path

pid

Path to “pid”, i.e. path/pid.

Type

Path

result

Path to “result”, i.e. path/result.

Type

Path

runner

Path to “runner”, i.e. path/runner.

Type

Path

storage

Path to “storage”, i.e. path/storage.

Type

Path

timestamp

Path to “timestamp”, i.e. path/timestamp.

Type

Path

verification

Path to “verification”, i.e. path/verification.

Type

Path

consists

A list of pathes under the workspace.

Type

list[Path]

results

Path to the results which is prepared in the execution directory, i.e. “./results”.

Type

Path

check_consists() bool

Check required directories exist or not.

Returns

All required directories exist or not.

Return type

bool

clean() None

Delete a workspace.

It is assumed to be the first one to be executed.

create() bool

Create a work directory.

Returns

None

Raises

NotADirectoryError – It raises if a workspace argument (self.path) is not a directory.

exists() bool

Returns whether workspace exists or not.

Returns

True if the workspace exists.

Return type

bool

move_completed_data() Path | None

Move workspace to under of results directory when finished.

Raises

FileExistsError – Occurs if destination directory already exists when the method is called.

Returns

Path of destination.

Return type

Path | None

aiaccel.wrapper_tools module

aiaccel.wrapper_tools.create_runner_command(command: str, param_content: dict, trial_id: int, config_path: str, command_error_output: str) list[str]

Create a list of command strings to run a hyper parameter.

Parameters
  • command (str) – A string command.

  • param_content (dict) – A hyper parameter content.

  • trial_id (str) – A unique name of a hyper parameter.

Returns

A list of command strings.

Return type

list[str]

aiaccel.wrapper_tools.save_result(ws: pathlib.Path, dict_lock: pathlib.Path, trial_id_str: str, result: float, start_time: str, end_time: str, err_message: str = '') None

Save a result file.

Parameters
  • ws (Path) – A path of a workspace.

  • dict_lock (Path) – A directory to store lock files.

  • trial_id_str (str) – An unique name of a parameter set.

  • result (float) – A result of a parameter set.

  • start_time (str) – A start time string.

  • end_time (str) – An end time string.

  • err_message (str) – Error message from Wrapper (user program)

Returns

None

Module contents

索引と検索

謝辞

  • この成果の一部は、国立研究開発法人新エネルギー・産業技術総合開発機構(NEDO)の委託業務として開発されたものです。

  • TPEアルゴリズムは Optuna を利用しました。