在ZDT3问题上基于多目标超体积的蚁群优化基准测试#
在本教程中,我们将展示如何使用pygmo运行maco算法,并使用Zitzler、Deb和Thiele(ZDT)测试问题套件中的第3个问题进行基准测试,该问题通常用于在两个目标问题上对多目标算法进行基准测试。
ZDT3问题是一个盒约束的连续双目标问题,由pygmo在zdt类中作为UDP(用户定义问题)提供。
我们现在想要对三种用户定义的算法进行基准测试。由于这是一个多目标问题,我们需要一个能够处理约束的UDA(用户定义算法)。因此,我们将对多目标蚁群优化算法maco、基于分解的多目标进化算法(MOEA/D)moead以及非支配排序遗传算法(NSGA-II)nsga2进行基准测试。
特别是,我们将使用上述三种UDAs,分别采用三种不同的人口规模(即32、64、128),并且每次模拟运行三次(每次使用不同的固定种子)。这个问题的Pareto前沿是已知的,pygmo.zdt问题集中的问题实现了一个称为p_distance的收敛度量,它允许我们检查非支配前沿覆盖已知Pareto前沿的程度。此外,我们将使用hypervolume的概念作为指标来比较不同算法的最终种群。
为了在这些问题上运行UDAs,我们可以编写以下代码:
>>> from pygmo import *
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> pop_sizes=[32, 64, 128]
>>> udp = zdt(prob_id = 3)
>>> hv_moead=[0, 0, 0]
>>> hv_maco=[0, 0, 0]
>>> hv_nsga2=[0, 0, 0]
>>> p_dist_moead=[0, 0, 0]
>>> p_dist_maco=[0, 0, 0]
>>> p_dist_nsga2=[0, 0, 0]
>>> #We run the algos three times each, for 3 different pop-sizes
>>> for j in pop_sizes:
... for i in range(0,3):
... pop_1 = population(prob = udp, size = j, seed = i)
... pop_2 = population(prob = udp, size = j, seed = i)
... pop_3 = population(prob = udp, size = j, seed = i)
...
... hv=hypervolume(pop_1)
... ref_point=hv.refpoint(offset=0.01)
...
... #I store all the pop-sizes results for all the runs:
... #1st seed:
... if j==pop_sizes[0] and i==0:
... first_pop_32_1=pop_1.get_f()
... if j==pop_sizes[1] and i==0:
... first_pop_64_1=pop_1.get_f()
... if j==pop_sizes[2] and i==0:
... first_pop_128_1=pop_1.get_f()
...
... #2nd seed:
... if j==pop_sizes[0] and i==1:
... first_pop_32_2=pop_1.get_f()
... if j==pop_sizes[1] and i==1:
... first_pop_64_2=pop_1.get_f()
... if j==pop_sizes[2] and i==1:
... first_pop_128_2=pop_1.get_f()
...
... #3rd seed:
... if j==pop_sizes[0] and i==2:
... first_pop_32_3=pop_1.get_f()
... if j==pop_sizes[1] and i==2:
... first_pop_64_3=pop_1.get_f()
... if j==pop_sizes[2] and i==2:
... first_pop_128_3=pop_1.get_f()
...
... algo = algorithm(moead(250, 'random'))
... algo_2 = algorithm(maco(gen = 250, ker = j-20, q = 1.0, threshold = 250, n_gen_mark = 47, evalstop=10000, focus=0.0, memory=False))
... algo_3 = algorithm(nsga2(gen = 250))
... algo.set_seed(i+1)
... algo_2.set_seed(i+1)
... algo_3.set_seed(i+1)
... pop_1 = algo.evolve(pop_1)
... pop_2=algo_2.evolve(pop_2)
... pop_3 = algo_3.evolve(pop_3)
...
... #This returns a series of arrays: in each of them it is contained (in this order), the -non-dominated front, -domination list,
... #-domination count, -non-domination rank
... fnds=fast_non_dominated_sorting(pop_1.get_f())
... fnds_2=fast_non_dominated_sorting(pop_2.get_f())
... fnds_3=fast_non_dominated_sorting(pop_3.get_f())
...
... #This returns the first (i.e., best) non-dominated front:
... first_ndf_moead=fnds[0][0]
... first_ndf_maco=fnds_2[0][0]
... first_ndf_nsga2=fnds_3[0][0]
...
... #I store all the pop-sizes non-dominated fronts for all the runs:
... #1st seed:
... if j==pop_sizes[0] and i==0:
... #MOEA/D
... hv_moead[0]=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[0]=udp.p_distance(pop_1)
... first_col_moead_32_1=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_32_1=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[0]=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[0]=udp.p_distance(pop_2)
... first_col_maco_32_1=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_32_1=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[0]=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[0]=udp.p_distance(pop_3)
... first_col_nsga2_32_1=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_32_1=pop_3.get_f()[first_ndf_nsga2,1]
...
... if j==pop_sizes[1] and i==0:
... #MOEA/D
... hv_moead[1]=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[1]=udp.p_distance(pop_1)
... hv_moead[1]=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[1]=udp.p_distance(pop_1)
... first_col_moead_64_1=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_64_1=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[1]=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[1]=udp.p_distance(pop_2)
... first_col_maco_64_1=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_64_1=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[1]=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[1]=udp.p_distance(pop_3)
... first_col_nsga2_64_1=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_64_1=pop_3.get_f()[first_ndf_nsga2,1]
...
... if j==pop_sizes[2] and i==0:
... #MOEA/D
... hv_moead[2]=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[2]=udp.p_distance(pop_1)
... first_col_moead_128_1=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_128_1=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[2]=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[2]=udp.p_distance(pop_2)
... first_col_maco_128_1=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_128_1=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[2]=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[2]=udp.p_distance(pop_3)
... first_col_nsga2_128_1=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_128_1=pop_3.get_f()[first_ndf_nsga2,1]
...
... #2nd seed:
... if j==pop_sizes[0] and i==1:
... #MOEA/D
... hv_moead[0]+=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[0]+=udp.p_distance(pop_1)
... first_col_moead_32_2=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_32_2=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[0]+=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[0]+=udp.p_distance(pop_2)
... first_col_maco_32_2=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_32_2=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[0]+=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[0]+=udp.p_distance(pop_3)
... first_col_nsga2_32_2=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_32_2=pop_3.get_f()[first_ndf_nsga2,1]
...
... if j==pop_sizes[1] and i==1:
... #MOEA/D
... hv_moead[1]+=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[1]+=udp.p_distance(pop_1)
... first_col_moead_64_2=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_64_2=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[1]+=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[1]+=udp.p_distance(pop_2)
... first_col_maco_64_2=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_64_2=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[1]+=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[1]+=udp.p_distance(pop_3)
... first_col_nsga2_64_2=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_64_2=pop_3.get_f()[first_ndf_nsga2,1]
...
... if j==pop_sizes[2] and i==1:
... #MOEA/D
... hv_moead[2]+=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[2]+=udp.p_distance(pop_1)
... first_col_moead_128_2=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_128_2=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[2]+=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[2]+=udp.p_distance(pop_2)
... first_col_maco_128_2=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_128_2=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[2]+=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[2]+=udp.p_distance(pop_3)
... first_col_nsga2_128_2=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_128_2=pop_3.get_f()[first_ndf_nsga2,1]
...
... #3rd seed:
... if j==pop_sizes[0] and i==2:
... #MOEA/D
... hv_moead[0]+=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[0]+=udp.p_distance(pop_1)
... first_col_moead_32_3=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_32_3=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[0]+=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[0]+=udp.p_distance(pop_2)
... first_col_maco_32_3=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_32_3=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[0]+=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[0]+=udp.p_distance(pop_3)
... first_col_nsga2_32_3=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_32_3=pop_3.get_f()[first_ndf_nsga2,1]
...
... if j==pop_sizes[1] and i==2:
... #MOEA/D
... hv_moead[1]+=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[1]+=udp.p_distance(pop_1)
... first_col_moead_64_3=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_64_3=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[1]+=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[1]+=udp.p_distance(pop_2)
... first_col_maco_64_3=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_64_3=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[1]+=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[1]+=udp.p_distance(pop_3)
... first_col_nsga2_64_3=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_64_3=pop_3.get_f()[first_ndf_nsga2,1]
...
... if j==pop_sizes[2] and i==2:
... #MOEA/D
... hv_moead[2]+=hypervolume(pop_1).compute(ref_point)
... p_dist_moead[2]+=udp.p_distance(pop_1)
... first_col_moead_128_3=pop_1.get_f()[first_ndf_moead,0]
... second_col_moead_128_3=pop_1.get_f()[first_ndf_moead,1]
... #MACO
... hv_maco[2]+=hypervolume(pop_2).compute(ref_point)
... p_dist_maco[2]+=udp.p_distance(pop_2)
... first_col_maco_128_3=pop_2.get_f()[first_ndf_maco,0]
... second_col_maco_128_3=pop_2.get_f()[first_ndf_maco,1]
... #NSGA2
... hv_nsga2[2]+=hypervolume(pop_3).compute(ref_point)
... p_dist_nsga2[2]+=udp.p_distance(pop_3)
... first_col_nsga2_128_3=pop_3.get_f()[first_ndf_nsga2,0]
... second_col_nsga2_128_3=pop_3.get_f()[first_ndf_nsga2,1]
正如我们从python脚本中观察到的,我们正在使用三种不同的种群大小(32、64、128)运行三种算法250代,并存储最终的非支配Pareto前沿以及最终种群的超体积和p距离值。 我们现在可以在适应度空间中绘制结果(即,通过在y轴上绘制第二个适应度值,在x轴上绘制第一个适应度值)。此外,我们将打印三种算法和所有种群大小的超体积和p距离值的三次运行的平均值。特别是,向量的第一个元素对应于种群大小32的三次运行的平均值,第二个元素对应于种群大小64的平均值,第三个元素对应于128的平均值。为此,我们编写了以下代码:
>>> print('\n joint hypervolume MOEA/D :\n')
>>> print(np.array(hv_moead)/3)
>>> print('\n joint hypervolume MACO: \n')
>>> print(np.array(hv_maco)/3)
>>> print('\n joint hypervolume NSGA2: \n')
>>> print(np.array(hv_nsga2)/3)
>>> print('\n p-distance MOEA/D: \n')
>>> print(np.array(p_dist_moead)/3)
>>> print('\n p-distance MACO: \n')
>>> print(np.array(p_dist_maco)/3)
>>> print('\n p-distance NSGA-II: \n')
>>> print(np.array(p_dist_nsga2)/3)
joint hypervolume MOEA/D:
[4.68242751 5.2765971 5.57259658]
joint hypervolume MACO:
[4.74695083 5.38002359 5.49987744]
joint hypervolume NSGA2:
[5.45305456 5.58634807 5.65456127]
p-distance MOEA/D:
[0.98580786 0.43830665 0.11202489]
p-distance MACO:
[0.75737982 0.27526069 0.21809924]
p-distance NSGA-II:
[0.01847673 0.00465985 0.00137918]
>>> fig, axes = plt.subplots(nrows=3, ncols=3, sharex='col', sharey='row', figsize=(15,15))
>>> axes[0,0].plot(first_pop_32_1[:,0], first_pop_32_1[:,1], '.', label= 'initial population')
>>> axes[0,0].plot(first_col_moead_32_1, second_col_moead_32_1,'k*', label = 'moead')
>>> axes[0,0].plot(first_col_maco_32_1, second_col_maco_32_1,'ro', label = 'maco')
>>> axes[0,0].plot(first_col_nsga2_32_1, second_col_nsga2_32_1, 'b^', label = 'nsga2')
>>> axes[0,0].legend(loc='upper right')
>>> axes[0,0].set_title('ZDT3: final Pareto front (1st run, pop=32)')
>>> axes[0,1].plot(first_pop_64_1[:,0], first_pop_64_1[:,1], '.', label= 'initial population')
>>> axes[0,1].plot(first_col_moead_64_1, second_col_moead_64_1,'k*', label = 'moead')
>>> axes[0,1].plot(first_col_maco_64_1, second_col_maco_64_1,'ro', label = 'maco')
>>> axes[0,1].plot(first_col_nsga2_64_1, second_col_nsga2_64_1, 'b^', label = 'nsga2')
>>> axes[0,1].legend(loc='upper right')
>>> axes[0,1].set_title('ZDT3: final Pareto front (1st run, pop=64)')
>>> axes[0,2].plot(first_pop_128_1[:,0], first_pop_128_1[:,1], '.', label= 'initial population')
>>> axes[0,2].plot(first_col_moead_128_1, second_col_moead_128_1,'k*', label = 'moead')
>>> axes[0,2].plot(first_col_maco_128_1, second_col_maco_128_1,'ro', label = 'maco')
>>> axes[0,2].plot(first_col_nsga2_128_1, second_col_nsga2_128_1, 'b^', label = 'nsga2')
>>> axes[0,2].legend(loc='upper right')
>>> axes[0,2].set_title('ZDT3: final Pareto front (1st run, pop=128)')
>>> axes[1,0].plot(first_pop_32_2[:,0], first_pop_32_2[:,1], '.', label= 'initial population')
>>> axes[1,0].plot(first_col_moead_32_2, second_col_moead_32_2,'k*', label = 'moead')
>>> axes[1,0].plot(first_col_maco_32_2, second_col_maco_32_2,'ro', label = 'maco')
>>> axes[1,0].plot(first_col_nsga2_32_2, second_col_nsga2_32_2, 'b^', label = 'nsga2')
>>> axes[1,0].legend(loc='upper right')
>>> axes[1,0].set_title('ZDT3: final Pareto front (2nd run, pop=32)')
>>> axes[1,1].plot(first_pop_64_2[:,0], first_pop_64_2[:,1], '.', label= 'initial population')
>>> axes[1,1].plot(first_col_moead_64_2, second_col_moead_64_2,'k*', label = 'moead')
>>> axes[1,1].plot(first_col_maco_64_2, second_col_maco_64_2,'ro', label = 'maco')
>>> axes[1,1].plot(first_col_nsga2_64_2, second_col_nsga2_64_2, 'b^', label = 'nsga2')
>>> axes[1,1].legend(loc='upper right')
>>> axes[1,1].set_title('ZDT3: final Pareto front (2nd run, pop=64)')
>>> axes[1,2].plot(first_pop_128_2[:,0], first_pop_128_2[:,1], '.', label= 'initial population')
>>> axes[1,2].plot(first_col_moead_128_2, second_col_moead_128_2,'k*', label = 'moead')
>>> axes[1,2].plot(first_col_maco_128_2, second_col_maco_128_2,'ro', label = 'maco')
>>> axes[1,2].plot(first_col_nsga2_128_2, second_col_nsga2_128_2, 'b^', label = 'nsga2')
>>> axes[1,2].legend(loc='upper right')
>>> axes[1,2].set_title('ZDT3: final Pareto front (2nd run, pop=128)')
>>> axes[2,0].plot(first_pop_32_3[:,0], first_pop_32_3[:,1], '.', label= 'initial population')
>>> axes[2,0].plot(first_col_moead_32_3, second_col_moead_32_3,'k*', label = 'moead')
>>> axes[2,0].plot(first_col_maco_32_3, second_col_maco_32_3,'ro', label = 'maco')
>>> axes[2,0].plot(first_col_nsga2_32_3, second_col_nsga2_32_3, 'b^', label = 'nsga2')
>>> axes[2,0].legend(loc='upper right')
>>> axes[2,0].set_title('ZDT3: final Pareto front (3rd run, pop=32)')
>>> axes[2,1].plot(first_pop_64_3[:,0], first_pop_64_3[:,1], '.', label= 'initial population')
>>> axes[2,1].plot(first_col_moead_64_3, second_col_moead_64_3,'k*', label = 'moead')
>>> axes[2,1].plot(first_col_maco_64_3, second_col_maco_64_3,'ro', label = 'maco')
>>> axes[2,1].plot(first_col_nsga2_64_3, second_col_nsga2_64_3, 'b^', label = 'nsga2')
>>> axes[2,1].legend(loc='upper right')
>>> axes[2,1].set_title('ZDT3: final Pareto front (3rd run, pop=64)')
>>> axes[2,2].plot(first_pop_128_3[:,0], first_pop_128_3[:,1], '.', label= 'initial population')
>>> axes[2,2].plot(first_col_moead_128_3, second_col_moead_128_3,'k*', label = 'moead')
>>> axes[2,2].plot(first_col_maco_128_3, second_col_maco_128_3,'ro', label = 'maco')
>>> axes[2,2].plot(first_col_nsga2_128_3, second_col_nsga2_128_3, 'b^', label = 'nsga2')
>>> axes[2,2].legend(loc='upper right')
>>> axes[2,2].set_title('ZDT3: final Pareto front (3rd run, pop=128)')
>>> for ax in axes.flat:
... ax.set(xlabel='f_1', ylabel='f_2')
... ax.grid()
结果图可以在下图中看到: