加快 Gekko 在最小化具有交互变量的许多方程时的速度。

huangapple go评论68阅读模式
英文:

Speed up Gekko when minimizing many equations with interactive variables

问题

我正在使用gekko来通过最小化约10,000个方程来解决14个变量的问题,使用IMODE=3

每个方程是响应y与训练数据中第i行的多项式模型输出之间的平方误差。

eq[i] = (y[i] - model[i]) ** 2

在每行中,多项式模型大约有10到100个项,其中找到了14个优化的变量。这些变量在模型中具有很强的交互性,意味着多个变量多次相乘。

问题: 我可以采用什么策略来加速求解时间?

这里有一个简化的可重现示例,其中模型试图拟合一条直线:

from gekko import GEKKO
import numpy as np

m = GEKKO()  # 实例化gekko模型

# 实例化自由变量
a = m.FV(lb=0, ub=2)
a.STATUS = 1
b = m.FV(lb=0, ub=2)
b.STATUS = 1
c = m.FV(lb=0, ub=2)
c.STATUS = 1

n_eqs1 = 1000  # 数据集1中的方程数量
n_eqs2 = 500  # 数据集2中的方程数量
n_terms = 12  # 每个方程中的项数
noise_scl = 1  # 噪声的数量,表示为正态分布的标准差

# 训练数据集
x = {
    "dataset1": np.arange(n_eqs1)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
    "dataset2": np.arange(n_eqs2)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
}
# 响应
y = np.arange(n_eqs1)

for x_ds in x.values():
    for i in range(x_ds.shape[0]):
        # 最小化方程
        m.Minimize(
            (
                y[i]
                - (
                    x_ds[i, 0] * a
                    + x_ds[i, 1] * a**2
                    + x_ds[i, 2] * a * b
                    + x_ds[i, 3] * a * (b**2)
                    + x_ds[i, 4] * (a**2) * b
                    + x_ds[i, 5] * (a**2) * (b**2)
                    + x_ds[i, 6] * c
                    + x_ds[i, 7] * (c**2)
                    + x_ds[i, 8] * c * b
                    + x_ds[i, 9] * c * (b**2)
                    + x_ds[i, 10] * (c**2) * b
                    + x_ds[i, 11] * (c**2) * (b**2)
                )
                / n_terms
            )
            ** 2
        )

m.options.IMODE = 3
m.solve(disp=True)

# 根据噪声的数量,优化值应趋向于1
print(f"a = {a.value[0]:3f}\n" f"b = {b.value[0]:3f}\n" f"c = {c.value[0]:3f}")

(注意:我已经将Python代码提供给您,以便您可以查看示例和策略,但代码部分不需要翻译。)

英文:

I am using gekko to solve for 14 variables by minimizing around 10,000 equations with IMODE=3.

Each equation is the squared error between a response y and the output of a polynomial model at row i in the training data.

eq[i] = (y[i] - model[i]) ** 2

In each row, the polynomial model has around 10 to 100 terms, where the 14 optimized variables are found. The variables are very interactive in the model, meaning that multiple variables are multiplied together multiple times.

Question: What strategies can I employ to speed up the solving time?

Here is a much simpler reproducible example where the model tries to fit a straight line:

from gekko import GEKKO
import numpy as np
m = GEKKO()  # instantiate gekko model
# instantiate free variables
a = m.FV(lb=0, ub=2)
a.STATUS = 1
b = m.FV(lb=0, ub=2)
b.STATUS = 1
c = m.FV(lb=0, ub=2)
c.STATUS = 1
n_eqs1 = 1000  # number of equations in dataset1
n_eqs2 = 500  # number of equations in dataset2
n_terms = 12  # number of terms in each  equation
noise_scl = 1  # amount of noise represented as the std of the normal distributions
# training datasets
x = {
"dataset1": np.arange(n_eqs1)[:, np.newaxis]
+ np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
"dataset2": np.arange(n_eqs2)[:, np.newaxis]
+ np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
}
# response
y = np.arange(n_eqs1)
for x_ds in x.values():
for i in range(x_ds.shape[0]):
# minimize equations
m.Minimize(
(
y[i]
- (
x_ds[i, 0] * a
+ x_ds[i, 1] * a**2
+ x_ds[i, 2] * a * b
+ x_ds[i, 3] * a * (b**2)
+ x_ds[i, 4] * (a**2) * b
+ x_ds[i, 5] * (a**2) * (b**2)
+ x_ds[i, 6] * c
+ x_ds[i, 7] * (c**2)
+ x_ds[i, 8] * c * b
+ x_ds[i, 9] * c * (b**2)
+ x_ds[i, 10] * (c**2) * b
+ x_ds[i, 11] * (c**2) * (b**2)
)
/ n_terms
)
** 2
)
m.options.IMODE = 3
m.solve(disp=True)
# depending on the amount of noise, the optimized values should tend towards 1
print(f"a = {a.value[0]:3f}\n" f"b = {b.value[0]:3f}\n" f"c = {c.value[0]:3f}")

答案1

得分: 1

