いわて駐在研究日誌2。

NEVER STAND BEHIND ME

Dakotaの並列計算機能について(その2)

以下のような簡単な問題(Beale's function)を最適化で解いてみる。設計変数がx1, x2で、目的関数(単一)がf、制約条件(単一)がc>=0である。最小値の答えはf(3, 0.5)=0。

See: Test functions for optimization - Wikipedia, the free encyclopedia

#!/bin/python
from sys import argv
from math import *
import numpy as np

def f(x1, x2):
    return (1.5-x1+x1*x2)**2+(2.25-x1+x1*x2**2)**2+(2.625-x1+x1*x2**3)**2

def c(x1, x2):
    return x1**2-x2

if __name__ == '__main__':
    x1 = float(argv[1])
    x2 = float(argv[2])
    print f(x1,x2)
    print c(x1,x2)

これの最適解は、

 

①Gradientベースの最適化(conmin_mfd method)

勾配を用いる最適化の場合は、逐次的に最適値を探索する。勾配には、あらかじめ数式などで求まっている場合と数値的な微分を用いる場合があるが、後者が一般的。

Dakotaで実装されている一番一般的な勾配法として、conmin_mfdやconmin_frcg ( conjugate gradient optimization method)がある。ここでは前者を利用する。勾配はNumerical gradientである。初期値は(1,0)とする。

1)シリアル計算で実行した場合

<<<<< Function evaluation summary: 10 total (8 new, 2 duplicate)
<<<<< Best parameters          =
                      5.0524767374e-01 x1
                      2.5527521182e-01 x2
<<<<< Best objective function  =
                      8.9519566068e+00
<<<<< Best constraint values   =
                     -1.2678746941e-13
<<<<< Best data captured at function evaluation 6


<<<<< Iterator conmin_mfd completed.
<<<<< Environment execution completed.
DAKOTA execution time in seconds:
  Total CPU        =       0.02 [parent =   0.010999, child =   0.009001]
  Total wall clock =    1.26761

real    0m1.362s
user    0m1.528s
sys    0m0.221s

 2)evaluation_concurrency=4を指定した場合

<<<<< Function evaluation summary: 10 total (8 new, 2 duplicate)
<<<<< Best parameters          =
                      5.0524767374e-01 x1
                      2.5527521182e-01 x2
<<<<< Best objective function  =
                      8.9519566068e+00
<<<<< Best constraint values   =
                     -1.2678746941e-13
<<<<< Best data captured at function evaluation 6


<<<<< Iterator conmin_mfd completed.
<<<<< Environment execution completed.
DAKOTA execution time in seconds:
  Total CPU        =       0.02 [parent =   0.011998, child =   0.008002]
  Total wall clock =    1.26666

real    0m1.367s
user    0m1.534s
sys    0m0.234s

 3)mpirun -np 4で起動した場合(evaluation_concurrency指定なし)

<<<<< Function evaluation summary: 10 total (8 new, 2 duplicate)
<<<<< Best parameters          =
                      5.0524767374e-01 x1
                      2.5527521182e-01 x2
<<<<< Best objective function  =
                      8.9519566068e+00
<<<<< Best constraint values   =
                     -1.2678746941e-13
<<<<< Best data captured at function evaluation 6


<<<<< Iterator conmin_mfd completed.
<<<<< Environment execution completed.
DAKOTA master processor execution time in seconds:
  Total CPU        =       0.02 [parent   =   0.018997, child =   0.001003]
  Total wall clock =    1.42358 [MPI_Init = 1.69277e-05, run   =    1.42357]

 

という結果になった(3つとも当然ながら計算結果は一致し、勾配ベースはやはり計算が速い!)が、正解には到達していない。

 原理的に逐次計算を必要とする(数値的勾配を用いる場合)は、並列計算の意味があまりなさそうである(もしかしたらもっと良い方法があるのかもしれないが....)。

※ 勾配ベースの最適化は、実際には滑らかな応答局面でないと収束しなかったり、

局所最適解に落ちつくなどがあるので、流体計算などで適用できる場合は限られるかもしれない。

 

②Non-Gradientベースの最適化(moga method)

MOGA(Multi Objective GA)で確認してみる。mogaの設定は以下の通りで、最適解の可能性のあるものを1つ出力する。このあたりのパラメーターの設定をどうすればよいか、指針が欲しいところ(現状は、ネットで調べた設定をそのまま利用)。

method
  moga
  output silent
    seed = 10983
    final_solutions = 1
  max_function_evaluations = 5000
  initialization_type unique_random
  crossover_type shuffle_random
    num_offspring = 2 num_parents = 2
    crossover_rate = 0.8
  mutation_type replace_uniform
    mutation_rate = 0.1
  fitness_type domination_count
  replacement_type below_limit = 6
    shrinkage_percentage = 0.9
  convergence_type metric_tracker
    percent_change = 0.05 num_generations = 50

1)シリアル計算で実行した場合

<<<<< Function evaluation summary: 257 total (257 new, 0 duplicate)
<<<<< Best parameters          =
                     -9.7989947697e-01 x1
                      9.9330955813e-01 x2
<<<<< Best objective function  =
                      1.4384761666e+01
<<<<< Best constraint values   =
                     -3.3106573164e-02
<<<<< Best data captured at function evaluation 115


<<<<< Iterator moga completed.
<<<<< Environment execution completed.
DAKOTA execution time in seconds:
  Total CPU        =        0.2 [parent =    0.19597, child =    0.00403]
  Total wall clock =    47.6183

real    0m47.714s
user    0m41.059s
sys    0m5.870s

2)evaluation_concurrency=4を指定した場合

<<<<< Function evaluation summary: 257 total (257 new, 0 duplicate)
<<<<< Best parameters          =
                     -9.7989947697e-01 x1
                      9.9330955813e-01 x2
<<<<< Best objective function  =
                      1.4384761666e+01
<<<<< Best constraint values   =
                     -3.3106573164e-02
<<<<< Best data captured at function evaluation 115


<<<<< Iterator moga completed.
<<<<< Environment execution completed.
DAKOTA execution time in seconds:
  Total CPU        =       0.18 [parent =   0.187972, child =  -0.007972]
  Total wall clock =     22.097

real    0m22.193s
user    0m43.546s
sys    0m6.179s

3)mpirun -np 4で起動した場合(evaluation_concurrency指定なし)

<<<<< Function evaluation summary: 257 total (257 new, 0 duplicate)
<<<<< Best parameters          =
                     -9.7989947697e-01 x1
                      9.9330955813e-01 x2
<<<<< Best objective function  =
                      1.4384761666e+01
<<<<< Best constraint values   =
                     -3.3106573164e-02
<<<<< Best data captured at function evaluation 115


<<<<< Iterator moga completed.
<<<<< Environment execution completed.
DAKOTA master processor execution time in seconds:
  Total CPU        =       0.58 [parent   =   0.588911, child =  -0.008911]
  Total wall clock =    27.0884 [MPI_Init = 9.77516e-06, run   =    27.0884]

real    0m27.302s
user    1m20.837s
sys    0m7.109s

ということで、並列計算では計算時間は約半分になる....がやはり正解にたどり着かない!

 

(追記)

nonlinear constraintをなしにするとどちらも正解に近い値を出すことを確認できた。