生活随笔
收集整理的這篇文章主要介紹了
多目标优化系列1---NSGA2的非支配排序函数的讲解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
作為一名非數學、非計算機專業的野生研究僧程序員,在學習和實踐多目標優化時,遇到了各種困難,加之相關方向的交流資源有限,也使得整個過程顯得緩慢。在此,非常感謝西電曉風(https://blog.csdn.net/qq_40434430/article/details/82876572)及其他各路貢獻知識的大神給予的啟發、交流,他的嚴謹、謙虛、熱情讓我能不拋棄不放棄,入了門。
為何要專門講解NSGA2非支配排序函數
多目標優化中的經典是NSGA2,NSGA2的經典是non-dominated sort。非支配排序做好了,才能談后面的一切(這句話的領悟,非生而知之,而是在各種試錯、奔潰的過程中領略到的)。掌握了NSGA2才能談后面的其他各類算法,如:NSGA3,ε-NSGA2,MOEA,MOEA/D(這里的提法也并非完全正確,他們直接部分并沒有強耦合關系,僅為個人一己之見)。
非支配排序函數的基本原理
首先看一下數學定義:
需要說明幾點潛在內涵:
- 都是求最小化問題(一個約定俗成的規則);
- 所有的 fi(Xa)f_i(X_a)fi?(Xa?) 小于或者等于fi(Xb)f_i(X_b)fi?(Xb?) ,且至少存在一個 fi(Xa)f_i(X_a)fi?(Xa?) 完全小于fi(Xb)f_i(X_b)fi?(Xb?)
- fi(Xa)f_i(X_a)fi?(Xa?) 完全等于fi(Xb)f_i(X_b)fi?(Xb?)時,XaX_aXa?和XbX_bXb?不存在支配關系(劃重點:這個在實際的進化過程中,會出現很多,目前網上很多的代碼忽略了這一點,會導致在已有Deb大神原始NSGA2測試問題上運行沒問題,但是轉換到現實問題中會出現很多的問題,如:不收斂、不穩定等。為什么會出現這樣的問題呢?因為Deb大神采用的是標準遺傳算子中的一種,即:實數編碼和多項式交叉,且論文中定義的PC很大,世代之間出現完全復制的可能性小。然而,現實中應用改造問題,很多時候需要改造掉遺傳算子,即:非標遺傳算子,從而就會展現出各種奇葩問題。之所以在這里強調這問題,是因為我自己在這里耗費了很多的精力,各種調試,找不出原因,最終發現是因為一個等于號坑了我。也特別感謝課題組Jing Huang給予的耐心調試和討論。)
如何測試非支配排序函數
我們需要構建專門針對非支配排序函數的測試類,從而驗證函數的正確性,構建測試類的關鍵是在于輸入的測試評價值Array的有效性。我通過大量的實驗,提煉出基礎的、正確的、報錯的三個測試評價值Array。
- 基礎的測試評價值Array,大家可以用來自行推演,該值參考至鄭金華老師的書(主觀評價:鄭老師的書是目前國內對此塊做了系統介紹的書,他的治學風格嚴謹、務實,而非論文的直接堆砌,建議入門學生可以從這本書開始,論文堆砌的書可以到高階階段再學習)
- 正確的測試評價值Array,跑ZDT3的時候從內存中Debug Copy的。
- 報錯的測試評價值Array,跑ZDT6的時候從內存中Debug Copy的。以下給出的代碼中test_fast_non_dominated_sort_error函數會顯示出他錯在哪。
import random
import numpy
as np
from matplotlib
.ticker
import MultipleLocator
import matplotlib
.pyplot
as plt
class Test_class():def __init__(self
,f_num
):self
.f_num
=f_numY1
= [9, 7, 5, 4, 3, 2, 1, 10, 8, 7, 5, 4, 3, 10, 9, 8, 7, 10, 9, 8]Y2
= [1, 2, 4, 5, 6, 7, 9, 1, 5, 6, 7, 8, 9, 5, 6, 7, 9, 6, 7, 9]self
.objectives_fitness_zjh
=np
.array
([Y1
,Y2
]).Tself
.objectives_fitness_8
= np
.array
([[0.6373723585181119, 9.089424920752537],[0.6307563745957109, 9.484134522661321],[0.6307726564027054, 9.370453232401315],[0.9214017573731662, 8.974173267351892],[0.8106208092655269, 9.00814519794432],[0.6308299859236132, 9.381311843663337],[0.9996933421004693, 8.998732212375378],[0.8106208092655269, 9.087298161567794],[0.9968206553777186, 9.020037858133483],[0.9503113437004427, 9.04519027298749],[0.9214017573731662, 8.974173267351892],[0.9214017573731662, 9.00187266065025],[0.6307563745957109, 9.493829448943414],[0.999999999999489, 9.180616877016963],[0.8150090640161689, 9.041622216379706],[0.9990805452551389, 8.980910429010232],[0.9979468094812165, 9.04561922020985],[0.7527617476769539, 9.136335451211739],[0.6364241984468356, 9.20992553291975],[0.8106208092655269, 9.083868693443087]])self
.objectives_fitness_20
= np
.array
([[0.01783689,1.02469787],[0.04471213,0.93037726],[0.0236877,0.96322404],[0.04938809,0.92641409],[0.07031985,0.83355839],[0.05199109,0.88398541],[0.05006115,0.91107188],[0.,1.18579768],[0.05358649,0.85849188],[0.01657041,1.0721905,],[0.10409921,0.84829613],[0.06643826,0.84941993],[0.05358649,0.89876683],[0.01740193,1.09732744],[0.04938809,0.94687415],[0.05199109,0.93536007],[0.02400905,1.11603965],[0.05358649,0.89107165],[0.,1.23996387],[0.01783689,1.11625582]])def test_fast_non_dominated_sort_1(self
, objectives_fitness
):fronts
= [] fronts
.append
([])set_sp
= []npp
= np
.zeros
(2*10)rank
= np
.zeros
(2*10)for i
in range(2 * 10):temp
= []for j
in range(2 * 10):if j
!= i
:if (objectives_fitness
[j
][0] >= objectives_fitness
[i
][0] and objectives_fitness
[j
][1] > objectives_fitness
[i
][1]) or \
(objectives_fitness
[j
][0] > objectives_fitness
[i
][0] and objectives_fitness
[j
][1] >= objectives_fitness
[i
][1]) or \
(objectives_fitness
[j
][0] >= objectives_fitness
[i
][0] and objectives_fitness
[j
][1] >= objectives_fitness
[i
][1]):temp
.append
(j
)elif (objectives_fitness
[i
][0] >= objectives_fitness
[j
][0] and objectives_fitness
[i
][1] > objectives_fitness
[j
][1]) or \
(objectives_fitness
[i
][0] > objectives_fitness
[j
][0] and objectives_fitness
[i
][1] >= objectives_fitness
[j
][1]) or \
(objectives_fitness
[j
][0] > objectives_fitness
[i
][0] and objectives_fitness
[j
][1] > objectives_fitness
[i
][1]):npp
[i
] += 1 set_sp
.append
(temp
) if npp
[i
] == 0:fronts
[0].append
(i
) rank
[i
] = 1 i
= 0while len(fronts
[i
]) > 0:temp
= []for j
in range(len(fronts
[i
])):a
= 0while a
< len(set_sp
[fronts
[i
][j
]]):npp
[set_sp
[fronts
[i
][j
]][a
]] -= 1if npp
[set_sp
[fronts
[i
][j
]][a
]] == 0:rank
[set_sp
[fronts
[i
][j
]][a
]] = i
+ 2 temp
.append
(set_sp
[fronts
[i
][j
]][a
])a
= a
+ 1i
= i
+ 1fronts
.append
(temp
)del fronts
[len(fronts
) - 1]self
.output_fronts
(fronts
)def output_fronts(self
, fronts
):sum_coun
= 0for kk
in range(len(fronts
)):sum_coun
+= len(fronts
[kk
])print(sum_coun
)print(fronts
)def test_fast_non_dominated_sort_error(self
, objectives_fitness
):fronts
= [] fronts
.append
([])set_sp
= []npp
= np
.zeros
(2*10)rank
= np
.zeros
(2*10)for i
in range(2 * 10):temp
= []for j
in range(2 * 10):if j
!= i
:if (objectives_fitness
[j
][0] >= objectives_fitness
[i
][0] and objectives_fitness
[j
][1] >= objectives_fitness
[i
][1]) :temp
.append
(j
)elif (objectives_fitness
[i
][0] > objectives_fitness
[j
][0] and objectives_fitness
[i
][1] > objectives_fitness
[j
][1]):npp
[i
] += 1 set_sp
.append
(temp
) if npp
[i
] == 0:fronts
[0].append
(i
) rank
[i
] = 1 i
= 0while len(fronts
[i
]) > 0:temp
= []for j
in range(len(fronts
[i
])):a
= 0while a
< len(set_sp
[fronts
[i
][j
]]):npp
[set_sp
[fronts
[i
][j
]][a
]] -= 1if npp
[set_sp
[fronts
[i
][j
]][a
]] == 0:rank
[set_sp
[fronts
[i
][j
]][a
]] = i
+ 2 temp
.append
(set_sp
[fronts
[i
][j
]][a
])a
= a
+ 1i
= i
+ 1fronts
.append
(temp
)del fronts
[len(fronts
) - 1]self
.output_fronts
(fronts
)def output_fronts(self
, fronts
):sum_coun
= 0for kk
in range(len(fronts
)):sum_coun
+= len(fronts
[kk
])print(sum_coun
)print(fronts
)def test_fast_non_dominated_sort_2(self
, objectives_fitness
):set_sp
=[[] for i
in range(0, np
.shape
(objectives_fitness
)[0])]fronts
= [[]]npp
=[0 for i
in range(0, np
.shape
(objectives_fitness
)[0])]rank
= [0 for i
in range(0, np
.shape
(objectives_fitness
)[0])]for i
in range(0, np
.shape
(objectives_fitness
)[0]):set_sp
[i
]=[]for j
in range(0, np
.shape
(objectives_fitness
)[0]):if i
!= j
:if (objectives_fitness
[j
][0] >= objectives_fitness
[i
][0] and objectives_fitness
[j
][1] > objectives_fitness
[i
][1]) or \
(objectives_fitness
[j
][0] > objectives_fitness
[i
][0] and objectives_fitness
[j
][1] >= objectives_fitness
[i
][1]) or \
(objectives_fitness
[j
][0] >= objectives_fitness
[i
][0] and objectives_fitness
[j
][1] >= objectives_fitness
[i
][1]):set_sp
[i
].append
(j
)elif (objectives_fitness
[i
][0] >= objectives_fitness
[j
][0] and objectives_fitness
[i
][1] > objectives_fitness
[j
][1]) or \
(objectives_fitness
[i
][0] > objectives_fitness
[j
][0] and objectives_fitness
[i
][1] >= objectives_fitness
[j
][1]) or \
(objectives_fitness
[j
][0] > objectives_fitness
[i
][0] and objectives_fitness
[j
][1] > objectives_fitness
[i
][1]):npp
[i
] += 1 if npp
[i
]==0:rank
[i
] = 0if i
not in fronts
[0]:fronts
[0].append
(i
)i
= 0while(fronts
[i
] != []):Q
=[]for p
in fronts
[i
]:for q
in set_sp
[p
]:npp
[q
] =npp
[q
] - 1if( npp
[q
]==0):rank
[q
]=i
+1if q
not in Q
:Q
.append
(q
)i
= i
+1fronts
.append
(Q
)del fronts
[len(fronts
)-1]self
.output_fronts
(fronts
)def test_fast_non_dominated_sort_3(self
, objectives_fitness
):fronts
= [] fronts
.append
([])set_sp
= []npp
= np
.zeros
(2 * 10)rank
= np
.zeros
(2 * 10)for i
in range(2 * 10):temp
= []for j
in range(2 * 10):if j
!= i
:less
= 0 equal
= 0 greater
= 0 for k
in range(self
.f_num
):if (objectives_fitness
[i
][k
] < objectives_fitness
[j
][k
]):less
= less
+ 1elif (objectives_fitness
[i
][k
] == objectives_fitness
[j
][k
]):equal
= equal
+ 1else:greater
= greater
+ 1if (less
== 0 and equal
!= self
.f_num
):npp
[i
] += 1 elif (greater
== 0 and equal
!= self
.f_num
):temp
.append
(j
)set_sp
.append
(temp
) if npp
[i
] == 0:fronts
[0].append
(i
) rank
[i
] = 1 i
= 0while len(fronts
[i
]) > 0:temp
= []for j
in range(len(fronts
[i
])):a
= 0while a
< len(set_sp
[fronts
[i
][j
]]):npp
[set_sp
[fronts
[i
][j
]][a
]] -= 1if npp
[set_sp
[fronts
[i
][j
]][a
]] == 0:rank
[set_sp
[fronts
[i
][j
]][a
]] = i
+ 2 temp
.append
(set_sp
[fronts
[i
][j
]][a
])a
= a
+ 1i
= i
+ 1fronts
.append
(temp
)del fronts
[len(fronts
) - 1]self
.output_fronts
(fronts
)if __name__
== '__main__':test_class
=Test_class
(f_num
=2)print("測試1:普通")test_class
.test_fast_non_dominated_sort_1
(test_class
.objectives_fitness_zjh
)test_class
.test_fast_non_dominated_sort_2
(test_class
.objectives_fitness_zjh
)test_class
.test_fast_non_dominated_sort_3
(test_class
.objectives_fitness_zjh
)test_class
.test_fast_non_dominated_sort_error
(test_class
.objectives_fitness_zjh
)print("測試2:正確,重點看錯誤的函數test_fast_non_dominated_sort_error")test_class
.test_fast_non_dominated_sort_1
(test_class
.objectives_fitness_20
)test_class
.test_fast_non_dominated_sort_2
(test_class
.objectives_fitness_20
)test_class
.test_fast_non_dominated_sort_3
(test_class
.objectives_fitness_20
)test_class
.test_fast_non_dominated_sort_error
(test_class
.objectives_fitness_20
)print("測試3:ZDT6 錯誤,重點看錯誤的函數test_fast_non_dominated_sort_error")test_class
.test_fast_non_dominated_sort_1
(test_class
.objectives_fitness_8
)test_class
.test_fast_non_dominated_sort_2
(test_class
.objectives_fitness_8
)test_class
.test_fast_non_dominated_sort_3
(test_class
.objectives_fitness_8
)test_class
.test_fast_non_dominated_sort_error
(test_class
.objectives_fitness_8
)
總結
這里寫的測試函數,客觀來說還是不夠好的,因為是采用窮舉的方式來驗證小于、等于、大于的關系,兩個目標函數的時候,這樣寫還是可以湊合的,但是如果是5個目標,這個顯然就不可以了。所以增加了test_fast_non_dominated_sort_3()函數,正確的做法應該是參考mooplatm中,排除的寫法,可以適用于多個目標,而不僅僅局限于兩個目標。
總結
以上是生活随笔為你收集整理的多目标优化系列1---NSGA2的非支配排序函数的讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。