基于Hyperopt与Gekko的超参数搜索空间定义问题求助
超参数优化搜索空间定义问题:Hyperopt+Gekko得到全0解的修复
已知优化问题的最优解为[0,4050,2100,2100,1200,0,0,450,150],但使用Hyperopt结合Gekko进行超参数优化时,两种搜索空间定义方式均得到全0解,以下是问题分析和修复方案:
原代码问题分析
1. 搜索空间定义错误
- 第一种方式:
hp.choice('x1', IV[0])是从IV[0]的27个0/1元素中选单个值,但每个x1应该是长度为27的0-1向量(对应每个电容型号的选择),这种定义完全不符合需求,Hyperopt每次只传单个0或1,而非向量。 - 第二种方式:
hp.quniform('x1',0,1,Nc)参数错误,quniform的步长参数q是间隔值,0到1之间步长27只会返回0,无法覆盖有效候选值。
2. 目标函数逻辑错误
在objective函数中,先创建Gekko的二维变量数组x,随后直接将x1-x9赋值为params的数值,完全覆盖了Gekko的优化变量,导致Gekko实际求解的是固定参数下的问题,而非利用Hyperopt搜索最优参数组合。
修复方案
核心思路
每个节点最多选择一个电容型号(或不选),因此可以将每个节点的选择简化为整数索引:0代表不安装电容,127对应选择`Qc`中第026个型号。Hyperopt搜索每个节点的索引值,再在目标函数中转换为对应的电容容量,结合Gekko处理约束并计算目标值。
修正后的代码
from gekko import GEKKO import numpy as np from hyperopt import fmin, tpe, hp from hyperopt import STATUS_OK, STATUS_FAIL # 原始数据 P = [13105.11598923, 11261.13968067, 10103.92043191, 8199.51950018, 6411.29606705, 4753.51971915, 3897.77624628, 2659.30922847, 1639.99999999] Q = [0., 4434.40470446, 3808.26080152, 3262.6022579, 1256.88696212, 0., 0., 352.26399841, 200.00000001] V = [22836.72949, 22709.57526, 22158.26541, 21804.24667, 21094.79492, 20864.73522, 20445.8738, 19749.82457, 19262.43063] R = [1.2330e-04, 1.4000e-05, 7.4630e-04, 6.9840e-04, 1.9831e-03, 9.0530e-04, 2.0552e-03, 4.7953e-03, 5.3434e-03] Kc = [0.5, 0.35, 0.253, 0.22, 0.276, 0.183, 0.228, 0.17, 0.207, 0.201, 0.193, 0.187, 0.211, 0.176, 0.179, 0.170, 0.189, 0.187, 0.183, 0.180, 0.195, 0.174, 0.188, 0.170, 0.183, 0.182, 0.179] Qc = [150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, 1950, 2100, 2250, 2400, 2550, 2700, 2850, 3000, 3150, 3300, 3450, 3600, 3750, 3900, 4050] Ke = 168 T = 24 * 365 N = len(Q) Nc = len(Qc) # 定义搜索空间:每个节点选择0(不装)或1~27(对应Qc的索引+1) space = { f'x{i+1}': hp.choice(f'x{i+1}', list(range(Nc + 1))) for i in range(N) } def objective(params): m = GEKKO(remote=False) # 每个节点的电容选择:0代表不装,否则取对应Qc的值 qc_selected = [Qc[idx-1] if idx !=0 else 0 for idx in params.values()] # 约束:总电容容量不超过总Q的和 total_qc = m.sum(qc_selected) m.Equation(total_qc <= m.sum(Q)) # 目标函数计算 obj = 0 for i in range(N): q_i = Q[i] - qc_selected[i] loss_term = R[i] * T * Ke * (1 / V[i]**2) * (P[i]**2 + q_i**2) cost_term = Kc[params[f'x{i+1}']-1] * qc_selected[i] if params[f'x{i+1}'] !=0 else 0 obj += loss_term + cost_term m.Minimize(obj) m.solver_options = [ 'minlp_gap_tol 1e-5', 'minlp_maximum_iterations 10000', 'minlp_max_iter_with_int_sol 2000' ] m.options.SOLVER = 1 try: m.solve(disp=False, debug=False) obj_val = m.options.objfcnval status = STATUS_OK except Exception as e: obj_val = np.inf status = STATUS_FAIL m.cleanup() return {'loss': obj_val, 'status': status, 'qc_selected': qc_selected} # 运行Hyperopt搜索 best = fmin(objective, space, algo=tpe.suggest, max_evals=100) sol = objective(best) # 转换最优解为对应Qc值 best_qc = [] for i in range(N): idx = best[f'x{i+1}'] best_qc.append(Qc[idx-1] if idx !=0 else 0) print(f"解状态: {sol['status']}") print(f"目标函数值: {sol['loss']:.2f}") print(f"最优电容配置: {best_qc}")
关键修正点
- 搜索空间:每个节点的搜索范围改为027的整数,0对应不装电容,127对应
Qc的具体型号索引。 - 目标函数逻辑:不再覆盖Gekko变量,而是将Hyperopt传入的索引转换为实际电容容量,结合Gekko处理约束并计算目标值。
- 约束简化:直接利用选择的电容容量总和进行约束,避免复杂的二维0-1变量数组。
内容的提问来源于stack exchange,提问作者Chaymae Makri
相关产品推荐
相关产品推荐

