概要:
まず、遺伝的アルゴリズムの概要
2.1グループ
2.2遺伝子型と表現型
2.3突然変異
2.4選択
2.5遺伝
第二に、インテリジェントな鳥の実現
2.1鳥の遺伝子型と表現型
遺伝子が鳥の飛行経路にどのような影響を与えるか2.2バーディー
2.3鳥の適応性
2.4選択:高いフィットネス鳥を選択
2.5変異:遺伝子の豊かさを増します
2.6生殖:新しいDNAを生成
2.7育種集団
三
概要と最適化
スマート鳥
インテリジェントな鳥を達成するために、遺伝的アルゴリズムを使用することにより。最初から画面の図鳥のシナリオでは、画面の左に障害物上の最終目的地点。目標点(図2下)に直接鳥(図1で)意志初期状態では画面では、一定の進化と、最終的に鳥を飛んで、効果を見るにはこちらをクリックしてください。以下は、最初の遺伝的アルゴリズムを導入しました。
まず、遺伝的アルゴリズムの概要
遺伝的アルゴリズムは、集団で、個人の高い適応性が彼らの遺伝子の遺伝子(特性)に行く可能性が高いだろうであるダーウィンの自然淘汰のアイデアを借りました。ここでは、自然選択の重要な概念のいくつかは以下のとおりです。
グループは、個人、グループの多様性を確保するために、遺伝子プールのための自然な選択の富を提供するために、より簡単に、より適応個人を作り出します。
規格外のパフォーマンスで我々が見個々の外観と動作は、内部の遺伝子によって決定されます。つまり、内部データの個体の遺伝子型の性能を決定され、表現型は、個人の外観と動作があります。そのような個々の高さを表すことができる個々の色を表すことができる数値125として。符号125は、個々の表現型の等個体の遺伝子型、色、高さ、です。遺伝的アルゴリズムの設計では、個体の遺伝子型と表現型に注力するように設計。
遺伝的変異と選択は、3つの基本的なルールではダーウィンの進化論です。両親から特性を継承することができ、遺伝的子孫を確認してください。変異個人の多様性を確保するために、変異していない子孫と親が常に同じままならば、新しい機能が発生することはありません、人口は進化しません。人口はいくつかの個体を繁殖することができますし、いくつかの個人がないチャンスや再生の少しチャンスがないように、より適応の方向性を確保するために進化したグループを選択します。それは、しばしばそれは「適者生存。」と言われています 遺伝的アルゴリズムでは、個体の適応性の各世代における個々の遺伝子の計算は、高い遺伝的適応性の次の世代が続く中、個々の遺伝子の低い適合性は排除されるであろう。
第二に、インテリジェントな鳥の実現
下面借助白鹭引擎实现智能鸟群
1. 小鸟的基因型和表现型
为了使小鸟不断飞行,在小鸟的生命周期的每一时刻都会为小鸟赋予一个推力,通过推力改变小鸟的加速度,进而影响到小鸟的速度和位置。在小鸟的整个生命周期中(假设为200帧),可以把每一帧上的推力所组成的数组作为小鸟的基因型。小鸟在一系列的推力作用下所形成的飞行路线,为小鸟的表现型。可以用DNA类来定义小鸟的基因,其中推力用一个二维向量来定义。
1 class DNA { 2 private _genes=[]; 3 private _fitness:number; 4 private _maxforce=0.5;//最大推力为0.5 5 private _lifetime=200;//小鸟的生命周期为200帧 6 7 public constructor() { 8 for(let i=0;i<this._lifetime;i++){ 9 let force=Vector2D.random2D(); 10 force.mult(Math.random()*this._maxforce);//初始状态,每一时刻的推力是随机的。 11 this._genes.push(force); 12 } 13 } 14 15 public get genes(){ 16 return this._genes; 17 } 18 }
2. 小鸟的基因如何影响小鸟的飞行路线
在小鸟的类中,我们定义了一个applyForce方法,会根据生命周期的不同时刻将DNA上对应的推力应用在小鸟身上,从而使小鸟的位置发生改变。下面例子中我们使用egret画了一个三角形代表小鸟。代码如下:
1 class Bird extends egret.Sprite { 2 3 public location:Vector2D; 4 public velocity:Vector2D; 5 public acceleration:Vector2D; 6 public mass:number; 7 private shape:egret.Shape; 8 9 public target:Vector2D; 10 public dna:DNA; 11 private geneCounter=0; 12 13 public constructor(mass:number,x:number,y:number,target:Vector2D=new Vector2D(0,0)) { 14 super(); 15 this.dna=new DNA(); 16 this.mass=mass; 17 this.location=new Vector2D(x,y); 18 this.velocity=new Vector2D(0,0); 19 this.acceleration=new Vector2D(0,0); 20 this.target=target; 21 22 this.shape=new egret.Shape(); 23 let g=this.shape.graphics; 24 g.clear(); 25 g.beginFill(0xff0000); 26 g.moveTo(0,0); 27 g.lineTo(-10,-5); 28 g.lineTo(-10,5); 29 g.lineTo(0,0); 30 this.addChild(this.shape); 31 this.shape.x=this.location.x; 32 this.shape.y=this.location.y; 33 } 34 35 public run(){ 36 this.geneCounter++; 37 this.applyForce(this.dna.genes[this.geneCounter]);//将基因对应时刻的力作用在小鸟上 38 this.update(); 39 this.display(); 40 } 41 42 public applyForce(force:Vector2D){ 43 let f:Vector2D=Vector2D.div(force,this.mass); 44 this.acceleration.add(f); 45 } 46 47 public update(){ 48 this.velocity.add(this.acceleration); 49 this.location.add(this.velocity); 50 this.acceleration.mult(0); 51 } 52 53 public display(){ 54 this.shape.x=this.location.x; 55 this.shape.y=this.location.y; 56 let angle=this.velocity.heading2D()*180/Math.PI; 57 this.shape.rotation=angle; 58 } 59 }
3. 小鸟的适应性
在小鸟的生命周期结束时,我们通过判断小鸟离目标点的距离来判断小鸟的适应性,离目标点越近的小鸟适应性越高,否则适应性越低。可以通过小鸟离目标点的距离的倒数的平方作为小鸟的适应度。计算小鸟的适应度函数如下(在Bird类中定义):
1 /*适应度计算*/ 2 public fitness(){ 3 let d=Vector2D.dist(this.location,this.target);//this.target为小鸟的目标点 4 this._fitness=Math.pow(1/d,2); 5 } 6 7 public getFitness(){ 8 return this._fitness; 9 }
4. 选择:选择适应度更高的小鸟
我们定义一个Population类来管理所有的小鸟以及负责小鸟的选择和遗传。在Population类中定义了一个population数组来存储所有的小鸟,另外定义了一个matingPool数组作为交配池,我们根据小鸟适应性的强弱来将其放入交配池中,适应性越强的小鸟放入交配池中的数量越多,否则就越少。最后我们从交配池中随机的选择小鸟进行交配遗传,这样就保证了适应性强的小鸟选到的概率就越大。Population类中的选择函数如下:
1 public selection(){ 2 this.matingPool=[]; 3 let totalFitness=0; 4 for(let i=0;i<this.totalPopulation;i++){ 5 totalFitness+=this.population[i].getFitness(); 6 } 7 8 for(let i=0;i<this.totalPopulation;i++){ 9 let n=this.population[i].getFitness()/totalFitness*200;//适应性越大的小鸟,存入交配池中的数量就越多 10 if(n<1){ 11 continue; 12 } 13 for(let j=0;j<n;j++){ 14 this.matingPool.push(this.population[i]); 15 } 16 } 17 }
上面的方法,先计算所有小鸟的适应度之和,最后计算每个小鸟的适应度在所有小鸟的适应度中所占比例,然后将这个比例换算为相应的个数存入交配池。可以把这种选择方法想象成一个轮盘,某个个体的适应度所占的比例约大,它被选中的概率就越高。
5. 突变:增加基因的丰富性
为了增加基因的丰富性,从而产生适应性更强的个体,我们需要在每一代使小鸟的基因产生1%的突变率,我们在小鸟的DNA类中加入突变函数:
1 public mutate(mutationRate:number){ 2 for(let i=0;i<this._genes.length;i++){ 3 if(Math.random()<mutationRate){ 4 let force=Vector2D.random2D(); 5 force.mult(Math.random()*this._maxforce); 6 this._genes[i]=force; 7 } 8 } 9 }
并且为Bird类添加mutate接口
1 public mutate(mutationRate:number){ 2 this.dna.mutate(mutationRate); 3 }
6. 繁殖:产生新的DNA
在DNA类中,添加crossover方法,它接受另一个DNA实例,通过交叉组合生成新的DNA:
1 public crossover(partner:DNA):DNA{ 2 let child=new DNA(); 3 for(let i=0;i<this._genes.length;i++){ 4 let random=Math.random(); 5 if(random>0.5){ 6 child._genes[i]=this._genes[i]; 7 }else{ 8 child._genes[i]=partner._genes[i]; 9 } 10 } 11 return child; 12 }
在上面方法中,在生命周期的每一帧中随机选择双亲对应节点的数据作为子代的基因。下面为Bird类添加繁殖的方法:
/*小鸟的繁殖*/ public crossover(b:Bird):Bird{ let bird=new Bird(1,initX,initY);//小鸟质量为1,初始位置为(initX,initY) let dna=this.dna.crossover(b.dna); bird.dna=dna; return bird; }
7. 群体的繁殖
接下来在Population中添加reproduction方法,用来产生下一代。在reproduction方法中,我们从交配池中随机的选择两个小鸟作为双亲,产生新的小鸟,并使小鸟发生突变,最后把新产生的小鸟加入数组population中。
1 public reproduction(){ 2 3 for(let i=0;i<this.population.length;i++){ 4 let a=Math.floor(Math.random()*this.matingPool.length); 5 let b=Math.floor(Math.random()*this.matingPool.length); 6 let partnerA=this.matingPool[a]; 7 let partnerB=this.matingPool[b]; 8 let child=partnerA.crossover(partnerB); 9 child.target=this.target;//为小鸟设定目标 10 11 child.mutate(this.mutationRate); 12 this.removeChild(this.population[i]); 13 this.population[i]=child; 14 this.addChild(child); 15 } 16 }
三
、总结和优化
通过上面的示例,我们可以总结出使用遗传算法时的几个关键步骤:
1. 定义个体的基因型和表现型,基因型发生改变表现型也会随之变化。
2. 计算群体中每个个体的适应性;
3. 选择适应性更高的个体作为下一代的双亲(可以通过交配池实现);
4. 通过双亲繁殖下一代,产生的下一代会发生基因突变;
5. 返回2进行下下一代的繁殖;
上例中,小鸟在进行多代繁殖后,最终会沿直线朝目标飞去。为了体现遗产算法的强大,可以在小鸟和目标之间加入障碍物,当小鸟碰到障碍物时会停止,并且碰到障碍物的小鸟的适应性会急速下降。可以看看经过几代的进化后聪明的小鸟会如何绕过障碍物到达目标点。
上面只贴出了整个项目中关键几步的代码,整个项目可以访问我的GitHub,欢迎提交issues交流。