以下のような簡単な問題(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をなしにするとどちらも正解に近い値を出すことを確認できた。