關於我對GA遺傳算法的理解:
剛開始只聽說過遺傳算法的時候,聽到這個名字就感覺好牛掰的樣子。然後看了一本叫做《MATLAB智能算法30個案例分析》的書,學習了GA遺傳算法,然而學完了之後知道我的第一感覺是什麼?那就是真特麼扯淡,哈哈哈!這特麼不就是瞎碰,瞎貓碰上死耗子,碰上了最優解就碰上了,碰不上不就得到個不知道差多少的解嗎?不過存在即合理仔細想想能發明這個算法的人還是很值得尊敬的。好了來說說我的理解,首先遺傳算法當然是模擬生物進化優勝劣汰的法則了,它最大的優點就是不要你去尋找解,而只需要你作爲上帝去否決那些你認爲不好的解,最終留下來的就是最優解(或者次優解)了。
首先來解釋一下幾個名詞:
1. 染色體,一條染色體對應的就是你需要求的一個解,例如你需要求一個三元四次的複雜方程的極小值,那麼你的一個結當然包含三個數(因爲是三元嘛,當然是三個未知 數啦),假設是x,y,z。那麼你的一條染色體就包含三個數,類似於一個向量[x y z]。類似的如果你的一個解只有一個數,那麼一條染色體就只包含一個數。
2. 基因,咱們都是理科生,當然知道染色體是由基因組成的,上面說到了[x y z]對應的是一條染色體,那麼自然組成x , y , z的就是基因嘍,這裏我們就要說到編碼了,一般 我們會將染色體進行編碼,假設使用的是二進制編碼,那麼我們用二進制0和1將[x y z]橫着寫成一排,那麼是不是就是遺傳0和1。那麼這些0和1就是基因了。
3. 交叉,交叉也是跟生物裏面學的一樣,就是兩條染色體並排的時候相對應的那一段交叉接起來
4. 變異,變異就是基因中某個bit的0變成了1,或者1變成了0,機率很小。當然在算法中是我們讓它變異的。
5. 壓差,在下面的例子中,有個詞語叫“壓差”,之前網上都沒找到明白的解釋,其實說的那麼高端,壓差就是指你把本來0~255之間的數按照某種算法映射到1~10的話,那麼 壓差就是指這個1~10了,其實就是歸一化之後的範圍。
6. 適應度,上面說到優勝劣汰,我們作爲上帝需要指定一個規則,怎麼樣的算是優秀,什麼樣的算是劣質,說讓誰淘汰就讓誰淘汰,比如說我們求一個方程的極小值,那麼 我們當然是將每條染色體的值帶入到方程中,求得的值越小就越優秀,越大就越劣質嘍。那麼我們就要淘汰那些使得方程值大的染色體,通過交叉編譯來補充那些被淘汰 染色體的位置。
7. 適應度函數,適應度函數顧名思義就是用來計算適應度的函數,這個函數的定義很重要,但是總得來說只要保證越符合我們要求的,得出來的值(適應度)越大理論上就 可以接受,至於好不好另說。
8. 種羣,就是若干個染色體組成種羣。
接下來就說說GA遺傳算法的步驟:
下面這個用matlab寫的例子就是一個求極值問題,求方程y = sin(10*pi*x)/x , x屬於[1,2] , 的極值
clc;
clear all;close all;
figure(1);
hold on;
lb = 1; ub = 2; %這個值是自變量的範圍,在這個範圍內求解
ezplot('sin(10*pi*X)/X',[lb,ub]); %第一個參數表示的是方程,y的計算公式,畫出圖像
xlabel('自變量/X');
ylabel('函數值/Y');
NIND = 40; %初始化40個解,每一個解代表的是一條染色體,這條染色體就代表的是一個x的值
MAXGEN = 20; %最大遺傳代數
PRECT = 20; %染色體精度,也就是一個個體的基因數(2進制數長度),也就是用多少個bit表示一個x的值
GGAP = 0.95; %代溝,表示每一代從種羣中選擇多少個體到下一代
px = 0.7; %染色體交叉機率,具體自己寫的話不知道這個概率怎麼用的,不過matlab中作爲參數直接帶入就好了
pm = 0.01; %染色體變異機率,具體自己寫的話不知道這個概率怎麼用的,不過matlab中作爲參數直接帶入就好了
trace = zeros(2,MAXGEN);%初始化爲0
FieldD = [PRECT;lb;ub;1;0;1;1]; % PRECT:2進制位數 lb:範圍下限 ub:表示範圍上限
% 1:二進制編碼 0:表示用算術刻度 1:表示包含左邊界 1:表示包含右邊界
Chrom = crtbp(NIND,PRECT); %隨機產生初始解
gen = 0;%遺傳代數
X = bs2rv(Chrom , FieldD); %根據區域描述器,自動將2進制編碼轉化成指定範圍內的實數值
%得出的X是一個長度爲40的列向量
ObjV = sin(10*pi*X)./X ;%“./”表示爲陣列操作,非矩陣運算,得出的也是一個長度爲40的列向量,適應度值
%經過上一步,X已經爲列向量,所以ObjV也是列向量了
while gen<MAXGEN
%ranking : 根據適應度值,使用ranking()得出各自的入選率(適應度)
%第一個參數:注意ObjV必須是列向量(這是ranking函數要求的),表示需要計算適應度的種羣,
%第二個參數:一個有兩個標量的向量,第一個標量可以認爲總爲2,同時代表壓差的上限
% 第二個標量有兩重意義,如果爲0表示線性排序,如果爲1表示非線性排序,
% 同時它代表壓差的下限。返回得到的FitnV會是一個長度跟ObjV相同的列向量
% ,他們之間的值是一一對應的,FitnV中較大的表示適應度的值對應ObjV中較
% 較小的值。但是FitnV中的順序並非是有序的,順序跟ObjV中的每個值得順序
% 是一樣的。
%第三個參數:表示種羣中子種羣的數量
FitnV = ranking(ObjV,[2,0],1);
%select : 通過計算得到的適應度值,從原始種羣Chrom中篩選一些不符合要求的個體得到
% 新的種羣返回個SelCh
%第一個參數:表示選擇篩選的策略,sus表示隨機平均選擇 ,還可以是rws表示輪盤賭選擇
%第二個參數:表示原始的需要被篩選的種羣
%第三個參數:表示這個種羣對應的適應度
%第四個參數:表示代溝,也就是說從Chrom中選擇多少百分比的個體到下一代,這裏爲0.95
% 也就是說從Chrom中選擇Chrom*0.95個個體進入下一代,有0.05的染色體被淘汰
SelCh = select('sus',Chrom,FitnV,GGAP); %這就是優勝劣汰的過程
SelCh = recombin('xovsp',SelCh,px); %交叉基因函數 ,xovsp或者recdis表示交叉策略 , px表示染色體交叉機率
SelCh = mut(SelCh,pm); %變異函數 ,pm表示編譯機率
X = bs2rv(SelCh , FieldD);
ObjVSel = sin(10*pi*X)./X;
%reins : 將子代個體插入到父代種羣中,代替那些不合適的父代個體
%第一個參數:表示父代種羣
%第二個參數:子代種羣
%第三個參數:指明Chrom,SelCh中子種羣個數,每個子種羣必須有相同的大小
%第四個參數:其實是一個有兩個元素的向量,在這裏相當於[1,1] ,第一個標量表示用什麼策略將子代
% 將子代插入父代種羣,如果爲0表示用隨機均勻選擇,如果爲1表示根據適應度進行選擇;
% 第二個標量表示子代種羣插入父代,佔百分比,可以是[0,1]之間的標量,如果缺省表示
% 默認值爲1
%第五個參數:基於適應度重插入(也就是第四個參數爲1)的時候這個參數是必須的,Objv包含Chrom中
% 個體的目標值(也就是根據公式計算得到的值比如上面的sin(10*pi*X)./X得到的值)。
% 這是因爲基於適應度的方法,得到適應度必須是根據目標值來確定適應度,所以這裏必須
% 要帶入目標值。
%第六個參數:如果子代的個體數量大於將要插入父代的個體數量,那麼這個參數是必須的,因爲待插入
% 的個數多餘需要插入的個數,那麼必然存在有一部分不能插入,那麼淘汰那一部分個體,是
% 根據子代種羣的個體適應度來決定的,淘汰掉適應度底的個體,那麼得到個體的適應度就需
% 要子種羣的各個個體的目標值來計算。
[Chrom,ObjV] = reins(Chrom , SelCh , 1 , 1 , ObjV , ObjVSel)
X = bs2rv(Chrom , FieldD);
gen = gen + 1;
%min : 返回向量ObjV的最小值,Y記錄ObjV中每一列的最小值,I記錄每一列的最小值的行號
[Y,I] = min(ObjV)
trace(1,gen) = X(I);
trace(2,gen) = Y;
end
plot(trace(1,:),trace(2,:),'bo');
grid on;
plot(X,ObjV,'b*');
hold off;
figure(2);
plot(1:MAXGEN,trace(2,:));
grid on;
xlabel('遺傳代數');
ylabel('解的變化');
title('進化過程');
bestY = trace(2,end);
bestX = trace(1,end);
fprintf(['最優解:\nX = ', num2str(bestX), '\nY = ' , num2str(bestY) , '\n']);