源码
先放上我的源码链接:
https://github.com/AIjugg/Genetic_Algorithm.git
自己思考加纯手写的代码,有兴趣的同学可以拿去玩玩
前言
生物进化是一个有趣的话题,人是怎么从人猿进化到的人,长颈鹿的脖子为什么这么长,猫和老虎为什么一个这么大一个这么小只?
有个人在19世纪就对这些问题感到了浓厚的兴趣,1859年,《物种起源》出版,标志着生物学进入了新的阶段。
生物进化是怎么进行的
学过生物进化论的同学应该知道,进化的核心是自然选择,进化其实是被动的,自然选择对物种做了筛选,保留下了适宜生存的基因,也就是适者生存。
适者生存,现代的生物进化论将适者生存修改为了适者繁衍。
举个🌰,在远古时期,树越长越高,于是短颈鹿吃不到🍃活不下去了,只剩下长颈鹿,经过一代代的繁衍,它们的脖子越来越长。
遗传算法的由来
在20世纪60年代,有人提出将进化论的思想应用到计算机运算中;70年代有人成功运用到了运算中;到了80年代,被Goldberg归纳总结,形成了基本框架。
这便是遗传算法的问世过程。
遗传算法的重要概念与步骤
在学习遗传算法前,我们首先得学习几个概念。
种群
一个生物个体是完不成繁衍进化的,需要众多个体组成一个团体,这个团体称为种群。
附上百度百科的定义:种群(population)指同一时间生活在一定自然区域内,同种生物的所有个体。种群是进化的基本单位,同一种群的所有生物共用一个基因库。
适应度(fitness)
适应度是用来衡量个体对环境适应的能力,一般适应度越高,越适应这个环境。
交叉(crossover)
其实就是生物的交配。父代交叉得到子代。
变异(mutation)
父代交叉得到的子代,其基因有概率发生一定的变化,这种变化有可能是有利的,也可能是有害的。变异是种群多样化的重要一环。
选择(selection)
其实就是淘汰。从群体中选择优胜的个体,淘汰劣质个体的操作叫选择。
流程图
实际应用
在《遗传算法原理及应用》一书中指出,遗传算法是一种自适应全局优化概率搜索算法。我们可以用来做数据拟合、生产规划等,遗传算法的流程跟神经网络的算法很像……
这里我举一个有趣的实例:图像拟合。
之前在网上看到这么一张图片👇
这是怎么实现的?一度令我非常困惑,后来得知这是用遗传算法拟合得到的,于是我开始爬遗传算法的坑。
有想了解遗传算法的同学,可以去我的git上下电子书《遗传算法原理及应用》
实践
目标图
拟合图
上述图片都是我的拟合结果图,数字表示迭代轮次,可见越到后面越接近原图。
浅谈代码原理
问题分析
首先我们需要思考图像拟合这个问题,如何应用遗传算法,我们先用进化论的思维去思考这个问题。
个体:遗传算法中,我们首先需要有个个体,在这里,我们的个体就是一张图片。
基因:有了个体之后,需要明确个体内部需要改变的是什么,也就是基因。
基因是个体内部,发生改变的最小单元,我们知道图片是由像素点构成的,那么我们可以把每个像素点看做是一个基因,那么100*100的图片就是 100*100的像素点。
但这好像太多了,计算起来非常繁琐……上面的蒙娜丽莎图给了我启发,我考虑到可以用半透明的多边形组合成图片,在遗传算法中,个体的基因数量是保持不变的,所以我们的半透明多边形数量也是一直保持不变的(之前这点也令我非常困惑,蒙娜丽莎的拟合图中多边形的数量似乎是变化的)。
适应度 :用来衡量个体适应环境的能力,在我们当前的场景下,可以用图片相似度来表示。用数学公式表示也非常简单,把图片当作矩阵,那么计算出矩阵之间的欧氏距离即可。
我之前的代码就是这么计算适应度的,但后来我发现python里有现成的图片相似度计算方法,于是我直接调用了。
种群:在我们这里,种群自然就是指图片数量了。由于我们的运算是占用cpu内存的,根据cpu计算能力,选择一个合适的种群数量是非常重要的。
种群迭代:我认为种群迭代的概念也是非常重要的,当每次选择父代生成子代,再淘汰一部分适应度低的个体后,算是完成了一轮种族的迭代。
交叉:两个图片要怎么交叉呢?我的做法是,按照顺序,随机选中父本或母本的基因出来,作为子代的基因,按照概率而言,子代一半的基因来自父本,一半来自母本。
变异: 在我的代码中,变异只发生在生成子代时,子代的极少部分基因会发生变异(多边形的某个点坐标变化、或者多边形的颜色发生改变),随着种族的迭代,这种变异改变的特性会越来越小(坐标变化幅度变小、颜色也只会小幅改变)。当然这只是我的经验之谈,在我的实践中就是如此,从常理来想,这样也是合理的,因为到后期我们已经逼近了某个极值点了(局部最优)。
选择:我们每次进行种群迭代时,需要选择,首先计算出每个个体的适应度,根据适应度高低做排行,适应度越高的个体,获得交叉的概率越高(被我戏称为优先交配权),生成子代后,再做一次适应度计算和排行,适应度最低的个体将被无情淘汰。
遇到的有趣的问题
经过非常非常久的反复实践,我遇到了许多有趣的问题,我有时在想,这些问题会不会也是生物进化中的问题呢?
再一次感叹造物主的伟大。
没有变异的繁衍
当我在最初做代码调试时,并没有写变异的代码,在我的认知中,不变异也可以使得种群不断进化,只不过进化速度慢一些罢了。
实际上真的是这样吗?
不,经过几百轮的迭代后,每个个体的适应度都一样了,也就是说种群中的每个个体基因都一模一样😲!
经过打印调试,我发现了一个有趣的现象,由于适应度最高的个体拥有优先交叉权,于是他可以把自己一半的基因传递给子代,而往往他的子代适应度也不会低,于是也拥有较高的交叉权。
经过短短几百轮的迭代,就会出现一个神奇的现象,种群中适应度最高的两个个体,适应度居然一模一样了(基因也一模一样)。而且一旦出现这个现象,那么整个种群被同化就是瞬间的事儿了👻~
我在想,也许我们国人的许多基因是一样的,因为不管是人猿时代还是开启智慧后的五千年,我们也在不断做着选择淘汰。
同时可以看出变异对于一个种群是多么的重要,没有变异,种群就会进化停滞。变异是种群多样化的重要一环。
变异速度
如果一直保持同一变异速度,且变异概率一直很小或很大,都很难快速得到适应度高的个体。
对此我是用爬山来理解的,身处群山中,我想要登顶最高的山峰,如果我的步幅太小,我很可能以为这座山就是最高的山;如果我的步幅非常大,我又可能错过了最高的山;
当然大家要切记,遗传算法并不是求全局最优的算法,它是求局部最优的算法。
纯变异
其实我很早就实践过纯变异版本的遗传算法,我发现压根就不需要交叉,靠每个个体的纯变异,也可以得到一个适应度很高的个体。
这是不是说明,如果一种生命可以自我变异,那么就不需要繁衍了(当然还得有无限寿命才行)。
基因数量是不是越高越好
我个人浅薄的理解是 “是的”,基因越多,个体的表现越充分,能表达的东西越多,比如这个实践中,150个多边形拟合的图片比100个多边形拟合的图片更加细腻。
但由于我们计算资源是有限的,所以基因数量差不多就得了……