3. 基本操作

3. 基本操作

本章では、最初のEvoX最適化タスクを実行する手順を案内します。これには、EvoXの起動最適化プロセスの初期化EvoXプロジェクトの構成(アルゴリズムと問題の選択および組み立て)、そして最適化プロセスを制御するためによく使用される基本コマンド(またはメソッド)が含まれます。簡単な例を通して、EvoXの基本的な使い方を学びます。

起動と初期化

インストールの確認後、EvoXを使用して最適化スクリプトの作成を開始できます。EvoXは任意のPython環境(ターミナル、Jupyter Notebook、IDEなど)でインポートできます。

まず、EvoXとその関連モジュールをインポートし、簡単な最適化タスクを初期化しましょう。例えば、Particle Swarm Optimization (PSO) アルゴリズムを使用して、古典的なAckley関数を最適化します。Ackley関数は、((0,0,\dots,0)) に既知の大域的最適解を持つ一般的なベンチマーク関数であり、デモンストレーションに適しています。 以下は、最適化を開始して実行する方法を示す最小限のEvoXサンプルコードです。

import torch
from evox.algorithms import PSO                      # Import PSO algorithm
from evox.problems.numerical import Ackley           # Import Ackley optimization problem
from evox.workflows import StdWorkflow, EvalMonitor  # Import standard workflow and monitor

# 1. Define the optimization algorithm and problem
algorithm = PSO(
    pop_size=50,                    # Population size of 50
    lb=-32 * torch.ones(2),         # Decision variable lower bound: 2D vector, each -32
    ub= 32 * torch.ones(2)          # Decision variable upper bound: 2D vector, each 32
)
problem = Ackley()                  # Optimization problem: Ackley function (default dimension matches the algorithm)

# 2. Assemble the workflow and add a monitor to track results
monitor = EvalMonitor()
workflow = StdWorkflow(algorithm, problem, monitor)

# 3. Initialize the workflow
workflow.init_step()  # Initialize the internal state of the algorithm and problem

# 4. Execute optimization iterations
for i in range(100):
    workflow.step()   # Advance the optimization by one step

# 5. Obtain results (e.g., print the optimal value)
best_fitness = monitor.get_best_fitness() # Get the best fitness value from the monitor
print("Iteration completed, current best fitness value found:", float(best_fitness))

上記のコードには以下の手順が含まれています。

  • まず、PSOアルゴリズムのパラメータを設定します:個体数(population size)は50、探索空間は2次元で範囲は[-32, 32]です。
  • 次に、Ackley問題を定義します(Ackley関数はデフォルトで2次元として定義されています)。
  • アルゴリズムと問題を組み立てる標準ワークフロー StdWorkflow を作成し、最適化プロセスのデータを記録するためにモニター EvalMonitor を渡します。
  • 続いて、workflow.init_step() を使用して初期化プロセスを完了します。これにより、個体群、乱数シード、その他の内部状態が自動的に初期化されます。
  • その後、ループを実行して workflow.step() を使用し、100回の反復(イテレーション)を継続的に実行します。step() が呼び出されるたびに、アルゴリズムは新しい解を生成してその適応度(fitness)を評価し、最適解に近づき続けます。
  • 最後に、モニターが提供する get_best_fitness() メソッドを使用して、反復プロセス中の最良の適応度を取得し、それを出力します。

このスクリプトを実行すると、最適化の反復結果が出力されます。例:

Iteration completed, current best fitness value found: 9.5367431640625e-07

ループ内で中間結果を明示的に出力していないため、中間結果は表示されません。しかし、最終的な適応度に基づいてアルゴリズムが収束したかどうかを判断できます。例えば、Ackley関数の最適値は0であり、出力が0に近い場合、PSOが大域的最適解に近い解を見つけたことを示しています。また、print(monitor.history) を呼び出してモニターに記録された履歴データを表示したり、monitor.plot() を使用して収束曲線を描画したりすることもできます(Plotlyなどの可視化サポートが必要です)。

注: StdWorkflow は、EvoXが提供する標準的な最適化プロセスのカプセル化です。これは、従来の進化的アルゴリズムに見られる「初期化-反復更新」のロジックを内部的に実装し、アルゴリズムと問題の間の相互作用をカプセル化しています。ほとんどの単純なアプリケーションでは、StdWorkflow を直接使用するだけで十分です。EvalMonitor は、get_best_fitness()plot() などのメソッドを実装したモニターであり、最適化プロセス中のパフォーマンス指標を収集して表示します。初心者は、これを「後で分析するために各反復の最良の結果を記録する記録帳」として一時的に理解しておくと良いでしょう。

