如何使用 scipy.optimize.minimize 和通过数据库更新定义的 x

问题描述 投票:0回答:1

我正在处理一个黑盒优化问题。由于黑盒的性质,向量(或向量集)

x
在优化期间无法以编程方式重新定义。也就是说,
x
本身不会直接传递到黑匣子,而是传递数据库 JSON 文件中定义的一些
x
等效项。在我看来,我必须阅读数据库的内容,以编程方式调用
x
,然后在优化迭代后更新数据库。据我所知,
scipy.optimize.minimize
无法使用以这种方式定义的目标函数。有没有解决方法,或者我必须从头开始定义自己的优化函数?

代码(编辑4)

好吧,这是一段代码,或多或少是我想要实现的目标。

# Sum of sum of squared differences function
def sum_ssd(y1, y2):
    ssd_y1 = np.sum((y1-y1_data)**2)
    ssd_y2 = np.sum((y2-y2_data)**2)
    sum_that = ssd_y1 + ssd_y2
    return sum_that

# Objective function
def objective(x12):
    # Separate opt input into BB inputs
    x1 = x12[:5]
    x2 = x12[5:]
    # Update BB inputs in database
    json_obj[some_index]["x1"]=x1.tolist()
    json_obj[some_index]["x2"]=x2.tolist()
    with open(file_path, "w") as json_fp:
        json.dump(json_obj, json_fp, indent = 4)
    # Black Box - db_param changes with database changes
    y1 = bb(db_param, param1)
    y2 = bb(db_param, param2)
    # Sum of SSDs
    out = sum_ssd(y1, y2)
    return out

# Callback function
def callback(x):
    print(x)
    print(objective(x))

# Set up x0 equivalent
with open(file_path, "r") as json_fp:
    json_obj = json.load(json_fp)
x1 = json_obj[some_index]["x1"]
x2 = json_obj[some_index]["x2"]
x1 = np.asarray(x1)
x2 = np.asarray(x2)
x012 = np.append(x1, x2)

# Perform optimization and finish up
res = sp.optimize.minimize(objective, x012, method='Nelder-Mead', callback=callback, options={'disp':True})

因此,对于这个示例,我有

x1
x2
是 5 个元素的数组,并且为了欺骗
minimize
来处理多变量输入,我使用
x012
。至于为什么是Nelder-Mead,我不知道黑匣子是不是总是可微的,但它总是连续的。当我运行代码时,
minimize
执行,但数据库中的
x1
x2
似乎没有发生任何事情。

编辑:我目前尝试过的...

  1. 根据 @NickODell 的评论,更改数据库的更新方式。
  2. x2.tolist()
    更改为
    [1, 2]
    以查看数据库是否实际更新 - 确实如此。
  3. 创建一个回调函数来向我展示每次迭代后
    x
    objective(x)
    会发生什么。答案是没什么。
  4. 使用其他不可微目标函数的算法,例如“Powell”。不用找了。仅作记录,Nelder-Mead 完成了 14 次迭代(1119 次函数评估),Powell 在放弃之前完成了 1 次迭代(235 次函数评估)。

此外,由于我没有使用可微函数,我认为这不应该是由“爆炸梯度”引起的(参见this)。所以,是的,在这一点上我不知所措,并对这个问题悬赏。我知道这是一个普遍问题 - 没有显示黑匣子的代码或如何定义

param1
param2
的定义,但我希望这里仍然有足够的代码可以为我提供一些帮助。再次感谢。

python scipy scipy-optimize scipy-optimize-minimize
1个回答
0
投票

这个答案表明即使没有回调,与数据库交互也是可行的。

首先我们提供缺失的和平代码,主要是:

  • 一个简单的 JSON 作为数据库
  • 虚拟数据集
  • 虚拟黑匣子功能

例如:

# Create DB:
data = {
    "p": {
        "x1": [1, 2, 3, 4, 5],
        "x2": [6, 7, 8, 9, 0]
    }
}

with open("db.json", "w") as handler:
    json.dump(data, handler)

# Create some datasets:
n = 30
y1_data = np.linspace(0, 1, n)
y2_data = np.linspace(-1, 0, n)


# Whatever black box function:
def bb(db_params, params):
    """No idea of what this function does"""
    return np.sum(db_params * params) * np.linspace(-1, 1, n)

现在我们调整您的代码以在每一步与 JSON 数据库交互:

# Sum of sum of squared differences function
def sum_ssd(y1, y2):
    ssd_y1 = np.sum((y1-y1_data)**2)
    ssd_y2 = np.sum((y2-y2_data)**2)
    sum_that = ssd_y1 + ssd_y2
    return sum_that

# Objective function
def objective(x12):
    
    # Separate opt input into BB inputs
    x1 = x12[:5]
    x2 = x12[5:]
    
    # Write to DB:
    db = {
        "p": {
            "x1": x1.tolist(),
            "x2": x2.tolist()
        }
    } 
    with open("db.json", "w") as handler:
        json.dump(db, handler)
    
    # Black Box - db_param changes with database changes
    # Ensure function signature here!
    y1 = bb(x1, x1)
    y2 = bb(x2, x2)

    # Sum of SSDs
    out = sum_ssd(y1, y2)
    return out


def callback(x):
    with open("db.json", "r") as handler:
        print(json.load(handler))


# Read from DB:
with open("db.json", "r") as handler:
    db = json.load(handler)

x1 = db["p"]["x1"]
x2 = db["p"]["x2"]

x1 = np.asarray(x1)
x2 = np.asarray(x2)

x012 = np.append(x1, x2)

# Perform optimization and finish up
res = optimize.minimize(objective, x012, method='Nelder-Mead', callback=callback)

额外的回调不是必需的,但我们用它来检查 JSON DB 在每一步是否更新内容。可以通过运行当前代码来确认。

#...
#{'p': {'x1': [0.5635924679456159, 0.37744611037456866, 0.16889467850450193, 0.08056540458960171, 0.06987014247935036], 'x2': [-0.4420054776612644, 0.4365207767214855, -0.25828873817490783, 0.2155649422026483, 0.02998456765120435]}}
#{'p': {'x1': [0.5635974343191635, 0.37744623780370357, 0.16888311231741251, 0.0805657374136636, 0.06985568009797576], 'x2': [-0.44201141928424603, 0.43652230546899895, -0.2582863842239018, 0.21555487781815993, 0.029980534312484618]}}
#...
#       message: Optimization terminated successfully.
#       success: True
#        status: 0
#           fun: 15.000000000000522
#             x: [ 5.636e-01  3.774e-01  1.689e-01  8.056e-02  6.985e-02
#                 -4.420e-01  4.365e-01 -2.583e-01  2.156e-01  2.997e-02]
#           nit: 130
#          nfev: 258

参数已更新,通过此设置,优化成功结束。如果您只有一步并且优化成功,您可能已经将正确的解决方案存储到数据库中。

© www.soinside.com 2019 - 2024. All rights reserved.