※記事内に商品プロモーションを含むことがあります。
はじめに
最適化フレームワークCasADiのOptiスタックでcallback関数を使って、最適化ソルバの各反復における解の推移を取得する方法をまとめました。言語はPythonです。
検証環境は以下の通りです。
ソフトウェア |
バージョン |
Python |
3.9.7 |
CasADi |
3.6.3 |
リンク
callback関数の基本的な使い方
2変数の凸連続最適化問題を例に、Optiスタックでcallback関数を使用する例を以下に示します。最適化ソルバには、凸連続最適化問題に適したIPOPTを使用しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import casadi as ca
opti = ca.Opti()
# 変数を定義
x1 = opti.variable()
x2 = opti.variable()
# 初期値を指定
opti.set_initial(x1, 100)
opti.set_initial(x2, 10)
# 目的関数を定義
obj = x1**2 + x2**2
opti.minimize(obj)
# 制約条件を定義
opti.subject_to( x1*x2 >= 1 )
# 最適化ソルバを設定
p_opts = {}
s_opts = {'print_level': 4}
opti.solver('ipopt', p_opts, s_opts)
# callback関数を定義
opti.callback(lambda i: print(i, opti.debug.value(x1)))
# 最適化計算を実行
sol = opti.solve()
|
上記のコードを実行すると、変数x1
, x2
の内、x1
の推移が以下のようにコンソールに出力されます。左側の数字は最適化ソルバの反復回数、右側の数字はx1
です。x1
が初期値の100から、最適解の1に近づいていることが分かります。
1
2
3
4
5
6
7
8
9
10
|
0 100.0
1 4.689542724520109
2 1.0795374935431634
3 0.5517089519112491
4 0.8179977199977577
5 1.0262185402295063
6 1.0018147643511712
7 1.0000773780870829
8 1.00000092044001
9 0.999999996253379
|
1
|
opti.callback(lambda i: print(i, opti.debug.value(x1)))
|
上記の例では、ラムダ式(無名関数)を使い、最適化ソルバの反復ごとに呼び出すcallback関数を定義しています。このラムダ式の引数i
には、反復回数が与えられます。また、変数にはopti.debug.value()
メソッドを使ってアクセスします。
全変数の推移を取得
全ての変数の推移を取得する方法は色々ありますが、1例を以下に示します。log
というリストに各反復のopti.debug
を追加していきます。最適化計算の終了後、各変数を取り出します。
1
2
3
4
5
6
7
8
9
10
|
log = []
# callback関数を定義
opti.callback(lambda i: log.append(opti.debug))
# 最適化計算を実行
sol = opti.solve()
for deb in log:
print(deb.value(x1), deb.value(x2))
|
実行結果
1
2
3
4
5
6
7
8
9
10
|
100.0 10.0
4.689542724520109 16.043123296985808
1.0795374935431634 1.9311817025775309
0.5517089519112491 0.6966250709025741
0.8179977199977577 0.8500586577938801
1.0262185402295063 1.0243870906377914
1.0018147643511712 1.0017967248568909
1.0000773780870829 1.000077373885306
1.00000092044001 1.0000009204400082
0.999999996253379 0.999999996253379
|
参考
CasADiの公式リファレンス
CasADi - Docs