上記の例では、アルゴリズムの選択、問題の定義、ワークフローの組み立てを含む、EvoXプロジェクトの基本的な構成を作成しました。一般的に、EvoXプロジェクトの構成には以下の手順が含まれます。

  1. 最適化問題の選択/定義:解決しようとしている最適化問題を明確にします。例えば、数学関数を最適化する場合、EvoXは evox.problems モジュール下に多くの組み込み問題(Sphere、Rastrigin、Ackleyなどの古典的な関数など)を提供しており、これらを直接使用できます。問題が組み込みに含まれていない場合は、独自に定義することができます(後の章で扱います)。問題を構成する際、通常は決定変数の次元とその値の範囲を知る必要があります。

  2. 最適化アルゴリズムの選択/構成:問題のタイプに基づいて適切な進化的アルゴリズムを選択します。EvoXは evox.algorithms 下に、単目的アルゴリズム(PSO、GA、CMA-ESなど)や多目的アルゴリズム(NSGA-II、RVEAなど)を含む豊富なアルゴリズムセットを提供しています。アルゴリズムを選択した後、通常は個体数(pop_size)やアルゴリズム固有のパラメータ(GAにおける交叉確率や突然変異確率など)を設定する必要があります。ほとんどのアルゴリズムでは、個体群を初期化するために変数の範囲(下限 lb と上限 ub)および問題の次元が必要です。多目的アルゴリズムを使用する場合は、目的の数(n_objs)も指定する必要があります。EvoXのアルゴリズムは一般的なハイパーパラメータのデフォルト値を提供することが多いですが、初心者はパフォーマンス向上のためにタスクに基づいてこれらのパラメータを調整することを検討すべきです。

  3. ワークフローの組み立て:アルゴリズムと問題のインスタンスが準備できたら、それらをワークフローに「組み立てる」必要があります。これは完全な最適化プロセス制御を表します。EvoXでは、通常 StdWorkflow を使用してアルゴリズムと問題を組み合わせます。最適化の進行状況を監視したい場合は、ワークフローにモニター(EvalMonitor など)を追加できます。モニターは必須ではありませんが、デバッグや分析の際に非常に役立ちます。ワークフローの組み立ては通常、workflow = StdWorkflow(algo, prob, monitor) のように1行のコードで行われます。

  4. 初期化:ワークフローの初期化メソッドを呼び出して最適化を開始します。EvoXの最新バージョンでは、便利な StdWorkflow.init_step() メソッドが提供されており、1回の呼び出しで初期化プロセスを完了できます。

  5. 反復の実行:ループを使用して workflow.step() を繰り返し呼び出し、進化プロセスを前進させます。各呼び出しは、アルゴリズム内での「新しい解の生成 -> 評価 -> 選択」などのステップを含む1回の反復を実行します。反復中、モニターを使用してリアルタイムの結果を観察できます(例:数世代ごとに現在の最良の適応度を出力するなど)。終了条件はニーズに基づいて設定できます。一般的なものには、固定の世代数(例:100世代実行)や、監視対象の指標が収束した時点(例:数世代にわたって大幅な改善がない場合)での停止などがあります。

  6. 結果の取得:反復終了後、アルゴリズムから最終結果(最良解やその目的関数値など)を抽出する必要があります。EvoXでは、これらは通常モニターを介して取得されます。例えば、EvalMonitor.get_best_fitness() は最良の適応度を返します。最良解のベクトルを取得するには、評価中に問題オブジェクトに最良の候補を保存させるか、モニターのインターフェースを使用する方法があります。EvoXの標準実装では、EvalMonitor は各世代の最良個体と適応度を記録し、プロパティを通じてアクセス可能です。monitor.history に履歴が保存されていると仮定すると、最後の世代から最良個体を取得できます。もちろん、EvalMonitor をスキップしてループ後にアルゴリズムオブジェクトを直接クエリすることも可能です(これはアルゴリズムの実装に依存します)。カスタムアルゴリズムが get_best() を実装しているか、その状態に最良個体を保存している場合、それを直接抽出できます。ただし、EvoXは純粋関数とモジュール性を重視しているため、結果は通常、監視モジュールを介してアクセスされます。

これらの手順に従うことで、最適化タスクのコードを明確に構造化できます。初心者にとって、アルゴリズム-問題-ワークフローの3要素がどのように連携するかを理解することは重要です。アルゴリズムは解の生成と改善を処理し、問題はその質を評価し、ワークフローはそれらを反復ループに接続します。

