读研究生的时候上了智能控制的课,课上讲了遗传算法、粒子群算法还有模糊控制等等。我对遗传算法非常感兴趣,用MATLAB复现了遗传算法进化蒙娜丽莎,这也是我公众号头像的来源。
本文就来详细的介绍遗传算法的基本内容,以及如何使用遗传算法绘制“蒙娜丽莎”等让你心仪的图片。
第一节 遗传算法概述
遗传算法(Genetic Algorithm, GA)起源于对生物系统所进行的计算机模拟研究。它是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法,借鉴了达尔文的进化论和孟德尔的遗传学说。其本质是一种高效、并行、全局搜索的方法,能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应地控制搜索过程以求得最佳解。遗传算法是一种借鉴生物界自然选择和自然遗传机制的随机搜索法。它与传统的算法不同,大多数古典的优化算法是基于一个单一的度量函数的梯度或较高次统计,以产生一个确定性的试验解序列;遗传算法不依赖于梯度信息,而是通过模拟自然进化过程来搜索最优解,它利用某种编码技术,作用于称为染色体的数字串,模拟由这些串组成的群体的进化过程。
1.1 遗传算法的基本思想
遗传算法正是依据生物进化中的“适者生存”规律的基本思想设计的,它把问题的求解过程模拟为群体的适者生存过程,通过群体的一代代的不断进化(包括竞争、繁殖和变异等)出现新群体,相当于找出问题的新解,最终收敛到“最适应环境”的个体(解),从而求得问题的最优解或满意解。
遗传算法在求解优化问题时,都是将实际问题的求解空间按一定的编码方式表现出来,即对解空间中的各个解进行编码。所谓解的编码就是把各个解用一定数目的字符串(如“0”和“1”)表示。字符串中的每一位数称为遗传基因,每一个字符串(即一个解的编码)称为一个染色体或个体。个体的集合称为群体。遗传算法的寻优过程就是通过染色体的结合,即通过双亲的基因遗传、变异和交配等,使解的编码发生变化,从而根据“适者生存”的规律,最终找出最优解。表1说明了生物遗传的基本概念在遗传算法中的体现。
1.2 遗传算法与传统方法的比较
1.2.1 遗传算法与启发式算法的比较
启发式算法是通过寻求一种能产生可行解的启发式规则,找到问题的一个最优解或近似最优解。该方法求解问题的效率较高,但是具有唯一性,不具有通用性,对每个所求问题必须找出其规则。但遗传算法采用的是不是确定性规则,而是强调利用概率转换规则来引导搜索过程。
1.2.2 遗传算法与爬山法的比较
爬山法是直接法、梯度法和Hessian法的通称。爬山法首先在最优解可能存在的地方选择一个初始点,然后通过分析目标函数的特性,由初始点移到一个新的点,然后再继续这个过程。爬山法的搜索过程是确定的,容易产生局部最优解;而遗传算法是随机的。
1.2.3 遗传算法与穷举法的比较
穷举法就是对解空间内的所有可行解进行搜索,但是通常的穷举法并不是完全穷举法,即不是对所有解进行尝试,而是有选择地尝试,如动态规划法、限界剪枝法。对于特殊的问题,穷举法有时也表现出很好的性能。但一般情况下,对于完全穷举法,方法简单可行,但求解效率太低;对于动态规划法、限界剪枝法,则鲁棒性不强。相比较而言,遗传算法具有较高的搜索能力和极强的鲁棒性。
经上面的探讨,可以看到遗传算法与传统优化方法在本质上有着不同之处,主要有以下几点:
1.3 遗传算法的计算步骤
图1为利用遗传算法求解工程优化设计问题的流程图,包括以下步骤:
第二节 程序实现
本程序利用遗传算法,基于matlab软件编写程序,通过100个半透明三角形绘制图像逼近被载入的原始图像。在自然界中,生物个体样貌很大程度上由染色体上的基因决定的。同样,我们把100个半透明三角形组成的东西看作为一个个体,则该个体样貌由组成它的半透明三角形的位置及颜色决定。可以将100个半透明三角形认定为该个体的“基因”。该“基因”通过选择、交叉、变异等遗传过程,逐渐逼近理想中的原始图像。下面具体针对遗传算法的主要过程进行详细阐述:
(1)载入原始图像
在matlab中,图像是以矩阵的形式表述,通过以下程序即可载入原始图像。
[filename, pathname] = uigetfile({'*.jpg;*.png;','选择图片文件'});
pic_origin = imread(fullfile(pathname,filename));
(2)创建初始种群
种群由7200×total_amount阶矩阵表示,采取二进制形式(其中7200=8×(2×3+3)×100,8位二进制数表示0-255直接的数,每个三角形有三个顶点和一个RGB颜色)。在ASCII表中的48和49分别对应0和1。每个个体的“基因”,即100个三角形的位置色、颜随机。程序如下:
population = char(randi([48,49],7200,total_amount))
(3)计算适应度值
适应度值是度量某个物种对于生存环境的适应程度。对生存环境适应程度较高的物种将获得更多的繁殖机会,而对生存环境适应程度较低的物种,其繁殖机会就会相对较少,甚至逐渐灭绝。由于图片是由像素点构成的,因此需要将原始图像与matlab程序绘制的逼近图像进行逐像素点对比.将两张图片相应位置的像素点值相减求绝对值,再将差值累加就得到了图像之间的总差距。根据matlab中彩色图片的表示特性可知,两张图片的最大差值为255×255×255×3,因此适应度函数为:
适应度值计算程序如下:
error = abs(pic_resize - pic_gene);
Fitness = 1 - sum(error(:))/max_diff;
(4)选择最优子代
本程序对每代循环中适应度最高的2代基因特殊照顾,可不经过选择、交叉、变异直接遗传到下一代循环中。程序如下所示:
[~,outstanding_gene_index] = sort(fitness_array);
outstanding_gene_index = outstanding_gene_index(end-outstanding_gene_amount+1:end);
outstanding_gene = population(:,outstanding_gene_index);
(5)选择
选择指决定以一定的概率从种群中选择若干个体的操作。一般而言,选择的过程是一种基于适应度的优胜劣汰的过程。本程序采用轮盘赌选择法。其基本思想是:各个个体被选中的概率与其适应度大小成正比。计算各个种群的选择概率,并进一步得到累计概率,与在[0,1]区间内产生一个随机数进行对比,若该随机数小于或等于个体的累积概率且大于个体1的累积概率,选择个体进入子代种群。实现程序如下:
fitness_array = fitness_array / sum(fitness_array(:)); %归一化 (选择概率)
accumulation= cumsum(fitness_array); %累计概率
roulette_number = rand(1,pop_num);
survive_index = discretize(roulette_number ,[0,accumulation]);
new_population = population(:,survive_index);
new_population = [new_population,outstanding_gene];
new_population = new_population(:,randperm(total_amount))
(6)交叉
基因交叉,或者基因重组,就是把两个父体部分结构加以替换,生成新的个体的操作。交叉策略可分为单点交叉、多点交叉、均匀交叉等。其中,单点交叉指在个体编码串中只随机设置一个交叉点,然后在该点相互交换两个配体个体的部分染色体;多点交叉是指在个体基因串中随机设置多个交叉点,然后进行基因块交换。其操作过程与一点交叉和两点交叉相类似;均匀交叉也称一致交叉,其具体运算是通过随机生成一个屏蔽字来决定子代个体如何从父代个体获得基因。这个屏蔽字的长度要与个体基因串长度相同,且均由0,1生成。
交叉(二进制均匀交叉)
crossover_index = rand(7200,1)<cross_position; %生成屏蔽模板
population_new = new_population;
for m = 1:total_amount/4
if rand < cross_rate
ser=find(crossover_index==0);
population_new(ser,m) = new_population(ser,m+total_amount/4);
population_new(ser,m+total_amount/4) = new_population(ser,m);
end
end
for n = 2*total_amount/4:3*total_amount/4
if rand < cross_rate
ser=find(crossover_index==0);
population_new(ser,n) = new_population(ser,n+total_amount/4);
population_new(ser,n+total_amount/4) = new_population(ser,n);
end
end
本程序对二进制编码进行均匀交叉。均匀交叉在开始迭代时可以加快新的较优模式的发现,在趋于收敛时可防止收敛于局部极值点,而且具有比经典交叉更好的重组能力。
(7)变异
在基因交叉之后产生的子代个体,其变量可能以很小的概率或者步长发生转变,这个过程称为变异。程序中变异概率为0.001。实现程序如下:
%% 变异
mutation_index = rand(7200,total_amount)<mut_rate;
population = char(uint8(xor(new_population>48,mutation_index))+48); %异或,相同为1相异为0
population = [population(1:7200,outstanding_gene_amount+1:end),outstanding_gene];
第三节 运行结果
第四节 一点小结
感谢阅读!