遗传算法的具体介绍,请自行搜索,本文也没有完全按照网络上的写法做,作者水平有限,使用的中间算法也都不怎么高明,请各位带着批评看文章。
本文采用的遗传算法步骤
- ①初始种群
- ②淘汰
- ③交叉
- ④变异
- ⑤重建种群并迭代②-④步
- ⑥画图等额外操作
源码地址:https://github.com/kk1987n/GeneticAlgorithmPHP.git
本文引入某大神关于扇贝的故事,PHP代码大致也是这么写的。
某海滩上有一群扇贝无忧虑的生活着,上帝闲来无事派bob过来用遗传算法整这群扇贝,bob来了之后,给扇贝提了要求:
①你们只能有16个扇贝,每一代我要杀死2个,哪2个贝壳上的图案最不像谷歌浏览器图标我就杀谁;
②剩余的14个中有4个扇贝两两结合生2个孩子,再凑够16个,如此循环;
这些扇贝很是苦恼啊,可是又有什么办法呢,一些扇贝离开了,之后正好留下来16个,就是这些扇贝,创造了后来的chrome扇贝。
遗传算法模拟达尔文孟德斯鸠这类神人的遗传学规律,对种群进行筛选,繁殖,变异,如此经过多代,即可培育出那些符合规则的目标。
遗传算法的
初始种群可以是随机建立的,比如故事中最开始的16个扇贝。
为此我们为扇贝增加一个适应度属性,也就是扇贝背上的图案,与我们的chrome图标有多像;
这里适应度计算标准为,像素点个数*通道数/像素点4通道差值(绝对值)之和S,4通道包含透明通道。
我们使用的是32px*32px的chrome图标,所以适应度F=32*32*4/差值和S。
适应度冒泡排序,最差的2个,unset掉
所谓交叉,就是基因组合,就是父亲母亲基因各取一半,组成一个新的扇贝。
经过淘汰之后,还剩下14个,程序千7个选1个,后7个选1个,组合出1个新扇贝(这步循环2次,组成2个新扇贝)。
新扇贝的每个像素点,以50%的几率从父亲或母亲那里获取其像素点的颜色值。
新扇贝随机选取2个像素点,随机其颜色值
把新扇贝加入到原先的14个扇贝中,组成新的1代。
包含4个属性rgba
namespace Ga\Pix\base;
/**
* 颜色点
* 包含四个数学,r:红色,g:绿色,b:蓝色,a:透明度
* @author Linko
* @email [email protected]
* @link https://github.com/kk1987n/GeneticAlgorithmPHP.git
* @date 2018/04/24
*/
class Color {
public $r;
public $g;
public $b;
public $a;
public function __construct($rgba = array()) {
if (empty($rgba)) {
$this->setRand();
} else {
$this->r = $rgba[0];
$this->g = $rgba[1];
$this->b = $rgba[2];
$this->a = $rgba[3];
}
}
/**
* 设置随机值
* @return type
*/
public function setRand() {
$this->r = rand(0, 255);
$this->g = rand(0, 255);
$this->b = rand(0, 255);
$this->a = rand(0, 127);
return array($this->r, $this->g, $this->b, $this->a);
}
/**
* 适应率公式,像素点差额的和
* 当前像素与对比像素之间的差别
* @param type $Pix
* @return type
*/
public function fitness(Color $Pix) {
$r = abs($this->r - $Pix->r);
$g = abs($this->g - $Pix->g);
$b = abs($this->b - $Pix->b);
$a = abs($this->a - $Pix->a);
return $r + $g + $b + $a * 2;
}
}
包含32*32个颜色对象,扇贝的适应度,扇贝的代数和名字,基因变异次数,以及要对比的基础图像信息。
namespace Ga\Pix\base;
use Ga\Pix\Config;
/**
* 扇贝,一个扇贝包含多个颜色点,这些颜色点属于扇贝的基因
* @author Linko
* @email [email protected]
* @link https://github.com/kk1987n/GeneticAlgorithmPHP.git
* @date 2018/04/24
*/
class Scallop {
public $pixs = array(); //扇贝上的像素点
public $fitness; //当前扇贝的适应度
public $generation; //扇贝第几代
public $scpName; //扇贝的名字,每一个扇贝都有唯一的名字,用数字标识
public $variationCnt; //基因变异个数
public $baseImgPixs; //基础图片
public $baseImgWidth; //基础图片宽度
public $baseImgHeight; //基础图片高度
public function __construct($Generation, $scpName = 0, $baseImgWidth = 0, $baseImgHeight = 0) {
}
/**
* 初始化当前扇贝
* 分两步
* 1、创建扇贝每个像素点的颜色值
* 2、计算当前扇贝的fitness(适应度)
*/
public function initScp() {
for ($x = 0; $x < $this->baseImgHeight; $x++) {
for ($y = 0; $y < $this->baseImgWidth; $y++) {
$this->pixs[$x][$y] = new Color();
}
}
$this->calFitness();
}
/**
* 计算适应率
* 像素数*通道数/像素通道差额和
* @return int
*/
public function calFitness() {
}
/**
* 杂交
* 此处杂交父母基因各区50%概率
* @param Scallop $scpA
* @param Scallop $scpB
* @return boolean
*/
public function createScpByParent(Scallop $scpA, Scallop $scpB) {
}
/**
* 变异
* 根据变异像素数,为随机点设置新的颜色
* @return boolean
*/
public function variation() {
}
/**
* 画出当前扇贝
* 到文件
* @return type
*/
public function drawScp() {}
}
包含当前第几代,基础图片信息,种群内扇贝数等很多信息,种群进行了循环迭代
namespace Ga\Pix\base;
use Ga\Pix\base\Scallop;
use Ga\Pix\Config;
/**
* 这是一个种群
* 这是1个种群,种群内包含多个扇贝
*
* @author Linko
* @email [email protected]
* @link https://github.com/kk1987n/GeneticAlgorithmPHP.git
* @date 2018/04/24
*/
class Population {
public $baseImgPixs; //基础对比图
public $baseImgWidth; //基础图宽度
public $baseImgHeight; //基础图高度
public $scallops = array(); //扇贝
public $scpCnt; //种群内扇贝的数量
public $chdCnt; //每次迭代产生的孩子数量
public $generation; //当前是第几代
public $scpName = 1; //创建的扇贝的名字,每一个扇贝都有唯一的名字,用数字标识
public $fitness = array(); //适应度-用来画曲线
public function __construct($Generation = 1) {
}
/**
* 初始种群,最开始的随机种群,这是第一代种群
*/
public function initPop() {
}
/**
* 代数迭代
*/
public function start() {
for ($x = 0; $x < Config::GenerationMaX; $x++) {
echo $this->generation . PHP_EOL;
$this->generation++;
$this->killScp(); //杀死原种群中适应度最差的几个,补充上孩子
$children = $this->birthChild(); //结合生出孩子
$this->addToScp($children);
$this->calFitness(); //计算适应度总和
if ($this->generation % Config::drawByCnt == 0) {
foreach ($this->scallops as $scp) {
$scp->drawScp();
}
}
}
}
/**
* 生小孩
*/
public function birthChild() {
}
/**
* 交叉扇贝
*/
public function crossScp(Scallop $scpA, Scallop $scpB) {
}
/**
* 杀死较差的扇贝
*/
public function killScp() {
}
/**
* 把没被杀死的父辈,和孩子合起来
* @param type $children
*/
public function addToScp($children) {
}
}
这三个类组成了程序的核心部分,其余都是辅助类,包括加载机制,入口文件,分发器等等。。。
1万代适应度曲线
1万代生成的效果图
100万代适应度曲线
100万代生成的效果图(太多了,只看后边的了。)
源码地址:https://github.com/kk1987n/GeneticAlgorithmPHP.git
转载请注明:阿鑫-PHP写算法