尝试使用IMODE=2,这是专为数据回归设计的。总建模时间将减少,但求解时间应该是相似的。要减少求解时间,除了尝试更好的初始猜测值、简化模型、缩放数据、去除异常值或减少数据点数量之外,没有太多可以做的。

Total Build time: 0.04206514358520508
Total Solve time: 7.088646650314331
Solver time: 4.3853
a = 0.976090
b = 0.980885
c = 1.048744

修改为回归(IMODE=2)带定时

from gekko import GEKKO
import numpy as np
import time

start = time.time()
m = GEKKO()  # 实例化gekko模型

# 实例化自由变量
a = m.FV(lb=0, ub=2)
a.STATUS = 1
b = m.FV(lb=0, ub=2)
b.STATUS = 1
c = m.FV(lb=0, ub=2)
c.STATUS = 1

n_eqs1 = 1000  # 数据集1中的方程数量
n_eqs2 = 500  # 数据集2中的方程数量
n_terms = 12  # 每个方程中的项数
noise_scl = 1  # 代表正态分布标准差的噪声量

# 训练数据集
x = {
    "dataset1": np.arange(n_eqs1)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
    "dataset2": np.arange(n_eqs2)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
}
# 响应
y = np.arange(n_eqs1)

# 创建组合数据集
xd = np.vstack((x["dataset1"], x["dataset2"]))
yd = np.append(y, y[:n_eqs2])

yp = m.Param(yd)
x_ds = m.Array(m.Param, n_terms)
for i in range(n_terms):
    x_ds[i].value = xd[:, i]

# 最小化方程
m.Minimize((yp - (x_ds[0] * a
                  + x_ds[1] * a**2
                  + x_ds[2] * a * b
                  + x_ds[3] * a * (b**2)
                  + x_ds[4] * (a**2) * b
                  + x_ds[5] * (a**2) * (b**2)
                  + x_ds[6] * c
                  + x_ds[7] * (c**2)
                  + x_ds[8] * c * b
                  + x_ds[9] * c * (b**2)
                  + x_ds[10] * (c**2) * b
                  + x_ds[11] * (c**2) * (b**2)
                ) / n_terms)**2)

m.options.IMODE = 2
print('Total Build time:', time.time() - start)

start = time.time()
m.solve(disp=False)
print('Total Solve time:', time.time() - start)
print('Solver time:', m.options.SOLVETIME)

# 根据噪声量的不同,优化后的值应趋向于1
print(f"a = {a.value[0]:3f}\n" \
      f"b = {b.value[0]:3f}\n" \
      f"c = {c.value[0]:3f}")

原始模型使用IMODE=3,在Gekko中构建模型需要0.32秒,一旦Gekko编译和解决问题,需要6.88秒,其中有2.92秒用于求解。

Total Build time: 0.3288764953613281
Total Solve time: 6.876295566558838
Solver time: 2.9223
a = 1.021506
b = 0.978350
c = 1.007642

原始(IMODE=3)带定时

from gekko import GEKKO
import numpy as np
import time

start = time.time()
m = GEKKO()  # 实例化gekko模型

# 实例化自由变量
a = m.FV(lb=0, ub=2)
a.STATUS = 1
b = m.FV(lb=0, ub=2)
b.STATUS = 1
c = m.FV(lb=0, ub=2)
c.STATUS = 1

n_eqs1 = 1000  # 数据集1中的方程数量
n_eqs2 = 500  # 数据集2中的方程数量
n_terms = 12  # 每个方程中的项数
noise_scl = 1  # 代表正态分布标准差的噪声量

# 训练数据集
x = {
    "dataset1": np.arange(n_eqs1)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, \
                       size=(n_eqs1, n_terms)),
    "dataset2": np.arange(n_eqs2)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, \
                       size=(n_eqs2, n_terms)),
}
# 响应
y = np.arange(n_eqs1)

