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

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

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个优化的变量。这些变量在模型中具有很强的交互性,意味着多个变量多次相乘。

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

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

  1. from gekko import GEKKO
  2. import numpy as np
  3. m = GEKKO() # 实例化gekko模型
  4. # 实例化自由变量
  5. a = m.FV(lb=0, ub=2)
  6. a.STATUS = 1
  7. b = m.FV(lb=0, ub=2)
  8. b.STATUS = 1
  9. c = m.FV(lb=0, ub=2)
  10. c.STATUS = 1
  11. n_eqs1 = 1000 # 数据集1中的方程数量
  12. n_eqs2 = 500 # 数据集2中的方程数量
  13. n_terms = 12 # 每个方程中的项数
  14. noise_scl = 1 # 噪声的数量,表示为正态分布的标准差
  15. # 训练数据集
  16. x = {
  17. "dataset1": np.arange(n_eqs1)[:, np.newaxis]
  18. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
  19. "dataset2": np.arange(n_eqs2)[:, np.newaxis]
  20. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
  21. }
  22. # 响应
  23. y = np.arange(n_eqs1)
  24. for x_ds in x.values():
  25. for i in range(x_ds.shape[0]):
  26. # 最小化方程
  27. m.Minimize(
  28. (
  29. y[i]
  30. - (
  31. x_ds[i, 0] * a
  32. + x_ds[i, 1] * a**2
  33. + x_ds[i, 2] * a * b
  34. + x_ds[i, 3] * a * (b**2)
  35. + x_ds[i, 4] * (a**2) * b
  36. + x_ds[i, 5] * (a**2) * (b**2)
  37. + x_ds[i, 6] * c
  38. + x_ds[i, 7] * (c**2)
  39. + x_ds[i, 8] * c * b
  40. + x_ds[i, 9] * c * (b**2)
  41. + x_ds[i, 10] * (c**2) * b
  42. + x_ds[i, 11] * (c**2) * (b**2)
  43. )
  44. / n_terms
  45. )
  46. ** 2
  47. )
  48. m.options.IMODE = 3
  49. m.solve(disp=True)
  50. # 根据噪声的数量,优化值应趋向于1
  51. 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:

  1. from gekko import GEKKO
  2. import numpy as np
  3. m = GEKKO() # instantiate gekko model
  4. # instantiate free variables
  5. a = m.FV(lb=0, ub=2)
  6. a.STATUS = 1
  7. b = m.FV(lb=0, ub=2)
  8. b.STATUS = 1
  9. c = m.FV(lb=0, ub=2)
  10. c.STATUS = 1
  11. n_eqs1 = 1000 # number of equations in dataset1
  12. n_eqs2 = 500 # number of equations in dataset2
  13. n_terms = 12 # number of terms in each equation
  14. noise_scl = 1 # amount of noise represented as the std of the normal distributions
  15. # training datasets
  16. x = {
  17. "dataset1": np.arange(n_eqs1)[:, np.newaxis]
  18. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
  19. "dataset2": np.arange(n_eqs2)[:, np.newaxis]
  20. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
  21. }
  22. # response
  23. y = np.arange(n_eqs1)
  24. for x_ds in x.values():
  25. for i in range(x_ds.shape[0]):
  26. # minimize equations
  27. m.Minimize(
  28. (
  29. y[i]
  30. - (
  31. x_ds[i, 0] * a
  32. + x_ds[i, 1] * a**2
  33. + x_ds[i, 2] * a * b
  34. + x_ds[i, 3] * a * (b**2)
  35. + x_ds[i, 4] * (a**2) * b
  36. + x_ds[i, 5] * (a**2) * (b**2)
  37. + x_ds[i, 6] * c
  38. + x_ds[i, 7] * (c**2)
  39. + x_ds[i, 8] * c * b
  40. + x_ds[i, 9] * c * (b**2)
  41. + x_ds[i, 10] * (c**2) * b
  42. + x_ds[i, 11] * (c**2) * (b**2)
  43. )
  44. / n_terms
  45. )
  46. ** 2
  47. )
  48. m.options.IMODE = 3
  49. m.solve(disp=True)
  50. # depending on the amount of noise, the optimized values should tend towards 1
  51. 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,这是专为数据回归设计的。总建模时间将减少,但求解时间应该是相似的。要减少求解时间,除了尝试更好的初始猜测值、简化模型、缩放数据、去除异常值或减少数据点数量之外,没有太多可以做的。

  1. Total Build time: 0.04206514358520508
  2. Total Solve time: 7.088646650314331
  3. Solver time: 4.3853
  4. a = 0.976090
  5. b = 0.980885
  6. c = 1.048744

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

  1. from gekko import GEKKO
  2. import numpy as np
  3. import time
  4. start = time.time()
  5. m = GEKKO() # 实例化gekko模型
  6. # 实例化自由变量
  7. a = m.FV(lb=0, ub=2)
  8. a.STATUS = 1
  9. b = m.FV(lb=0, ub=2)
  10. b.STATUS = 1
  11. c = m.FV(lb=0, ub=2)
  12. c.STATUS = 1
  13. n_eqs1 = 1000 # 数据集1中的方程数量
  14. n_eqs2 = 500 # 数据集2中的方程数量
  15. n_terms = 12 # 每个方程中的项数
  16. noise_scl = 1 # 代表正态分布标准差的噪声量
  17. # 训练数据集
  18. x = {
  19. "dataset1": np.arange(n_eqs1)[:, np.newaxis]
  20. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
  21. "dataset2": np.arange(n_eqs2)[:, np.newaxis]
  22. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
  23. }
  24. # 响应
  25. y = np.arange(n_eqs1)
  26. # 创建组合数据集
  27. xd = np.vstack((x["dataset1"], x["dataset2"]))
  28. yd = np.append(y, y[:n_eqs2])
  29. yp = m.Param(yd)
  30. x_ds = m.Array(m.Param, n_terms)
  31. for i in range(n_terms):
  32. x_ds[i].value = xd[:, i]
  33. # 最小化方程
  34. m.Minimize((yp - (x_ds[0] * a
  35. + x_ds[1] * a**2
  36. + x_ds[2] * a * b
  37. + x_ds[3] * a * (b**2)
  38. + x_ds[4] * (a**2) * b
  39. + x_ds[5] * (a**2) * (b**2)
  40. + x_ds[6] * c
  41. + x_ds[7] * (c**2)
  42. + x_ds[8] * c * b
  43. + x_ds[9] * c * (b**2)
  44. + x_ds[10] * (c**2) * b
  45. + x_ds[11] * (c**2) * (b**2)
  46. ) / n_terms)**2)
  47. m.options.IMODE = 2
  48. print('Total Build time:', time.time() - start)
  49. start = time.time()
  50. m.solve(disp=False)
  51. print('Total Solve time:', time.time() - start)
  52. print('Solver time:', m.options.SOLVETIME)
  53. # 根据噪声量的不同,优化后的值应趋向于1
  54. print(f"a = {a.value[0]:3f}\n" \
  55. f"b = {b.value[0]:3f}\n" \
  56. f"c = {c.value[0]:3f}")

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

  1. Total Build time: 0.3288764953613281
  2. Total Solve time: 6.876295566558838
  3. Solver time: 2.9223
  4. a = 1.021506
  5. b = 0.978350
  6. c = 1.007642

