大白话讲解遗传算法
博客原文:cnblogs.com/heaad/archive/2010/12/23/1914725.html
遺傳算法 ( GA , Genetic Algorithm ) ,也稱進化算法 。 遺傳算法是受達爾文的進化論的啟發,借鑒生物進化過程而提出的一種啟發式搜索算法。因此在介紹遺傳算法前有必要簡單的介紹生物進化知識。
一.進化論知識?
作為遺傳算法生物背景的介紹,下面內容了解即可:
種群(Population):生物的進化以群體的形式進行,這樣的一個群體稱為種群。
個體:組成種群的單個生物。
基因?( Gene )?:一個遺傳因子。?
染色體?( Chromosome )?:包含一組的基因。
生存競爭,適者生存:對環境適應度高的、牛B的個體參與繁殖的機會比較多,后代就會越來越多。適應度低的個體參與繁殖的機會比較少,后代就會越來越少。
遺傳與變異:新個體會遺傳父母雙方各一部分的基因,同時有一定的概率發生基因變異。
?
簡單說來就是:繁殖過程,會發生基因交叉( Crossover ) ,基因突變 ( Mutation ) ,適應度( Fitness )低的個體會被逐步淘汰,而適應度高的個體會越來越多。那么經過N代的自然選擇后,保存下來的個體都是適應度很高的,其中很可能包含史上產生的適應度最高的那個個體。
二.遺傳算法思想?
借鑒生物進化論,遺傳算法將要解決的問題模擬成一個生物進化的過程,通過復制、交叉、突變等操作產生下一代的解,并逐步淘汰掉適應度函數值低的解,增加適應度函數值高的解。這樣進化N代后就很有可能會進化出適應度函數值很高的個體。
舉個例子,使用遺傳算法解決“0-1背包問題”的思路:0-1背包的解可以編碼為一串0-1字符串(0:不取,1:取) ;首先,隨機產生M個0-1字符串,然后評價這些0-1字符串作為0-1背包問題的解的優劣;然后,隨機選擇一些字符串通過交叉、突變等操作產生下一代的M個字符串,而且較優的解被選中的概率要比較高。這樣經過G代的進化后就可能會產生出0-1背包問題的一個“近似最優解”。
?
編碼:需要將問題的解編碼成字符串的形式才能使用遺傳算法。最簡單的一種編碼方式是二進制編碼,即將問題的解編碼成二進制位數組的形式。例如,問題的解是整數,那么可以將其編碼成二進制位數組的形式。將0-1字符串作為0-1背包問題的解就屬于二進制編碼。
?
遺傳算法有3個最基本的操作:選擇,交叉,變異。
?
選擇:選擇一些染色體來產生下一代。一種常用的選擇策略是?“比例選擇”,也就是個體被選中的概率與其適應度函數值成正比。假設群體的個體總數是M,那么那么一個體Xi被選中的概率為f(Xi)/( f(X1) + f(X2) + …….. + f(Xn) ) 。比例選擇實現算法就是所謂的“輪盤賭算法”( Roulette Wheel Selection ) ,輪盤賭算法的一個簡單的實現如下:
?
輪盤賭算法 /** 按設定的概率,隨機選中一個個體
* P[i]表示第i個個體被選中的概率
*/
int?RWS()
{
m?=0;
r?=Random(0,1);?//r為0至1的隨機數
for(i=1;i<=N; i++)
{
/*?產生的隨機數在m~m+P[i]間則認為選中了i
* 因此i被選中的概率是P[i]
*/
m?=?m?+?P[i];
if(r<=m)?return?i;
}
}
?
交叉(Crossover):2條染色體交換部分基因,來構造下一代的2條新的染色體。例如:
交叉前:
00000|011100000000|10000
11100|000001111110|00101
交叉后:
00000|000001111110|10000
11100|011100000000|00101
染色體交叉是以一定的概率發生的,這個概率記為Pc 。
?
變異(Mutation):在繁殖過程,新產生的染色體中的基因會以一定的概率出錯,稱為變異。變異發生的概率記為Pm 。例如:
變異前:
000001110000000010000
變異后:
000001110000100010000
?
適應度函數?( Fitness Function ):用于評價某個染色體的適應度,用f(x)表示。有時需要區分染色體的適應度函數與問題的目標函數。例如:0-1背包問題的目標函數是所取得物品價值,但將物品價值作為染色體的適應度函數可能并不一定適合。適應度函數與目標函數是正相關的,可對目標函數作一些變形來得到適應度函數。
?
?
三.基本遺傳算法的偽代碼?
??
基本遺傳算法偽代碼 /** Pc:交叉發生的概率
* Pm:變異發生的概率
* M:種群規模
* G:終止進化的代數
* Tf:進化產生的任何一個個體的適應度函數超過Tf,則可以終止進化過程
*/
初始化Pm,Pc,M,G,Tf等參數。隨機產生第一代種群Pop
do
{?
計算種群Pop中每一個體的適應度F(i)。
初始化空種群newPop
do
{
根據適應度以比例選擇算法從種群Pop中選出2個個體
if?( random (?0?,?1?)?<?Pc )
{
對2個個體按交叉概率Pc執行交叉操作
}
if?( random (?0?,?1?)?<?Pm )
{
對2個個體按變異概率Pm執行變異操作
}
將2個新個體加入種群newPop中
} until ( M個子代被創建 )
用newPop取代Pop
}until ( 任何染色體得分超過Tf, 或繁殖代數超過G ) ?
?
?
四.基本遺傳算法優化?
? 下面的方法可優化遺傳算法的性能。
? 精英主義(Elitist Strategy)選擇:是基本遺傳算法的一種優化。為了防止進化過程中產生的最優解被交叉和變異所破壞,可以將每一代中的最優解原封不動的復制到下一代中。
? 插入操作:可在3個基本操作的基礎上增加一個插入操作。插入操作將染色體中的某個隨機的片段移位到另一個隨機的位置。
五. 使用AForge.Genetic解決TSP問題
AForge.NET是一個C#實現的面向人工智能、計算機視覺等領域的開源架構。AForge.NET中包含有一個遺傳算法的類庫。
?
AForge.NET主頁:http://www.aforgenet.com/
AForge.NET代碼下載:http://code.google.com/p/aforge/
?
介紹一下AForge的遺傳算法用法吧。AForge.Genetic的類結構如下:
圖1. AForge.Genetic的類圖
?
?
?? 下面用AForge.Genetic寫個解決TSP問題的最簡單實例。測試數據集采用網上流傳的中國31個省會城市的坐標:
?
1304231236391315
41772244
37121399
34881535
33261556
32381229
41961004
4312790
4386570
30071970
25621756
27881491
23811676
1332695
37151678
39182179
40612370
37802212
36762578
40292838
42632931
34291908
35072367
33942643
34393201
29353240
31403550
25452357
27782826
23702975
?
?
?
操作過程:
?? (1) 下載AForge.NET類庫,網址:http://code.google.com/p/aforge/downloads/list
?? (2) 創建C#空項目GenticTSP。然后在AForge目錄下找到AForge.dll和AForge.Genetic.dll,將其拷貝到TestTSP項目的bin/Debug目錄下。再通過“Add Reference...”將這兩個DLL添加到工程。
?? (3) 將31個城市坐標數據保存為bin/Debug/Data.txt 。
?? (4) 添加TSPFitnessFunction.cs,加入如下代碼:
?
TSPFitnessFunction類 using?System;using?AForge.Genetic;
namespace?GenticTSP
{
///<summary>
///?Fitness function for TSP task (Travaling Salasman Problem)
///</summary>
publicclass?TSPFitnessFunction : IFitnessFunction
{
//?map
privateint[,] map?=null;
//?Constructor
public?TSPFitnessFunction(int[,] map)
{
this.map?=?map;
}
///<summary>
///?Evaluate chromosome - calculates its fitness value
///</summary>
publicdouble?Evaluate(IChromosome chromosome)
{
return1/?(PathLength(chromosome)?+1);
}
///<summary>
///?Translate genotype to phenotype?
///</summary>
publicobject?Translate(IChromosome chromosome)
{
return?chromosome.ToString();
}
///<summary>
///?Calculate path length represented by the specified chromosome?
///</summary>
publicdouble?PathLength(IChromosome chromosome)
{
//?salesman path
ushort[] path?=?((PermutationChromosome)chromosome).Value;
//?check path size
if?(path.Length?!=?map.GetLength(0))
{
thrownew?ArgumentException("Invalid path specified - not all cities are visited");
}
//?path length
int?prev?=?path[0];
int?curr?=?path[path.Length?-1];
//?calculate distance between the last and the first city
double?dx?=?map[curr,?0]?-?map[prev,?0];
double?dy?=?map[curr,?1]?-?map[prev,?1];
double?pathLength?=?Math.Sqrt(dx?*?dx?+?dy?*?dy);
//?calculate the path length from the first city to the last
for?(int?i?=1, n?=?path.Length; i?<?n; i++)
{
//?get current city
curr?=?path[i];
//?calculate distance
dx?=?map[curr,?0]?-?map[prev,?0];
dy?=?map[curr,?1]?-?map[prev,?1];
pathLength?+=?Math.Sqrt(dx?*?dx?+?dy?*?dy);
//?put current city as previous
prev?=?curr;
}
return?pathLength;
}
}
}
?
?
?? (5) 添加GenticTSP.cs,加入如下代碼:
?
GenticTSP類 using?System;using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.IO;
using?AForge;
using?AForge.Genetic;
namespace?GenticTSP
{
class?GenticTSP
{
staticvoid?Main()
{
StreamReader reader?=new?StreamReader("Data.txt");
int?citiesCount?=31;?//城市數
int[,] map?=newint[citiesCount,?2];
for?(int?i?=0; i?<?citiesCount; i++)
{
string?value?=?reader.ReadLine();
string[] temp?=?value.Split('');
map[i,?0]?=int.Parse(temp[0]);?//讀取城市坐標
map[i,?1]?=int.Parse(temp[1]);
}
//?create fitness function
TSPFitnessFunction fitnessFunction?=new?TSPFitnessFunction(map);
int?populationSize?=?1000;?//種群最大規模
/*?
* 0:EliteSelection算法?
* 1:RankSelection算法?
* 其他:RouletteWheelSelection 算法
*?*/
int?selectionMethod?=0;
//?create population
Population population?=new?Population(populationSize,
new?PermutationChromosome(citiesCount),
fitnessFunction,
(selectionMethod?==0)???(ISelectionMethod)new?EliteSelection() :
(selectionMethod?==1)???(ISelectionMethod)new?RankSelection() :
(ISelectionMethod)new?RouletteWheelSelection()
);
//?iterations
int?iter?=1;
int?iterations?=5000;?//迭代最大周期
//?loop
while?(iter?<?iterations)
{
//?run one epoch of genetic algorithm
population.RunEpoch();
//?increase current iteration
iter++;
}
System.Console.WriteLine("遍歷路徑是: {0}", ((PermutationChromosome)population.BestChromosome).ToString());
System.Console.WriteLine("總路程是:{0}", fitnessFunction.PathLength(population.BestChromosome));
System.Console.Read();
}
}
}
?
?
?
網上據稱這組TSP數據的最好的結果是?15404 ,上面的程序我剛才試了幾次最好一次算出了15402.341,但是最差的時候也跑出了大于16000的結果。
我這還有一個版本,設置種群規模為1000,迭代5000次可以算出15408.508這個結果。源代碼在文章最后可以下載。
?
總結一下使用AForge.Genetic解決問題的一般步驟:
?? (1) 定義適應函數類,需要實現IFitnessFunction接口
?? (2) 選定種群規模、使用的選擇算法、染色體種類等參數,創建種群population
?? (3)設定迭代的最大次數,使用RunEpoch開始計算
?
本文源代碼下載
總結
- 上一篇: 把烂土豆砸到古永锵的脸上
- 下一篇: 女性游戏市场崛起,B站能否能否抓住风口打