使用pymoo求解双目标整数优化问题时遇数组重塑错误求助
解决Pymoo NSGA-II整数变量双目标优化的维度不匹配错误
问题重现
使用Pymoo的NSGA-II求解5个整数变量的双目标优化问题时,出现以下错误:
Exception: ('Problem Error: F can not be set, expected shape (100, 2) but provided (1, 2)', ValueError('cannot reshape array of size 2 into shape (100,2)'))
原代码如下:
import numpy as np from pymoo.core.problem import ElementwiseProblem from pymoo.algorithms.moo.nsga2 import NSGA2 # from pymoo.factory import get_sampling, get_crossover, get_mutation from pymoo.optimize import minimize from pymoo.operators.sampling.rnd import IntegerRandomSampling from pymoo.operators.crossover.sbx import SBX from pymoo.operators.mutation.pm import PM from pymoo.visualization.scatter import Scatter # Custom 2-objective, 5-integer optimization problem class MyProblem(Problem): def __init__(self): super().__init__( n_var=5, n_obj=2, n_ieq_constr=0, xl=np.array([0,0,0,0,0]), # Lower bounds for variables xu=np.array([10,10,10,10,10]), # Upper bounds for variables vtype=int ) def _evaluate(self, x, out, *args, **kwargs): # Objective functions f1 = np.sum(x ** 2) # Minimize the sum of squares f2 = np.sum((x - 5) ** 2) # Minimize the sum of squared deviations from 5 # Assign objectives to the output out["F"] = [f1, f2] # Instantiate the custom problem problem = MyProblem() # NSGA-II algorithm setup algorithm = NSGA2( pop_size=100, n_offsprings=50, sampling=IntegerRandomSampling(), crossover=SBX(prob=1.0, eta=3.0), mutation=PM(prob=1.0, eta=3.0) ) # Optimize the problem using NSGA-II res = minimize( problem, algorithm, termination=('n_gen', 100), seed=1, save_history=True, verbose=True ) # Visualize the Pareto front plot = Scatter() plot.add(problem.pareto_front(), plot_type="line", color="black", alpha=0.7) plot.add(res.F, color="red", s=30, label="NSGA-II") plot.show()
错误原因
- Problem类继承错误:导入了
ElementwiseProblem但继承了未定义的Problem类,且ElementwiseProblem是逐个体评估的,而pymoo.core.problem.Problem要求批量处理所有个体(输入x形状为(pop_size, n_var)),你的_evaluate写法针对单个个体,导致批量处理时维度不匹配。 - 交叉变异算子不匹配整数变量:
SBX和PM默认处理连续变量,未设置整数类型约束,可能导致变量变为非整数。 - 帕累托前沿未定义:自定义问题没有内置
pareto_front()方法,直接调用会报错。
修正后的代码
import numpy as np from pymoo.core.problem import ElementwiseProblem from pymoo.algorithms.moo.nsga2 import NSGA2 from pymoo.optimize import minimize from pymoo.operators.sampling.rnd import IntegerRandomSampling from pymoo.operators.crossover.sbx import SBX from pymoo.operators.mutation.pm import PM from pymoo.visualization.scatter import Scatter from itertools import product # Custom 2-objective, 5-integer optimization problem class MyProblem(ElementwiseProblem): def __init__(self): super().__init__( n_var=5, n_obj=2, n_ieq_constr=0, xl=np.array([0,0,0,0,0]), # Lower bounds for variables xu=np.array([10,10,10,10,10]), # Upper bounds for variables vtype=int ) def _evaluate(self, x, out, *args, **kwargs): # Objective functions f1 = np.sum(x ** 2) # Minimize the sum of squares f2 = np.sum((x - 5) ** 2) # Minimize the sum of squared deviations from 5 # Assign objectives as numpy array (shape (2,) for single individual) out["F"] = np.array([f1, f2]) # Instantiate the custom problem problem = MyProblem() # NSGA-II algorithm setup: Configure SBX and PM for integer variables algorithm = NSGA2( pop_size=100, n_offsprings=50, sampling=IntegerRandomSampling(), # Set vtype=int for SBX to handle integers crossover=SBX(prob=1.0, eta=3.0, vtype=int), # Set vtype=int for PM to handle integers mutation=PM(prob=1.0, eta=3.0, vtype=int) ) # Optimize the problem using NSGA-II res = minimize( problem, algorithm, termination=('n_gen', 100), seed=1, save_history=True, verbose=True ) # Generate true Pareto front for this problem def true_pareto_front(): # Pareto optimal solutions have each x_i either 0 or 5 (trade-off between f1 and f2) pareto_F = [] for combo in product([0,5], repeat=5): x = np.array(combo) f1 = np.sum(x**2) f2 = np.sum((x-5)**2) pareto_F.append([f1, f2]) # Remove duplicate points pareto_F = np.unique(np.array(pareto_F), axis=0) return pareto_F # Visualize results plot = Scatter(title="Pareto Front Comparison", legend=True) plot.add(true_pareto_front(), plot_type="line", color="black", alpha=0.7, label="True Pareto Front") plot.add(res.F, color="red", s=30, label="NSGA-II Solutions") plot.show()
关键修改说明
- 继承正确的Problem类:将
class MyProblem(Problem)改为class MyProblem(ElementwiseProblem),匹配逐个体评估的_evaluate实现。 - 算子适配整数变量:在
SBX和PM中添加vtype=int参数,确保交叉变异后输出为整数。 - 定义真实帕累托前沿:手动生成该问题的帕累托最优解(所有变量取0或5的组合),用于可视化对比。
- 输出numpy数组:将
out["F"] = [f1, f2]改为out["F"] = np.array([f1, f2]),符合ElementwiseProblem的输出格式要求。
内容的提问来源于stack exchange,提问作者Dino Hsu
相关产品推荐
相关产品推荐

