多目标优化基于NSGA-II

多目标优化问题在汽车设计、生产制造和金融等领域常见,如同时追求高强度和轻量化。帕累托最优解集提供了一系列解决方案。NSGA-II算法结合遗传算法,通过快速非支配排序和拥挤距离计算寻找帕累托前沿,避免解的聚集。
摘要由CSDN通过智能技术生成

简介

多目标优化是优化问题中经常遇到的一类问题,解决这类问题的方法通常有直接求和法、加权求和法、帕累托最优集合法等。前两种方法将多个目标值相加的方法过于简单粗暴,而且不同量纲的量相加之后的实际意义也有待商榷。而帕累托集合就比较好地解决了这一缺点。

多目标优化问题生活中很常见,比如汽车车身零部件设计中,要求设计的零件刚度要很大,同时质量很轻,这就是一个两目标问题,同时他还有一些条件约束,比如模态约束,尺寸约束等。在生产制造过程中,我们希望生产线的产能尽可能高,同时又想要生产的成本尽可能低,最好碳排放还很低。再者金融领域中,我们希望投入的资金少,风险小,并且获得的利益最大,这就是一个三目标问题,但是掰着脚趾头都知道同时达到这三个目标是不可能的,多目标优化就是给出他的一些列可能的选择,成为帕累托最优解集,然后用户自己去评判想选谁,哈哈,是不是很鸡肋。

总而言之,在现实生活中有很多的问题都是由互相冲突和影响的多个目标组成,这些目标不可能同时达到最优的状态,我们通常会尽量让这些目标在一定的区域内达到最佳的状态,这就是多目标优化。

帕累托前沿等概念

定义1:帕累托占优(Pareto Dominate)

在这里插入图片描述

 也可称为a支配b,如果对于一个决策变量,不存在其他决策变量能够支配他,那么就称该决策变量为非支配解。

定义2:帕累托最优解

如果在整个参数空间内不存在任何一个决策向量帕累托占优某一个决策向量,就称该决策向量是帕累托最优解。所有帕累托最优解组成的集合称为帕累托最优解集合。

定义3:绝对最优解、非劣解、帕累托前沿
在决策变量的集合S中,有一个变量X*,对于任意的X属于S,存在目标函数F(X*)<=F(X),则称X*为目标函数的 绝对最优解
在决策变量的集合S中,有一个变量X-,对于任意的X属于S,存在目标函数F(X)<=F(X-) ,则称X-为目标函数的 最优解(非劣解) 
多目标优化问题的非劣解一般不止一个,由所有非劣解构成的集合称为 非劣解集
所有非劣解对应的目标函数构成了非劣最优目标域也就是帕累托前沿。

NSGA-II算法

该算法是引入了帕累托最优集合思想的遗传算法。

 快速非支配排序步骤:快速非支配排序就是将解集分解为不同次序的Pareto前沿的过程。
它可以描述为:

  • 1.为每个解p分配两个关键量:支配p的解个数n_p以及被p支配的解集S_p;
  • 2.设置i=1,将n_p=0的个体归入F_i;
  • 3.对于F_i中的个体,遍历每个解p的S_p,将其中每个解的n_p减1;
  • 4.i+=1,将n_p=0的解归入F_i;
  • 5.重复3、4,直到解集中所有个体都被归入某一个F_i。

python实现快速非支配排序:

# 进行快速非支配排序
def fast_non_dominate_sorting(popsize, chrom):
    s, n = {}, {}
    front, rank = {}, {}
    front[0] = []
    iter_range = popsize  # 如果不是亲子代混合,就是100+x个需要比较
    for p in range(iter_range):
        s[p] = []
        n[p] = 0
        for q in range(iter_range):
            if dominate(p, q, chrom):  # if p dominates q for three objectives
                if q not in s[p]:
                    s[p].append(q)  # s[p] is the set of solutions dominated by p
            elif dominate(q, p, chrom):  # if q dominates p for three objectives
                n[p] = n[p] + 1  # n[p] is the set of solutions dominating p, 3 obj
        if n[p] == 0:
            rank[p] = 0  # p belongs to front 0
            if p not in front[0]:
                front[0].append(p)

    i = 0
    while front[i]:
        Q = []  # Used to store the members of the next front
        for p in front[i]:
            for q in s[p]:
                n[q] = n[q] - 1
                if n[q] == 0:
                    rank[q] = i + 1
                    if q not in Q:
                        Q.append(q)
        i = i + 1
        front[i] = Q

    del front[len(front) - 1]
    return front, rank

计算拥挤距离,避免选出的解扎堆聚集在一起

def crowding_distance_calculation(front, chrom):
    if np.array(front).ndim != 1:
        distance = {m: 0 for m in front}  # {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0}
        for o in range(3):  # dual objective, we have three obj, so this should be adapted
            obj = {m: chrom[m][o] for m in front}
            sorted_keys = sorted(obj, key=obj.get)
            distance[sorted_keys[0]] = distance[sorted_keys[len(front) - 1]] = 999999999999
            for i in range(1, len(front) - 1):
                if len(set(obj.values())) == 1:
                    distance[sorted_keys[i]] = distance[sorted_keys[i]]
                else:
                    distance[sorted_keys[i]] = distance[sorted_keys[i]] + (
                            obj[sorted_keys[i + 1]] - obj[sorted_keys[i - 1]]) / (
                                                       obj[sorted_keys[len(front) - 1]] - obj[sorted_keys[0]])
        # The overall crowding distance is the sum of distance corresponding to each objective
        return distance
    elif np.array(front).ndim == 1:
        distance = np.zeros(len(front))
        objs = np.array([chrom[front[i]] for i in range(len(front))])
        for o in range(3):  # dual objective, we have three obj, so this should be adapted
            obj = {m: objs[m][o] for m in range(len(front))}
            sorted_keys = sorted(obj, key=obj.get)
            distance[sorted_keys[0]] = distance[sorted_keys[-1]] = 999999999999
            if len(distance) == 1:
                break
            else:
                for i in range(1, len(front) - 1):
                    distance[sorted_keys[i]] = distance[sorted_keys[i]] + (
                            obj[sorted_keys[i + 1]] - obj[sorted_keys[i - 1]]) / (
                                                       obj[sorted_keys[len(front) - 1]] - obj[sorted_keys[0]])
        return objs[np.argmin(distance)], front[np.argmin(distance)]

迭代100代后实现的效果如下图:

NSGA-II求解出的初始种群与最终种群

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TUUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值