遗传学算法概述

从之前转载的博客《非常好的理解遗传算法的例子》中可以知道,遗传学算法主要有6个步骤:

1. 个体编码

2. 初始群体

3. 适应度计算

4. 选择运算

5. 交叉运算

6. 变异运算

这是一个仿生的过程,模仿生物进化和自然选择。在该算法中,个体编码就相当于生物最基本的组成——基因,初始群体就是刚开始那些个原始的生物体。

在恶劣的环境中,适者生存的自然法则将让适应能力更好的生物继续存活繁衍下去,而适应能力差的生物将会被淘汰。因此遗传算法通过计算适应度来模拟这个自然选择的过程,用于筛选优良的个体保留下来。光这么讲也许太抽象,可能读者也无法知道具体如何实现的,也不知道这个适应度是如何去评价去个体的优劣程度的。下面举例个简单的例子来说明,如下图:假如现在要求一条曲线方程的最大值,并且已知有若干个点。那么曲线的值也就是求最大值过程中的适应度,因为值越大就越接近最大值,其适应度就越好。因此在这个求最大值的过程中,曲线对应的值可以直接作为适应度。在下一步选择运算过程中,这些适应能力好的个体也有更高的概率被保留下来。

选择运算就是自然选择的过程。在适应度计算过程中,各个个体的适应能力已经知道,因此部分适应能力差的个体就将会被淘汰。就想自然选择一样,大自然不会对生物体适应能力进行排序,然后一刀切全部淘汰弱者。在选择运算中,算法也是根据适应度来确定一个选择概率,按照概率来确定哪些个体允许保留下来。自然地,适应度高的,被保留下来的概率也更高,而适应度低的保留下来的可能性就越低。

进行选择之后,保留下来的个体就像生物一样,需要在自己的生命周期内繁衍后代来延续自己的物种。然后,就是脸红心跳的配对阶段了,两个个体之间需要贡献各自的染色体进行交换。这一过程中新的个体经过交叉运算获得由父母双方部分基因的组合,新的个体中基因来自于父母双方。当然了,算法中交差运算没有男女之分,交叉运算后所有的个体都是交叉运算产生的新个体,原本的个体被新个体代替不进入下一次迭代。如《非常好的理解遗传算法的例子》中过程5的描述:

交叉的时候进行交换基因的位置也是随机产生的,交换个体同样按照各自适应度以一定概率进行选择。因此适应度高的个体进行交差运算的概率也更高,这个在动物界比较普遍,即强壮的首领拥有交配权,以便优良基因更多机会保留下去。并且交叉本身也有一定发生概率,如果不进行交叉,那么交叉的结果就是新个体与原个体相同。这个理解起来也方便,就是说,要是进行交叉了,新个体为交叉结果;那要是不孕育新个体呢,那抱歉,你们两个个体还要经过下一次迭代。

最后,就是生物进化的过程了,这是一个小概率事件,但却是造就如今这样美丽而伟大的生命世界的关键。变异是随机的,因为随机,因此绝大部分变异都是恶性的,但也正是这种不确定性才导致了生物的多样性,让我们的世界变得美妙多彩。因为有自然选择的过程,变异后恶化的基因会被抛弃,因此,整个生物界依靠这几个关键步骤保持着不断进化,不断适应的趋势。但是,同样地,我们可以预料到,在变异运算这一步中,变异出现的概率会非常小,否则整个算法也就随机了。说了那么多,归结起来,变异在算法中的体现说白了就是按照一个小概率去挑选一个个体,然后将其某个编码后的码字取个反,当然,这是在二进制编码的情况下来说啦。

本身遗传学算法也是一门很复杂的学问,研究到现在,求解过程越来越像一个生命体的进化过程,但是基本思想还是如上述所说。同样地,下面我也将上述最基础的遗传学算法用matlab进行实现,各位读者也可以参照着代码来理解算法。

Matlab算法实现

下面演示,利用遗传学算法来求解最佳分割阈值。这个方法参考论文《Infrared Image Segmentation Based on Otsu and Genetic Algorithm》,该论文基于大津法和遗传算法来分割红外图像。不说算法有多好,其实也差不多,还不一定有Otsu来得直接(抱歉,我喜欢喷一喷(*^__^*) ),但是通过这个案例能够有效地描述遗传算法的使用。这里要感谢一下我师兄将该文献翻译的成中文,让我看起来方便多了。

