假設有一對$(x, y)$存在下列隱式(implicit)關係:
$y^{3}+2^{x}+5y^{2}-7x=2$
$sin(x)y+x^{2}y-xy^{3}=0$
這個方程組不好解,因為他們的顯式方程組(explicit equation set)不那麼明顯。如果以紙筆求出數值解,則需要先猜一組初始值,然後微分該方程組後代入初始值。以微分後得到的值為根據做進一步猜測,如此往復。求數值解的過程非常機械化且無聊,所以我們可以利用計算機幫我們完成這件討厭的工作。
作法
求數值解是一種最佳化算法。在電腦上手刻最佳化算法是非常不智的,就好像為了喝一瓶牛奶而培養微生物,然後祈禱它某一天會演化成乳牛。Python的套件optuna可以直接尋找數值解。
首先讓我們載入套件
# 載入必須套件
import optuna
optuna.logging.set_verbosity(optuna.logging.WARNING) # disable optuna warning
import numpy as np
# 安裝:python -m pip install optuna numpy
接下來我們要建立一個方程式objective
讓電腦知道最佳化的目標是什麼
# 目標函數
def objective(trial):
x = trial.suggest_float('x', -10, 10) # 假設 x ∈ [-10, 10]
y = trial.suggest_float('y', -10, 10) # 假設 y ∈ [-10, 10]
loss_1 = y**3 + 2**x + 5*(y**2) - 7*x - 2
loss_2 = np.sin(x)*y + (x**2)*y - x*(y**3)
loss = np.array([loss_1, loss_2])
return np.linalg.norm(loss) # L2 norm
然後optuna.optimize
就能夠透過不斷的嘗試找出 objective
的最佳解
# 最小化目標函數
sampler = optuna.samplers.TPESampler()
study = optuna.create_study(sampler=sampler, direction='minimize') # objectvie 越小越好
study.optimize(objective, n_trials=1000)
# 印出(x, y)的最佳值
print(study.best_params)
# output: {'x': 0.03111622282627699, 'y': -0.5141155663560733}
# 印出objective的最佳值
print(study.best_value)
# output: 0.016032011887374697
尋找數值解時也有一些需要注意的地方
- 如果有大於兩種loss,請確保所有的losses的scale不要差太多。
- 如果找不到解,可以檢查輸入值的範圍是否合適。除非萬不得已,不要輕易增加
n_trials
。 - 如果對於第一次找到的解不滿意,可以以第一次的解為基礎,以比較小的搜尋範圍再找一次解。
以下是根據第一次的結果,在比較小的(x, y)範圍內做最佳化的範例:
# 在比較小的(x, y)範圍內做最佳化
def objective2(trial):
x = trial.suggest_float('x', -0.5, 0.5)
y = trial.suggest_float('y', -1, 0)
loss_1 = y**3 + 2**x + 5*(y**2) - 7*x - 2
loss_2 = np.sin(x)*y + (x**2)*y - x*(y**3)
loss = np.array([loss_1, loss_2])
return np.linalg.norm(loss) # L2 norm
# 最小化目標函數
sampler = optuna.samplers.TPESampler()
study = optuna.create_study(sampler=sampler, direction='minimize')
study.optimize(objective, n_trials=1000)
# 印出(x, y)的最佳值
print(study.best_params)
# output: {'x': 0.005506817001806399, 'y': -0.4787724094168787}
# 印出objective的最佳值
print(study.best_value)
# output: 0.0026264689619759475
結語
工程上經常有許多隱式方程組,可能是過度複雜的並聯電路、或是需要查表的離散測量值。雖然也存在有簡單的作法。例如忽略所有的二次交叉項,這些值在真實的物理上通常都很小,但總是比較不準確。使用計算機找數值解曾經非常複雜,因為沒有好的套件提供最佳化算法。而Optuna為Python和計算機補上了這個空缺。
參考
- Optuna https://optuna.org/
所有文章分類