for x_ds in x.values():
    for i in range(x_ds.shape[0]):
        # 最小化方程
        m.Minimize(
            (
                y[i]
                - (
                    x_ds[i, 0] * a
                    + x_ds[i, 1] * a**2
                    + x_ds[i, 2] * a * b
                    + x_ds[i, 3] * a * (b**2)
                    + x_ds[i, 4] * (a**2) * b
                    + x_ds[i, 5] * (a**2) * (b**2)
                    + x_ds[i, 6] * c
                    + x_ds[i, 7] * (c**2)
                    + x_ds[i, 8] * c * b
                    + x_ds[i, 9] * c * (b**2)
                    + x_ds[i, 10] * (c**2) * b
                    + x_ds[i, 11] * (c

<details>
<summary>英文:</summary>

Try using `IMODE=2` that is designed for data regression. Total build time will decrease but the solve time should be similar. There isn&#39;t much that can be done to decrease the solve time except try better initial guess values, simplify the model, scale the data, remove outliers, or reduce the number of data points.

Total Build time: 0.04206514358520508
Total Solve time: 7.088646650314331
Solver time: 4.3853
a = 0.976090
b = 0.980885
c = 1.048744


**Modified for Regression (IMODE=2) with Timing**
```python
from gekko import GEKKO
import numpy as np
import time
start = time.time()
m = GEKKO()  # instantiate gekko model
# instantiate free variables
a = m.FV(lb=0, ub=2)
a.STATUS = 1
b = m.FV(lb=0, ub=2)
b.STATUS = 1
c = m.FV(lb=0, ub=2)
c.STATUS = 1
n_eqs1 = 1000  # number of equations in dataset1
n_eqs2 = 500  # number of equations in dataset2
n_terms = 12  # number of terms in each equation
noise_scl = 1  # amount of noise represented as the std of the normal distributions
# training datasets
x = {
&quot;dataset1&quot;: np.arange(n_eqs1)[:, np.newaxis]
+ np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
&quot;dataset2&quot;: np.arange(n_eqs2)[:, np.newaxis]
+ np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
}
# response
y = np.arange(n_eqs1)
# create combined dataset
xd = np.vstack((x[&quot;dataset1&quot;],x[&quot;dataset2&quot;]))
yd = np.append(y,y[:n_eqs2])
yp = m.Param(yd)
x_ds = m.Array(m.Param,n_terms)
for i in range(n_terms):
x_ds[i].value = xd[:,i]
# minimize equations
m.Minimize((yp - (  x_ds[0] * a
+ x_ds[1] * a**2
+ x_ds[2] * a * b
+ x_ds[3] * a * (b**2)
+ x_ds[4] * (a**2) * b
+ x_ds[5] * (a**2) * (b**2)
+ x_ds[6] * c
+ x_ds[7] * (c**2)
+ x_ds[8] * c * b
+ x_ds[9] * c * (b**2)
+ x_ds[10] * (c**2) * b
+ x_ds[11] * (c**2) * (b**2)
) / n_terms)**2)
m.options.IMODE = 2
print(&#39;Total Build time:&#39;,time.time()-start)
start = time.time()
m.solve(disp=False)
print(&#39;Total Solve time:&#39;,time.time()-start)
print(&#39;Solver time:&#39;,m.options.SOLVETIME)
# depending on the amount of noise, the optimized
#   values should tend towards 1
print(f&quot;a = {a.value[0]:3f}\n&quot; \
f&quot;b = {b.value[0]:3f}\n&quot; \
f&quot;c = {c.value[0]:3f}&quot;)

The original model with IMODE=3 solves with 0.32 sec to build the model in Gekko, 6.88 sec once Gekko compiles and solves the problem with 2.92 sec of that time spent by the solver.

Total Build time: 0.3288764953613281
Total Solve time: 6.876295566558838
Solver time: 2.9223
a = 1.021506
b = 0.978350
c = 1.007642

Original (IMODE=3) with Timing

from gekko import GEKKO
import numpy as np
import time

start = time.time()
m = GEKKO()  # instantiate gekko model

# instantiate free variables
a = m.FV(lb=0, ub=2)
a.STATUS = 1
b = m.FV(lb=0, ub=2)
b.STATUS = 1
c = m.FV(lb=0, ub=2)
c.STATUS = 1

n_eqs1 = 1000  # number of equations in dataset1
n_eqs2 = 500  # number of equations in dataset2
n_terms = 12  # number of terms in each equation
noise_scl = 1  # amount of noise represented as the std of the nrml distributions

# training datasets
x = {
    &quot;dataset1&quot;: np.arange(n_eqs1)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, \
                       size=(n_eqs1, n_terms)),
    &quot;dataset2&quot;: np.arange(n_eqs2)[:, np.newaxis]
    + np.random.normal(loc=0, scale=noise_scl, \
                       size=(n_eqs2, n_terms)),
}
# response
y = np.arange(n_eqs1)

for x_ds in x.values():
    for i in range(x_ds.shape[0]):
        # minimize equations
        m.Minimize(
            (
                y[i]
                - (
                    x_ds[i, 0] * a
                    + x_ds[i, 1] * a**2
                    + x_ds[i, 2] * a * b
                    + x_ds[i, 3] * a * (b**2)
                    + x_ds[i, 4] * (a**2) * b
                    + x_ds[i, 5] * (a**2) * (b**2)
                    + x_ds[i, 6] * c
                    + x_ds[i, 7] * (c**2)
                    + x_ds[i, 8] * c * b
                    + x_ds[i, 9] * c * (b**2)
                    + x_ds[i, 10] * (c**2) * b
                    + x_ds[i, 11] * (c**2) * (b**2)
                )
                / n_terms
            )
            ** 2
        )

m.options.IMODE = 3
print(&#39;Total Build time:&#39;,time.time()-start)

start = time.time()
m.solve(disp=False)
print(&#39;Total Solve time:&#39;,time.time()-start)
print(&#39;Solver time:&#39;,m.options.SOLVETIME)

# depending on the amount of noise,
#   the optimized values should tend towards 1
print(f&quot;a = {a.value[0]:3f}\n&quot; \
      f&quot;b = {b.value[0]:3f}\n&quot; \
      f&quot;c = {c.value[0]:3f}&quot;)

huangapple
  • 本文由 发表于 2023年6月1日 08:10:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377964.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定