大津法大家应该都听说过,目的是求最优的前景和背景的分界面,在图像分割算法中,大津法也是最有名的算法,个人觉得,没有之一。这里实际是使用遗传算法来求这个最优的分界面,就如上述我举例说求曲线的最大值一样,只是这里面最适应度的计算不是那么直接。下面从总体到各部分细节一一介绍。

(一)分割算法

这里将文中的算法命名为OtsuWithGenetic,算法不需要人为添加任何参数来辅助运算。从算法的名称来看,就可以知道,算法结合了大津法和遗传算法两者的特征。因此,在进行遗传算法的迭代流程之前,需要计算图像的直方图。而进行遗传学迭代运算的过程,在本案例中,我将其封装成一个名为BestThresh的函数,它的输入同样仅需要图像的直方图就可以了。在求取最佳阈值之后,就对图像进行二值化,得到最终结果图。

所以分割算法整体分为三个步骤:

1. 计算图像直方图

2. 利用遗传学算法求最佳阈值

3. 图像分割,进行二值化

function ImOut = OtsuWithGenetic(ImOriginal)
% 大津分割算法,结合遗传算法
% 在性能方面暂未进行相应优化,只对求解方程进行了优化
% 部分代码结构比较凌乱 ImGray = double(rgb2gray(ImOriginal)); %转换为双精度灰度图 [m,n] = size(ImGray); %计算图片的尺寸
ImHist = zeros(1,256); %灰度直方图
ImOut = zeros(m,n); %分割结果图像 % 统计各灰度级的像素点个数,计算灰度直方图
for i=1:m
for j=1:n
ImHist(ImGray(i,j)+1) = ImHist(ImGray(i,j)+1)+1;
end
end th = BestThresh(ImHist); % 分割图像,高于阈值为前景255,低于阈值为背景0
for i = 1:m
for j = 1:n
if (ImGray(i,j)+1>th)
ImOut(i,j) = 255;
else
ImOut(i,j) = 0;
end
end
end ImOut=uint8(ImOut); %读入读出变换
end

(二)遗传算法求解大津最佳阈值

这一步实际上就是BestThresh函数的描述。从整个函数的代码中我们可以很清楚地看到遗传学算法描述中的6个步骤。

function bestindividual = BestThresh(ImHist)
popsize=40; %群体大小
chromlength=8; %字符串长度(个体长度)
pc=0.9; %交叉概率
pm=0.001; %变异概率 pop = InitEntity(popsize,chromlength); %随机产生初始群体
for i = 1:50 %50为迭代次数
[objvalue] = FitnessValue(pop, ImHist); %计算目标函数
fitvalue = CalFitValue(objvalue); %计算群体中每个个体的适应度
[newpop] = Selection(pop,fitvalue); %选择
[newpop] = CrossOver(newpop,pc); %交叉
[newpop] = Mutation(newpop,pm); %变异
pop = newpop;
end
[bestindividual,bestfit] = BestEntity(pop,fitvalue); %求出群体中适应值最大的个体及其适应值
bestindividual = DecodeChrom(bestindividual,1,chromlength);
end

这里在一开始定义了四个参数:popsize, chromlength, pc, pm。具体含义见注释,这里重点介绍pc和pm两个参数。pc是交叉概率,pm是变异概率,在上述描述中我们说到,交叉和变异都是按照一定概率进行的,从这里也可以看到,两者的概率之间的差别。这里我默认将两者的概率定为了0.9和0.001,同样,迭代次数和群体的大小也定死了,实际上,运算次数再多,群体再大,也是浪费运算资源。

从代码中看到,在初始化完个体后,就按顺序进入迭代运算,迭代经过适应度的计算、选择运算、交叉运算和变异运算。其中计算目标函数和个体适应度计算实际是一个内容,CalFitValue实质是进行了矫正防止出现负数,而FitnessValue是适应度计算函数。

迭代结束以后,将适应度最大的作为最终的阈值,并且经过解码之后转换为实际的灰度值。

1. 初始化群体+个体编码

在本案例中,需要计算最佳的阈值,也就是计算作为阈值的那个最优的灰度值。对灰度值进行二进制编码获得随机的40个群体代码如下:

% 1 初始化群体(编码)
% popsize表示群体的大小,chromlength表示染色体的长度(二值数的长度)
function entities = InitEntity(entitySize,chromLength)
% rand随机产生随机数矩阵,round将其二值化
entities = round(rand(entitySize, chromLength));
end

该函数生成一个40行的矩阵,代码40个不同的初始个体;每个个体进行8位二进制编码,因此像素灰度本身也仅有8位深度。

2. 计算适应度

适应度的计算参考论文当中适应度函数

