在工程设计和科学研究中,我们经常遇到需要同时优化多个相互冲突的目标函数的问题。这类问题被称为多目标优化问题(MOP),其数学表达可以表示为:
Minimize F(x) = (f₁(x), f₂(x), ..., fₘ(x))
subject to x ∈ Ω
其中m≥2表示目标函数的数量,Ω表示决策变量的可行域。与单目标优化不同,多目标优化通常没有唯一的最优解,而是存在一组无法被其他解全面超越的Pareto最优解集。
NSGA-II(Non-dominated Sorting Genetic Algorithm II)是由Deb等人于2002年提出的改进多目标遗传算法,它通过三个关键机制有效解决了多目标优化问题:
实际工程应用中,约78%的多目标优化案例采用NSGA-II或其变种算法,其在收敛性和分布性方面的平衡使其成为最成功的多目标进化算法之一。
非支配排序是NSGA-II区分个体优劣的核心操作。对于最小化问题,解x₁支配x₂当且仅当:
∀i∈{1,...,m}: fᵢ(x₁) ≤ fᵢ(x₂)
且 ∃j∈{1,...,m}: fⱼ(x₁) < fⱼ(x₂)
快速非支配排序的具体步骤包括:
python复制# Python伪代码示例
def fast_non_dominated_sort(population):
fronts = [[]]
for p in population:
p.domination_count = 0
p.dominated_solutions = []
for q in population:
if p.dominates(q):
p.dominated_solutions.append(q)
elif q.dominates(p):
p.domination_count += 1
if p.domination_count == 0:
p.rank = 1
fronts[0].append(p)
i = 0
while fronts[i]:
next_front = []
for p in fronts[i]:
for q in p.dominated_solutions:
q.domination_count -= 1
if q.domination_count == 0:
q.rank = i+2
next_front.append(q)
i += 1
fronts.append(next_front)
return fronts[:-1]
拥挤距离用于衡量同一非支配层中个体周围的解密度,计算公式为:
crowding_distance = Σ (fᵢ⁺¹ - fᵢ⁻¹)/(fᵢ_max - fᵢ_min)
其中fᵢ⁺¹和fᵢ⁻¹分别是个体在目标i上相邻的两个解的目标值,fᵢ_max和fᵢ_min是该目标函数的极值。边界个体被赋予无限拥挤距离以保证它们能被保留。
NSGA-II采用(μ+λ)选择策略,具体步骤:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 种群大小 | 50-500 | 问题维度越高需要越大种群 |
| 交叉概率 | 0.7-0.9 | 控制解空间探索能力 |
| 变异概率 | 1/n (n为变量数) | 保证每个变量都有变异机会 |
| 分布指数(η_c) | 15-30 | SBX交叉的分布指数 |
| 分布指数(η_m) | 15-30 | 多项式变异的分布指数 |
| 最大代数 | 100-500 | 取决于问题复杂度 |
实际应用中,建议先使用默认参数进行初步测试,然后根据Pareto前沿的分布情况调整参数。收敛速度过快可能意味着种群多样性不足,需要增加变异概率或分布指数。
python复制import numpy as np
from deap import algorithms, base, creator, tools
# 定义多目标最小化问题
creator.create("FitnessMin", base.Fitness, weights=(-1.0, -1.0))
creator.create("Individual", list, fitness=creator.FitnessMin)
def initialize_NSGA2():
toolbox = base.Toolbox()
# 定义变量范围和各目标函数
toolbox.register("attr_float", np.random.uniform, -10, 10)
toolbox.register("individual", tools.initRepeat, creator.Individual,
toolbox.attr_float, n=30) # 30维决策变量
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
# 定义评价函数(以ZDT1测试问题为例)
def evaluate(individual):
f1 = individual[0]
g = 1 + 9 * np.sum(individual[1:]) / (len(individual)-1)
f2 = g * (1 - np.sqrt(f1/g))
return f1, f2
toolbox.register("evaluate", evaluate)
toolbox.register("mate", tools.cxSimulatedBinaryBounded,
eta=20.0, low=-10, up=10)
toolbox.register("mutate", tools.mutPolynomialBounded,
eta=20.0, low=-10, up=10, indpb=1.0/30)
toolbox.register("select", tools.selNSGA2)
return toolbox
def run_NSGA2():
toolbox = initialize_NSGA2()
pop = toolbox.population(n=100)
hof = tools.ParetoFront()
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", np.mean, axis=0)
stats.register("std", np.std, axis=0)
stats.register("min", np.min, axis=0)
stats.register("max", np.max, axis=0)
algorithms.eaMuPlusLambda(pop, toolbox, mu=100, lambda_=100,
cxpb=0.9, mutpb=0.1, ngen=250,
stats=stats, halloffame=hof)
return pop, stats, hof
实际工程问题通常包含各种约束条件,NSGA-II处理约束的常用方法包括:
罚函数法:将约束违反程度加入目标函数
python复制def evaluate(individual):
x = np.array(individual)
# 目标函数计算
f1 = x[0]
g = 1 + 9 * np.sum(x[1:]) / (len(x)-1)
f2 = g * (1 - np.sqrt(f1/g))
# 约束计算(示例)
c1 = 1 - (f2 / 0.85 - f1 / 0.35)
c2 = 1 - (f2 / 0.6 - f1 / 0.15)
violation = max(0, c1) + max(0, c2)
return f1 + 100*violation, f2 + 100*violation
约束支配原则:修改支配关系定义,优先满足约束的解
当目标维度m≥4时,NSGA-II面临选择压力不足的问题。改进策略包括:
NSGA-II的天然并行性可通过以下方式加速:
评估并行化:使用multiprocessing并行评估个体
python复制from multiprocessing import Pool
def parallel_evaluate(population):
with Pool(4) as p: # 使用4个进程
fitnesses = p.map(toolbox.evaluate, population)
for ind, fit in zip(population, fitnesses):
ind.fitness.values = fit
toolbox.register("map", parallel_evaluate)
岛模型:将种群分为多个子种群并行进化,定期迁移
| 指标 | 公式 | 解释 |
|---|---|---|
| 世代距离(GD) | (Σdᵢ²)/n | 衡量与真实前沿的距离 |
| 反向世代距离(IGD) | (Σdᵢ)/ | P* |
| 超体积(HV) | 目标空间被支配的体积 | 综合考虑收敛性和多样性 |
| 分布性(Δ) | (dₑ + dₗ + Σ | dᵢ - d̄ |
二维/三维目标空间图:直观展示Pareto前沿形状
python复制import matplotlib.pyplot as plt
def plot_pareto_front(population):
fits = np.array([ind.fitness.values for ind in population])
plt.scatter(fits[:,0], fits[:,1], c='blue', s=20)
plt.xlabel('Objective 1')
plt.ylabel('Objective 2')
plt.title('Pareto Front Approximation')
plt.show()
平行坐标图:适用于高维目标可视化
决策变量重要性分析:识别关键设计变量
以ZDT测试函数集为例,NSGA-II的典型表现:
| 测试函数 | GD(均值±标准差) | IGD(均值±标准差) | HV(均值±标准差) |
|---|---|---|---|
| ZDT1 | 0.0021±0.0003 | 0.0032±0.0004 | 0.865±0.012 |
| ZDT2 | 0.0018±0.0002 | 0.0029±0.0003 | 0.512±0.008 |
| ZDT3 | 0.0025±0.0004 | 0.0041±0.0006 | 0.774±0.015 |
汽车悬架系统优化案例:
优化变量包括弹簧刚度、阻尼系数等8个参数。经过200代NSGA-II优化后,得到的Pareto前沿揭示了设计目标间的权衡关系,工程师可根据优先级选择合适方案。
微电网多目标调度问题:
采用改进的NSGA-II处理混合整数变量和复杂约束,最终方案集比传统加权法获得更全面的解决方案。
神经网络多目标调优:
通过NSGA-II探索超参数空间,获得不同准确率-复杂度权衡下的模型集合,用户可根据部署环境选择合适模型。
局部搜索增强:在NSGA-II中嵌入SQP等局部搜索方法
python复制def local_search(individual, max_iter=10):
# 使用scipy的优化器进行局部搜索
from scipy.optimize import minimize
def local_eval(x):
individual[:] = x
return toolbox.evaluate(individual)
res = minimize(local_eval, individual,
method='SLSQP',
options={'maxiter': max_iter})
individual[:] = res.x
individual.fitness.values = local_eval(individual)
return individual
toolbox.register("local_search", local_search)
多种群协同进化:不同种群采用不同策略并行进化
动态交叉概率:根据种群多样性调整
python复制def adaptive_cxpb(gen, max_gen):
base_p = 0.9
min_p = 0.6
return max(min_p, base_p * (1 - gen/max_gen))
变异强度自适应:早期大变异探索,后期小变异微调
早熟收敛:
计算耗时过长:
前沿分布不均:
经过多个项目的实践验证,我发现NSGA-II在解决复杂工程问题时,初始种群的多样性对最终结果影响很大。建议采用拉丁超立方抽样等实验设计方法生成初始种群,而非完全随机生成。另外,当目标函数数量超过5个时,传统NSGA-II的选择压力会显著下降,此时考虑采用NSGA-III等改进算法可能更为合适。