人工智能开发,Unity的神经网络+遗传算法(三)
发表于2017-12-19
这次基于上一篇所讲主要讲解一下遗传算法的代码:
先说一下遗传算法的实现所需要的步骤:
需要知道这几点:
1、种群:
生物以种群形式进行(这也是游戏中训练的难点,并无法大规模的训练);
2、个体:
组成种群的单个生物;
3、基因:
一个遗传因子(这里我们是单个的权重);
4、染色体:
一组基因(也就是这一组权重);
5、 生存竞争,适者生存:
这里我们需要适应度来决定哪个更能适应这个环境,从而选择NB的基因进行繁殖;适应度低的也就是上一章讲的靠山下的给正义掉;从而选择优秀的基因进行繁殖;
6、 遗传和变异:
新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。(这个父母双方)这里我们采用一个轮盘赌的算法来决定这对夫妇;
遗传步骤:
1、随机种群基因:因为第一组的是弱智他不知道干什么;这需要在开始的时候初始化;
2、然后开始按照第一部分的基因开始神经网络判定和行为;
3、根据规则的一顿击杀评分来计算出他的适应度,因为这里只讲遗传算法的脚本,SO不多讲;
4、到时间后进行新的一波繁殖,根据适应度;也就是只找到了两只优秀的坦克;
5、繁殖过程需要经过交叉,变异和遗传;
6、第二轮经过优秀的坦克的基因继续进行行为;
下面贴代码:(代码已经在我个人认为的难点和属性做了注释)
using System; using System.Collections.Generic; using System.Linq; public class Geneticalgorithm { //选择的方法 public int Count;//种群数量 public List<IGizeable> ListIG; //储存种群所有个体 public double Mutation; //变异概率 public static Random _random = new Random(); public Geneticalgorithm(int poCount, double mutate) { this.Count = poCount; this.Mutation = mutate; ListIG = new List<IGizeable>(poCount); } private List<IGizeable> GetAThera() { //获取同样种群数量的对数的夫妇来用来繁殖新的群体 var res = new List<IGizeable>(2 * Count); var sum = ListIG.Sum( itme => itme.fitness ); //获取这个群体所有适应度的总和 var fitnessgote = new double[Count]; //用来储存每一个 单体生物的适应度概率; for (var i = 0; i < fitnessgote.Length; i++) fitnessgote[i] = ListIG[i].fitness / sum; //计算每一个适应度的概率 fitnessgote.OrderByDescending( x => x ); var counter = 0; while (counter < Count) {//循环不停的配对 每一对基本上都不一样 var leftGen = RandomIndex(fitnessgote); //获取适应度最好的那个个体下标; var rightGen = RandomIndex(fitnessgote);//获取另一个 两个不一样 if (leftGen == rightGen) continue; res.Add(ListIG[leftGen].Reproduce()); res.Add(ListIG[rightGen].Reproduce()); counter ++; } return res; } public void Cross(IGizeable mom, IGizeable dad) {//交叉 var momW = mom._weightAndBasi; var dadW = dad._weightAndBasi; var n = _random.Next(momW.Count); for (var i = 0; i < momW.Count; i++) { if (i < n) momW[i] = dadW[i]; else dadW[i] = momW[i]; } mom._weightAndBasi = momW; dad._weightAndBasi = dadW; } private void AllReproduce(List<IGizeable> pairs) {//繁殖新一代群体基因; ListIG.Clear(); for (var i = 0; i < pairs.Count; i += 2) { Cross(pairs[i], pairs[i + 1]); Muta(pairs[i]); ListIG.Add(pairs[i]); } } public void Evolve(double[] newFitnesses) {//进化 for (var i = 0; i < newFitnesses.Length; i++) ListIG[i].fitness = newFitnesses[i]; AllReproduce(GetAThera()); } public void Randomlation(double min = -1.0, double max = 1.0) {//随机种群 在训练初始化时调用 for (var i = 0; i < Count; i++) Randommm(ListIG[i], min, max); } private int RandomIndex(IList<double> probs) { //算法返回下标 double top = 0; var randomValue = _random.NextDouble(); for (var i = 0; i < probs.Count; i++) { var bot = top; top += probs[i]; if (randomValue >= bot && randomValue <= top) return i; } return 0; } public void Muta(IGizeable gen) {//变异 var w = gen._weightAndBasi; for (var i = 0; i < w.Count; i++) if (_random.NextDouble() < Mutation) w[i] += _random.NextDouble() * 2 - 1; gen._weightAndBasi = w; } private static void Randommm(IGizeable gen, double min, double max) { var w = gen._weightAndBasi; for (var i = 0; i < w.Count; i++) { w[i] = _random.NextDouble() * (max - min) + min; } gen._weightAndBasi = w; } } public interface IGizeable {//优化遗传接口 用来储存继承这个接口的所有个体; List<double> _weightAndBasi { get; set; } //一组遗传基因(这里也就是这组权重和偏移); double fitness { get; set; } //适应度 用来决定淘汰的是谁; IGizeable Reproduce(); //繁殖的方法; }