这里这里,是适应度函数,是目标图像像素数目,是背景图像像素数目;是目标图像像素总和,是背景图像像素总和。

% 2 计算适应函数
% 实现目标函数的计算
function [objvalue] = FitnessValue(pop, Imhist)
graysum = Imhist.*(0:1:255); % 各灰度值像素总和
x = DecodeChrom(pop,1,8);% 将pop每行转化成十进制数
loop = size(pop,1);
objvalue = zeros(loop,1);
for i = 1 : loop
P1 = sum(graysum(x(i)+1 : 255));
P2 = sum(graysum(1 : uint8(x(i))));
I = sum(Imhist(x(i)+1 : 255));
J = sum(Imhist(1 : uint8(x(i))));
objvalue(i) = I * J * ((P1-P2)^2) * 2 ;%计算目标函数值
end
end

function fitValue = CalFitValue(objValue)
Cmin = 0;
num = size(objValue,1);
fitValue = zeros(1,num);
for i = 1 : num
if objValue(i) + Cmin > 0
temp = Cmin + objValue(i);
else
temp = 0.0;
end
fitValue(i) = temp;
end
end

3. 选择运算

通过计算得到的适应度就可以知道各个体的适应能力,将这些适应度进行累加,各个体就对应于一个区间。将累加结果进行归一化,然后用随机函数来进行选择,落入哪个区间就选择区间对应的个体。

% 3 选择复制
function [selectedEntities] = Selection(entities,fitValue)
totalFit = sum(fitValue); %求适应值之和
fitValue = fitValue / totalFit; %单个个体被选择的概率
fitValue = cumsum(fitValue); %如 fitValue=[1 2 3 4],则 cumsum(fitValue)=[1 3 6 10]
[num,cols] = size(entities);
ms = rand(num,1); %产生用于选择的随机数 selectedEntities = zeros(num,cols); %初始化选择后的个体大小
for i = 1 : num
for j = 1 : num
if ms(i) < fitValue(j)
selectedEntities(i,:) = entities(j,:);
break;
end
end
end
end

4. 交叉运算

交叉运算利用一对个体产生新个体,函数如下:

% 4 交叉
% 群体中两个个体进行一定的概率 pc 的交叉,交换基因起始位置cpoint随机
function newEntities = CrossOver(entities,pc)
[num, cols]= size(entities);
newEntities = ones(size(entities));
for i = 1 : 2 : num-1
if(rand < pc)
cpoint = round(rand*cols); % 随机产生交换起始位置
newEntities(i,:) = [entities(i,1:cpoint), entities(i+1,cpoint+1:cols)];
newEntities(i+1,:) = [entities(i+1,1:cpoint), entities(i,cpoint+1:cols)];
else
newEntities(i,:) = entities(i,:);
newEntities(i+1,:) = entities(i+1,:);
end
end
end

5. 变异运算

在经过交叉运算以后,还要进行编译运算,由于是二进制编码,变异运算就可以直接将变异位置的二进制数取反。

% 5 变异
function [newEntities] = Mutation(entities,pm)
[num, cols] = size(entities);
newEntities = ones(size(entities));
for i = 1 : num
if(rand < pm)
mpoint = round(rand*cols); % 计算变异位置
if mpoint <= 0
mpoint = 1;
end
newEntities(i) = entities(i);
if any(newEntities(i,mpoint)) == 0 % 进行二进制取反
newEntities(i,mpoint) = 1;
else
newEntities(i,mpoint) = 0;
end
else
newEntities(i,:) = entities(i,:);
end
end
end

6. 计算最优值

在迭代结束后,所有的个体基本上呈现向最优值靠拢的趋势,这时候需要通过比较来取其中的最大值,作为最优解。这一步是一个比较过程,原理很简单:

% 6 求群体中对应的最大适应值
function [bestEntity,bestFit] = BestEntity(entities, fitValue)
num = size(entities, 1);
bestEntity = entities(1,:);
bestFit = fitValue(1);
for i = 2 : num
if fitValue(i) > bestFit
bestEntity = entities(i,:);
bestFit = fitValue(i);
end
end
end

(三)二进制转换函数

在运算中,由于使用数组来表示二进制编码数据,因此在运算过程中经常需要进行二进制与十进制之间的转换,转换函数如下:

% 将二进制编码转换成十进制
function decimals = DecodeChrom(entities,spoint,length)
temp = entities(:, spoint:spoint+length-1);
decimals = DecodeBinary(temp);
end % 将二进制转化为十进制
function decimals = DecodeBinary(pop)
[num,cols] = size(pop);
temp = zeros(num,cols);
for i = 1 : cols
temp(:,i) = 2.^(cols-i) .* pop(:,i);
end
decimals = sum(temp,2); 
end