原始(IMODE=3)带定时

  1. from gekko import GEKKO
  2. import numpy as np
  3. import time
  4. start = time.time()
  5. m = GEKKO() # 实例化gekko模型
  6. # 实例化自由变量
  7. a = m.FV(lb=0, ub=2)
  8. a.STATUS = 1
  9. b = m.FV(lb=0, ub=2)
  10. b.STATUS = 1
  11. c = m.FV(lb=0, ub=2)
  12. c.STATUS = 1
  13. n_eqs1 = 1000 # 数据集1中的方程数量
  14. n_eqs2 = 500 # 数据集2中的方程数量
  15. n_terms = 12 # 每个方程中的项数
  16. noise_scl = 1 # 代表正态分布标准差的噪声量
  17. # 训练数据集
  18. x = {
  19. "dataset1": np.arange(n_eqs1)[:, np.newaxis]
  20. + np.random.normal(loc=0, scale=noise_scl, \
  21. size=(n_eqs1, n_terms)),
  22. "dataset2": np.arange(n_eqs2)[:, np.newaxis]
  23. + np.random.normal(loc=0, scale=noise_scl, \
  24. size=(n_eqs2, n_terms)),
  25. }
  26. # 响应
  27. y = np.arange(n_eqs1)
  28. for x_ds in x.values():
  29. for i in range(x_ds.shape[0]):
  30. # 最小化方程
  31. m.Minimize(
  32. (
  33. y[i]
  34. - (
  35. x_ds[i, 0] * a
  36. + x_ds[i, 1] * a**2
  37. + x_ds[i, 2] * a * b
  38. + x_ds[i, 3] * a * (b**2)
  39. + x_ds[i, 4] * (a**2) * b
  40. + x_ds[i, 5] * (a**2) * (b**2)
  41. + x_ds[i, 6] * c
  42. + x_ds[i, 7] * (c**2)
  43. + x_ds[i, 8] * c * b
  44. + x_ds[i, 9] * c * (b**2)
  45. + x_ds[i, 10] * (c**2) * b
  46. + x_ds[i, 11] * (c
  47. <details>
  48. <summary>英文:</summary>
  49. 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

  1. **Modified for Regression (IMODE=2) with Timing**
  2. ```python
  3. from gekko import GEKKO
  4. import numpy as np
  5. import time
  6. start = time.time()
  7. m = GEKKO() # instantiate gekko model
  8. # instantiate free variables
  9. a = m.FV(lb=0, ub=2)
  10. a.STATUS = 1
  11. b = m.FV(lb=0, ub=2)
  12. b.STATUS = 1
  13. c = m.FV(lb=0, ub=2)
  14. c.STATUS = 1
  15. n_eqs1 = 1000 # number of equations in dataset1
  16. n_eqs2 = 500 # number of equations in dataset2
  17. n_terms = 12 # number of terms in each equation
  18. noise_scl = 1 # amount of noise represented as the std of the normal distributions
  19. # training datasets
  20. x = {
  21. &quot;dataset1&quot;: np.arange(n_eqs1)[:, np.newaxis]
  22. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)),
  23. &quot;dataset2&quot;: np.arange(n_eqs2)[:, np.newaxis]
  24. + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)),
  25. }
  26. # response
  27. y = np.arange(n_eqs1)
  28. # create combined dataset
  29. xd = np.vstack((x[&quot;dataset1&quot;],x[&quot;dataset2&quot;]))
  30. yd = np.append(y,y[:n_eqs2])
  31. yp = m.Param(yd)
  32. x_ds = m.Array(m.Param,n_terms)
  33. for i in range(n_terms):
  34. x_ds[i].value = xd[:,i]
  35. # minimize equations
  36. m.Minimize((yp - ( x_ds[0] * a
  37. + x_ds[1] * a**2
  38. + x_ds[2] * a * b
  39. + x_ds[3] * a * (b**2)
  40. + x_ds[4] * (a**2) * b
  41. + x_ds[5] * (a**2) * (b**2)
  42. + x_ds[6] * c
  43. + x_ds[7] * (c**2)
  44. + x_ds[8] * c * b
  45. + x_ds[9] * c * (b**2)
  46. + x_ds[10] * (c**2) * b
  47. + x_ds[11] * (c**2) * (b**2)
  48. ) / n_terms)**2)
  49. m.options.IMODE = 2
  50. print(&#39;Total Build time:&#39;,time.time()-start)
  51. start = time.time()
  52. m.solve(disp=False)
  53. print(&#39;Total Solve time:&#39;,time.time()-start)
  54. print(&#39;Solver time:&#39;,m.options.SOLVETIME)
  55. # depending on the amount of noise, the optimized
  56. # values should tend towards 1
  57. print(f&quot;a = {a.value[0]:3f}\n&quot; \
  58. f&quot;b = {b.value[0]:3f}\n&quot; \
  59. 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.

  1. Total Build time: 0.3288764953613281
  2. Total Solve time: 6.876295566558838
  3. Solver time: 2.9223
  4. a = 1.021506
  5. b = 0.978350
  6. c = 1.007642

Original (IMODE=3) with Timing

  1. from gekko import GEKKO
  2. import numpy as np
  3. import time
  4. start = time.time()
  5. m = GEKKO() # instantiate gekko model
  6. # instantiate free variables
  7. a = m.FV(lb=0, ub=2)
  8. a.STATUS = 1
  9. b = m.FV(lb=0, ub=2)
  10. b.STATUS = 1
  11. c = m.FV(lb=0, ub=2)
  12. c.STATUS = 1
  13. n_eqs1 = 1000 # number of equations in dataset1
  14. n_eqs2 = 500 # number of equations in dataset2
  15. n_terms = 12 # number of terms in each equation
  16. noise_scl = 1 # amount of noise represented as the std of the nrml distributions
  17. # training datasets
  18. x = {
  19. &quot;dataset1&quot;: np.arange(n_eqs1)[:, np.newaxis]
  20. + np.random.normal(loc=0, scale=noise_scl, \
  21. size=(n_eqs1, n_terms)),
  22. &quot;dataset2&quot;: np.arange(n_eqs2)[:, np.newaxis]
  23. + np.random.normal(loc=0, scale=noise_scl, \
  24. size=(n_eqs2, n_terms)),
  25. }
  26. # response
  27. y = np.arange(n_eqs1)
  28. for x_ds in x.values():
  29. for i in range(x_ds.shape[0]):
  30. # minimize equations
  31. m.Minimize(
  32. (
  33. y[i]
  34. - (
  35. x_ds[i, 0] * a
  36. + x_ds[i, 1] * a**2
  37. + x_ds[i, 2] * a * b
  38. + x_ds[i, 3] * a * (b**2)
  39. + x_ds[i, 4] * (a**2) * b
  40. + x_ds[i, 5] * (a**2) * (b**2)
  41. + x_ds[i, 6] * c
  42. + x_ds[i, 7] * (c**2)
  43. + x_ds[i, 8] * c * b
  44. + x_ds[i, 9] * c * (b**2)
  45. + x_ds[i, 10] * (c**2) * b
  46. + x_ds[i, 11] * (c**2) * (b**2)
  47. )
  48. / n_terms
  49. )
  50. ** 2
  51. )
  52. m.options.IMODE = 3
  53. print(&#39;Total Build time:&#39;,time.time()-start)
  54. start = time.time()
  55. m.solve(disp=False)
  56. print(&#39;Total Solve time:&#39;,time.time()-start)
  57. print(&#39;Solver time:&#39;,m.options.SOLVETIME)
  58. # depending on the amount of noise,
  59. # the optimized values should tend towards 1
  60. print(f&quot;a = {a.value[0]:3f}\n&quot; \
  61. f&quot;b = {b.value[0]:3f}\n&quot; \
  62. 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:

确定