次に、最適化プロセスの理解を深めるために、EvoXで利用可能な基本的なコマンドと関数呼び出しをいくつか紹介します。

基本コマンドの概要

EvoXを使用する際、慣れておくべき「コマンド」として機能するよく使われるメソッドや関数がいくつかあります。

ワークフロー関連のメソッド

  • StdWorkflow.init_step():初期化。これは最適化プロセスを開始するためのクイックスタートコマンドであり、スクリプトの冒頭でよく使用されます。アルゴリズムと問題の両方の初期化ロジックを呼び出し、初期個体群を生成し、適応度を評価します。この後、ワークフローは初期状態を持ち、反復の準備が整います。

  • StdWorkflow.step():最適化を1ステップ進めます。各呼び出しにより、アルゴリズムは現在の個体群の状態に基づいて新しい候補解を生成し、それらを評価して、次世代を選択します。ユーザーは通常、ループ内でこれを複数回呼び出します。step() 関数は通常何も返しません(内部状態はワークフロー内で更新されます)。古いバージョンでは新しい状態を返していたかもしれませんが、初心者は戻り値を気にせずに単に呼び出すだけで構いません。

モニター関連のメソッド

EvalMonitor を例にとると、一般的なメソッドには以下があります。

  • EvalMonitor.get_best_fitness():記録された最小の適応度(最小化問題の場合)または最大の適応度(最大化問題の場合。モニターは通常これを区別します)を返します。現在の最良の結果を知るのに役立ちます。
  • EvalMonitor.get_history() または monitor.history:各世代の最良値など、完全な履歴を取得します。収束傾向を分析するのに役立ちます。
  • EvalMonitor.plot():収束曲線やパフォーマンス曲線を描画します。グラフィカル環境またはNotebookが必要です。モニターは通常、グラフの描画にPlotlyを使用し、アルゴリズムのパフォーマンスを視覚的に評価するのに役立ちます。 内部的には、モニターは各世代の評価回数とその結果を記録します。通常、介入する必要はなく、必要なときにデータを抽出するだけです。

アルゴリズム関連のメソッド

  • Algorithm.__init__() メソッド:アルゴリズムの初期化メソッドです。変数は通常 evox.core.Mutable() で、ハイパーパラメータは evox.core.Parameter() でラップされます。

  • Algorithm.step() メソッド:特定のシナリオやカスタムアルゴリズム/問題を使用する場合、アルゴリズムの step() メソッドを直接呼び出すことがあります。これは通常、アルゴリズムの反復ロジック全体をカプセル化しています。

  • Algorithm.init_step() メソッド:init_step() メソッドには、アルゴリズムの最初の反復が含まれます。オーバーライドされていない場合、単に step() メソッドを呼び出します。一般的なケースでは、最初の反復は他の反復と変わらないため、多くのアルゴリズムではカスタムの init_step() を必要としない場合があります。しかし、ハイパーパラメータの調整を伴うアルゴリズムの場合、ここでハイパーパラメータや関連変数を更新する必要があるかもしれません。

デバイスと並列制御

  • .to(device) メソッド:プログラム内で計算デバイスを切り替える必要がある場合、PyTorchの .to(device) メソッドを使用してテンソル(torch.Tensor)をGPU/CPUに移動します(torch.randn などの一部のPyTorchメソッドもデバイスを指定する必要があります)。一般的に、torch.set_default_device() を使用してデバイスを cuda:0 に設定すれば(システムがサポートしており、EvoXと依存関係が正しくインストールされていると仮定し、torch.cuda.is_available() で確認)、ほとんどのEvoXの高性能並列計算は自動的にGPU上で実行されます。カスタムアルゴリズム、問題、またはモニターを作成する際、新しいテンソルを作成したり、デバイスに依存するPyTorchメソッドを使用したりする場合は、計算が異なるデバイスに分散してパフォーマンスが低下するのを避けるために、明示的に devicecuda:0 に指定するか、torch.get_default_device() を使用することをお勧めします。

初心者にとって、上記のメソッドは一般的な最適化タスクを処理するのに十分です。要するに、問題/アルゴリズムの初期化 – モニターの設定 – ワークフローの組み立て – 実行と結果の取得 が最も一般的なEvoXのワークフローです。これらを習得すれば、EvoXを使用して基本的な最適化タスクに取り組むことができます。

次の章に進む前に、例を変更してみてください。PSOから別のアルゴリズムに切り替える、Ackley関数を別のテスト関数に置き換える、またはモニターを使用してより多くの情報を抽出するなど、EvoXプロジェクト構成の柔軟性を実感するのに役立ちます。