遗传学详解及Matlab算法实现的更多相关文章

  1. 【机器学习详解】SMO算法剖析(转载)

    [机器学习详解]SMO算法剖析 转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/51227754 CSDN−勿在浮沙筑高台 本文力 ...

  2. 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)

    参考网址:图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) - 51CTO.COM 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath ...

  3. 机器学习--详解人脸对齐算法SDM-LBF

    引自:http://blog.csdn.net/taily_duan/article/details/54584040 人脸对齐之SDM(Supervised Descent Method) 人脸对齐 ...

  4. 机器学习笔记----Fuzzy c-means(FCM)模糊聚类详解及matlab实现

    前言:这几天一直都在研究模糊聚类.感觉网上的文档都没有一个详细而具体的讲解,正好今天有时间,就来聊一聊模糊聚类. 一:模糊数学 我们大家都知道计算机其实只认识两个数字0,1.我们平时写程序其实也是这样 ...

  5. (新手向)N皇后问题详解(DFS算法)

    非常经典的一道题: N皇后问题: 国际象棋中皇后的势力范围覆盖其所在的行.列以及两条对角线,现在考察如下问题:如何在n x n的棋盘上放置n个皇后,使得她们彼此互不攻击 . 免去麻烦我们这里假定n不是 ...

  6. TCP-IP详解:Nagle算法

    在使用一些协议通讯的时候,比如Telnet,会有一个字节字节的发送的情景,每次发送一个字节的有用数据,就会产生41个字节长的分组,20个字节的IP Header 和 20个字节的TCP Header, ...

  7. leetcode-全排列详解(回溯算法)

     全排列     给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2 ...

  8. 详解使用EM算法的半监督学习方法应用于朴素贝叶斯文本分类

    1.前言 对大量需要分类的文本数据进行标记是一项繁琐.耗时的任务,而真实世界中,如互联网上存在大量的未标注的数据,获取这些是容易和廉价的.在下面的内容中,我们介绍使用半监督学习和EM算法,充分结合大量 ...

  9. 机器学习——详解经典聚类算法Kmeans

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第12篇文章,我们一起来看下Kmeans聚类算法. 在上一篇文章当中我们讨论了KNN算法,KNN算法非常形象,通过距离公 ...

随机推荐

  1. Android IOS WebRTC 音视频开发总结(五六)-- 如何测试网络性能?

    本文主要介绍如何测试网络性能,文章来自博客园RTC.Blacker,欢迎关注微信公众号blacker,更多详见www.rtc.help 网络性能直接决定了视频通话效果,比如qq,很多时候我们我们觉得通 ...

  2. javaSE第二十五天

    第二十五天    399 1:如何让Netbeans的东西Eclipse能访问.    399 2:GUI(了解)    399 (1)用户图形界面    399 (2)两个包:    399 (3) ...

  3. PHP版实现友好的时间显示方式(例如:2小时前)

    完整php类,通常我会配合smary使用,快捷使用 (plugins/function.rdate.php),更多php技术开发就去php教程网,http://php.662p.com <?PH ...

  4. Show Users Assigned to a Specific Role

    In a previous post I showed you how to know what Roles are assigned to a specific user. But here is ...

  5. Java实现0~100之和

    经典问题了,三个变量分别表示起始.结尾以及和,for循环从起始到结尾,和不断累积.代码如下: public class ForLoop { public static void main(String ...

  6. Service(一)----->简单计算

    xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:t ...

  7. Eclipse之Failed to load the JNI shared library”……\jvm.dll”的解决方案

    问题描述:java环境变量配置完全正确,但是运行eclipse时提示:Failed to load the JNI shared library " xxx\jva.dll" 原因 ...

  8. android获取com.android.internal.R

    使用class.jar, layout.jar可以直接导入com.android.internal.R 但是有个方法获取不到值mDatePicker.findViewById(com.android. ...

  9. paypal api 相关资料

    https://developer.paypal.com/ https://developer.paypal.com/docs/classic/api/merchant/GetBalance_API_ ...

  10. C#使用SQL存储过程完整流程

    存储过程就是固化在SQL数据库系统内部的SQL语句,这样做的好处是可以提高执行效率.提高数据库的安全性.减少网络流量.接下来就讲解如何在数据库中建立一个存储过程. 打开SQL2055数据库,展开“数据 ...