0

我目前正在使用化学反应网络理论 (CRNT) 来研究胰岛素信号传导的双稳态。使用 CRNT,我需要解决具有约束的全局优化问题以获得鞍节点。我已经研究了多种算法来解决我的问题,但是,由于我的问题是非线性和非凸的,并且可能是多模态的,我发现只有少数几种方法是合适的。我发现差分进化(DE)似乎是最合适的开始。由于我没有优化领域的专业知识,我一直在寻找一个 Python 库,它可以像我的目标函数和约束的黑盒一样。经过快速搜索,我发现 Mystic 提供了一个看起来相当简单易用的 DE 功能。但是,当我实现 DE 功能时,

我已经在一个非常简单的问题上实现了 DE 函数,并获得了很好的结果。除此之外,我还尝试了 npop、gtol 和 maxiter 的较大值。npop 大约 5000 的值提供了接近我想要的范围的值,但是有些值仍然不在我给出的范围内(可能非常大的 npop 值会给我想要的结果)。似乎没有什么可以解决参数值超出我指定的范围的问题。下面是我正在运行的确切代码。

import mystic
from mystic.penalty import quadratic_equality
from mystic.solvers import diffev2
from mystic.constraints import as_constraint

def objective(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    c1 = -a2*(k34 + k39)/(c4*k34*k93)
    c2 = c4*k34*k93*(a1 - a2)*(k15 + k16)/(a2*k16*k51*(k34 + k39))
    c3 = -a1*(k27 + k28)/(c4*k27*k82)
    c5 = -(a1 - a2)/k16
    c6 = -a1/k27
    c7 = -a2/k34
    return 1e10*((1.0*c1**2*c4*k34*k51*k82*k93 + 1.0*c1**2*k27*k34*k51*k93 + 1.0*c1**2*k28*k34*k51*k93 - 2.0*c1*c2*c4*k16*k51*k82*k93 +
     1.0*c1*c2*c4*k34*k51*k82*k93 - 2.0*c1*c2*k16*k27*k51*k93 - 2.0*c1*c2*k16*k28*k51*k93 + 1.0*c1*c2*k27*k34*k51*k93 + 1.0*c1*c2*k28*k34*k51*k93 -
     2.0*c1*c3*c4*k27*k51*k82*k93 - 1.0*c1*c3*c4*k34*k51*k82*k93 - 1.0*c1*c3*k27*k34*k51*k82 - 1.0*c1*c3*k27*k39*k51*k82 - 1.0*c1*c4**2*k34*k51*k82*k93 +
     1.0*c1*c4*k15*k34*k82*k93 + 1.0*c1*c4*k16*k34*k82*k93 - 1.0*c1*c4*k27*k34*k51*k93 - 1.0*c1*c4*k28*k34*k51*k93 + 1.0*c1*k15*k27*k34*k93 + 1.0*c1*k15*k28*k34*k93 +
     1.0*c1*k16*k27*k34*k93 + 1.0*c1*k16*k28*k34*k93 - 1.0*c2*c3*k16*k34*k51*k82 - 1.0*c2*c3*k16*k39*k51*k82 - 1.0*c2*c3*k27*k34*k51*k82 - 1.0*c2*c3*k27*k39*k51*k82 -
     1.0*c2*c4*k16*k34*k51*k82 - 1.0*c2*c4*k16*k39*k51*k82 - 1.0*c2*k16*k27*k34*k51 - 1.0*c2*k16*k27*k39*k51 - 1.0*c2*k16*k28*k34*k51 - 1.0*c2*k16*k28*k39*k51 -
     2.0*c3*c4*k15*k27*k82*k93 - 1.0*c3*c4*k15*k34*k82*k93 - 2.0*c3*c4*k16*k27*k82*k93 - 1.0*c3*c4*k16*k34*k82*k93 - 1.0*c3*k15*k27*k34*k82 - 1.0*c3*k15*k27*k39*k82 -
     1.0*c3*k16*k27*k34*k82 - 1.0*c3*k16*k27*k39*k82 - 1.0*c4**2*k15*k34*k82*k93 - 1.0*c4**2*k16*k34*k82*k93 - 1.0*c4*k15*k27*k34*k93 - 1.0*c4*k15*k28*k34*k93 -
     1.0*c4*k16*k27*k34*k93 - 1.0*c4*k16*k28*k34*k93)**2/(k16**2*k27**2*k34**2*k51**2*k82**2*k93**2))

#c1
def penalty1(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    return -a2*(k34 + k39)/(c4*k34*k93)
#c2
def penalty2(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    return c4*k34*k93*(a1 - a2)*(k15 + k16)/(a2*k16*k51*(k34 + k39))

#c3
def penalty3(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    return -a1*(k27 + k28)/(c4*k27*k82)

#c5
def penalty4(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    return -(a1 - a2)/k16

#c6
def penalty5(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    return -a1/k27

#c7
def penalty6(x):
    k15,k51,k16,k82,k28,k27,k93,k39,k34,a1,a2,c4 = x
    return -a2/k34

@quadratic_equality(penalty1, k=1e12)
@quadratic_equality(penalty2, k=1e12)
@quadratic_equality(penalty3, k=1e12)
@quadratic_equality(penalty4, k=1e12)
@quadratic_equality(penalty5, k=1e12)
@quadratic_equality(penalty6, k=1e12)
def penalty(x):
    return 0.0

solver = as_constraint(penalty)

b1 = (1e-1,1e2)
b2 = (1e-1,1e2)
b3 = (1e-1,1e2)
b4 = (1e-1,1e2)
b5 = (1e-1,1e2)
b6 = (1e-1,1e2)
b7 = (1e-1,1e2)
b8 = (1e-1,1e2)
b9 = (1e-1,1e2)
b10 = (-1e-1,0)
b11 = (-1e-1,0)
b12 = (1e-1,1e2)


bounds = [b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12]

#npop should be at least 10*dim, where dim is the number of parameters
result = diffev2(objective, x0=bounds, bounds=bounds, penalty=penalty, npop=120, disp=False, full_output=True, gtol=100, maxiter=6000)

print("")
print("The minimized objection function value:")
print(result[1])
print("")
print("Parameter values:")
print(result[0])

运行它,我得到以下输出。

最小化的反对函数值 1.216082506137729

Parameter values [1.07383892e-01 9.99893116e+01 8.88912946e+01 9.99859090e+01 1.09022526e-01 9.99587677e+01 9.70349805e+01 1.23842240e+01 4.72484236e+00 -1.01491728e-08 -1.01491720e-08 1.00002390 e-01]

如您所见,为参数值提供的向量提供了 -1.01491728e-08 和 -1.01491720e-08 的值,它们应该在 (-0.1,0) 范围内。

我是否只是在 Mystic 中错误地实现或误解了某些东西,或者我是否需要探索不同的算法来解决我的优化问题?如果您建议使用不同的算法会更好,您是否建议我使用散点搜索(SS)?另外,Mystic 是否提供可以执行 SS 的功能,还是我需要自己实现它?

任何帮助,将不胜感激。

4

1 回答 1

1

我是mystic作者。首先要注意的是您正在使用penalty函数。它们不限制优化器的搜索空间,而是对目标添加惩罚,以“鼓励”它在惩罚不为零的情况下在空间中找不到解决方案。所以这是首先要注意的。如果要将解决方案限制在约束有效的空间区域,请constraints改用。

但是,这并不能解决您bounds不被尊重的原因。他们应该是。它们可能不是有原因的,例如您在优化过程中没有找到任何好的解决方案。众所周知,DE 对于具有严格界限的大量参数可能表现不佳。我会附上一个监视器,这样您就可以看到参数如何随时间变化。而且,在这种情况下,如果您看到所有参数都从“有效”变为超出范围,那么您发现了一个错误,请在 GitHub 上报告。

即使在后一种情况下,您也可以通过添加一个使用一系列不等式来确保参数在您选择的范围内的约束对象来更强烈地执行约束......但是,我怀疑正在发生一些可以辨别的事情通过附加一个VerboseMonitor.

mystic确实提供了类似于分散搜索算法的东西。查看mystic.ensemble求解器。

更新:显示我一直得到的结果

>>> mon = mystic.monitors.VerboseMonitor()
>>> result = diffev2(objective, x0=bounds, bounds=bounds, penalty=penalty, npop=40, disp=False, full_output=True, gtol=100, maxiter=6000, itermon=mon)
Generation 0 has ChiSquare: 2070417340.327223
Generation 10 has ChiSquare: 2070417340.327223
Generation 20 has ChiSquare: 1504378818.925922
Generation 30 has ChiSquare: 49226009.999661
Generation 40 has ChiSquare: 49226009.999661
Generation 50 has ChiSquare: 49226009.999661
Generation 60 has ChiSquare: 49226009.999661
Generation 70 has ChiSquare: 26549433.119812
Generation 80 has ChiSquare: 15513978.070527
Generation 90 has ChiSquare: 2637293.216637
Generation 100 has ChiSquare: 2466027.220625
Generation 110 has ChiSquare: 857082.416445
Generation 120 has ChiSquare: 409397.900243
Generation 130 has ChiSquare: 61023.902060
Generation 140 has ChiSquare: 61023.902060
Generation 150 has ChiSquare: 34911.899051
Generation 160 has ChiSquare: 22564.321601
Generation 170 has ChiSquare: 3078.667678
Generation 180 has ChiSquare: 3078.667678
Generation 190 has ChiSquare: 1233.029461
Generation 200 has ChiSquare: 1233.029461
Generation 210 has ChiSquare: 161.823695
Generation 220 has ChiSquare: 43.540529
Generation 230 has ChiSquare: 42.662921
Generation 240 has ChiSquare: 16.988486
Generation 250 has ChiSquare: 16.988486
Generation 260 has ChiSquare: 16.988486
Generation 270 has ChiSquare: 8.237803
Generation 280 has ChiSquare: 8.237803
Generation 290 has ChiSquare: 5.994087
Generation 300 has ChiSquare: 5.597002
Generation 310 has ChiSquare: 5.597002
Generation 320 has ChiSquare: 4.998805
Generation 330 has ChiSquare: 4.722383
Generation 340 has ChiSquare: 4.544368
Generation 350 has ChiSquare: 4.544368
Generation 360 has ChiSquare: 4.332436
Generation 370 has ChiSquare: 3.711041
Generation 380 has ChiSquare: 1.618530
Generation 390 has ChiSquare: 1.342488
Generation 400 has ChiSquare: 1.279087
Generation 410 has ChiSquare: 1.266669
Generation 420 has ChiSquare: 1.233121
Generation 430 has ChiSquare: 1.225398
Generation 440 has ChiSquare: 1.225398
Generation 450 has ChiSquare: 1.224930
Generation 460 has ChiSquare: 1.220611
Generation 470 has ChiSquare: 1.220611
Generation 480 has ChiSquare: 1.219702
Generation 490 has ChiSquare: 1.217958
Generation 500 has ChiSquare: 1.217265
Generation 510 has ChiSquare: 1.217095
Generation 520 has ChiSquare: 1.216879
Generation 530 has ChiSquare: 1.216421
Generation 540 has ChiSquare: 1.216096
Generation 550 has ChiSquare: 1.215315
Generation 560 has ChiSquare: 1.215274
Generation 570 has ChiSquare: 1.215125
STOP("ChangeOverGeneration with {'tolerance': 0.005, 'generations': 100}")
>>> lb,ub = zip(*bounds)
>>> result[0] < ub
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True])
>>> result[0] > lb
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True])
>>> 
于 2019-01-26T00:08:22.023 回答