Genetic Algorithm - intelligent birds

outline:

First, an overview of genetic algorithms

  2.1 groups

  2.2 genotype and phenotype  

  2.3 mutation

  2.4 Select

  2.5 Genetic

Second, the realization of intelligent birds

  2.1 birds genotype and phenotype

  2.2 birdie how genes affect a bird's flight path

  2.3 Birds adaptability

  2.4 Selection: select the higher fitness bird

  2.5 mutations: increase the richness of the gene

  2.6 Reproduction: generate new DNA

  2.7 breeding population

Summary and optimization

Smart birds

By using a genetic algorithm to achieve an intelligent birds. The scenario of FIG birds right of the screen from the start, the final destination point over obstacles left of the screen. Flying birds will (at FIG. 1) in the screen in the initial state, with the constant evolution, eventually birds directly to the target point (FIG. 2 lower), click here to see the effect . The following first introduced genetic algorithms.

 

 

First, an overview of genetic algorithms

Genetic algorithms borrowed the idea of ​​Darwinian natural selection, that is, in a population, higher adaptability of individuals would be more likely to go on their genetic gene (characteristics). Here are some of the key concepts of natural selection:

1. group

Groups to provide a wealth of natural selection for the gene pool to ensure the diversity of individuals, groups, the more easily produce more adaptive individuals.

2. genotype and phenotype

Individual appearance and behavior we see in substandard performance is determined by the genes inside of. That is, determining an individual's genotype performance of internal data, phenotype is the appearance and behavior of individuals. Such as numbers 125, which can represent the individual colors may also represent the height of an individual. Numeral 125 is the individual's genotype, color, height, etc. of the individual phenotypes. In the design of genetic algorithm, designed to focus on an individual's genotype and phenotype.

3. inheritance, mutation and selection

Genetic mutation and selection are Darwinian evolution in three basic rules. Ensure the genetic offspring can inherit characteristics from their parents. Mutations to ensure the diversity of individuals, if not mutated offspring and parent will always remain the same, the new features will never occur, the population will not evolve. Select the group evolved to ensure more adaptive direction, so that the population can breed some individuals and some individuals have no chance or little chance of reproduction. It is often said that "survival of the fittest." In the genetic algorithm, the calculation of individual genes in each generation of the adaptability of individuals will, in the next generation of high genetic adaptability will continue, low adaptability of individual genes will be eliminated.

Second, the realization of intelligent birds

下面借助白鹭引擎实现智能鸟群

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交流。

 

Guess you like

Origin www.cnblogs.com/snsart/p/11395503.html