遗传算法简单介绍与MATLAB实现(二)

遗传算法简单介绍与MATLAB实现(二)

引入题目一

上一篇文章中我们简单的介绍了一了一下遗传算法,其中提到了多元函数$f=f(x, y)$,所以在这里我们就定义一个二元函数,作为第一个练手的程序。

我们在这里令

$$z = \sin{x}+\cos{y}+0.1(x+y)$$

通过使用MATLAB作图可以看到下图

可以看出这是一个存在很多区域极大值,有很多“坑”。这正是遗传算法的缺陷之一——求出来的最优解可能并不是全局最优解而是局部最优解。

从图中可以看出全局最大值在$(10, 10)$附近。所以接下来我们就开始编程解决这个问题。


遗传算法MATLAB程序

设定参数

首先我们要确定一系列参数

N = 100;  %种群内个体数目
N_chrom = 2; %染色体节点数
iter = 2000; %迭代次数
mut = 0.2;  %突变概率
acr = 0.2; %交叉概率

其中突变概率指的是某个个体的染色体发生突变的概率。因为实际中并不可能每一个个体都会发生突变,而是存在一定的概率,因此我们在这里定义每一个个体突变发生的概率为0.2。

同理,交叉概率指的就是某个个体与另一个个体发生染色体交叉的概率。

迭代次数指的是整个种群迭代2000多次。

一般来说,并不是突变概率、交叉概率越小或者越大越好。比如说突变概率特别高的话,会让整个种群的最优适应度飘忽不定。如果特别小的话,会让种群迭代的速度特别慢,很难找到最优适应度。这里取0.2是我经过多次试验以后,觉得0.2是一个比较稳定不会乱飘且适应度收敛也不错的一个值。

迭代次数也同理,如果一个特别简单的模型去求最优解,可能五六次迭代就求出来了,那么2000次迭代纯属浪费时间。但是如果是一个特别复杂的模型,那么2000次迭代就有可能不够。具体迭代次数可以自己灵活决定。

chrom_range = [-10 -10; 10 10];%每个节点的值的区间
chrom = zeros(N, N_chrom);%存放染色体的矩阵
fitness = zeros(N, 1);%存放染色体的适应度
fitness_ave = zeros(1, iter);%存放每一代的平均适应度
fitness_best = zeros(1, iter);%存放每一代的最优适应度
chrom_best = zeros(1, N_chrom+1);%存放当前代的最优染色体与适应度

其中的chrom_range指的是每个节点值的区间。在我们的这个模型中,$x\in [-10, 10], y\in[-10, 10]$。第一行放的是两个变量的区间下限,第二行放的是区间上限。

chrom和fitness两个矩阵你们可以自己理解一下为什么这样子写。

fitness_ave用来存放每一代的平均适应度,主要是用来最后画图,观察种群在每一次迭代中适应度的变化情况。fitness_best同理。

chrom_best用来存放最优适应度对应的最优染色体与适应度,可以回想一下上一章染色体变异中需要最优适应度,优胜劣汰中需要最优染色体,这个矩阵作用就是如此。

初始化种群

接下来开始初始化参数

chrom = Initialize(N, N_chrom, chrom_range); %初始化染色体
fitness = CalFitness(chrom, N, N_chrom); %计算适应度
chrom_best = FindBest(chrom, fitness, N_chrom); %寻找最优染色体
fitness_best(1) = chrom_best(end); %将当前最优存入矩阵当中
fitness_ave(1) = CalAveFitness(fitness); %将当前平均适应度存入矩阵当中

Initialize函数是我自定义的一个函数,用于初始化染色体。具体操作就是用一个for循环对每个个体的染色体进行随机赋值,并利用chrom_range将其限定在变量规定的区间之内。

function chrom_new = Initialize(N, N_chrom, chrom_range)
chrom_new = rand(N, N_chrom);
for i = 1:N_chrom %每一列乘上范围
    chrom_new(:, i) = chrom_new(:, i)*(chrom_range(2, i)-chrom_range(1, i))+chrom_range(1, i);
end

CalFitness函数则是计算chrom内每个个体的适应度,并将其保存在fitness中。这个函数很重要,请着重理解这个函数的用法

function fitness = CalFitness(chrom, N, N_chrom)
fitness = zeros(N, 1);
%开始计算适应度
for i = 1:N
    x = chrom(i, 1);
    y = chrom(i, 2);
    fitness(i) = sin(x)+cos(y)+0.1*x+0.1*y;
end

FindBest函数寻找出当前种群中的最优染色体,并将其保存在chrom_best。

function chrom_best = FindBest(chrom, fitness, N_chrom)
chrom_best = zeros(1, N_chrom+1);
[maxNum, maxCorr] = max(fitness);
chrom_best(1:N_chrom) =chrom(maxCorr, :);
chrom_best(end) = maxNum;

CalAveFitness函数用于计算当前种群中的平均适应度。

function fitness_ave = CalAveFitness(fitness)
[N ,~] = size(fitness);
fitness_ave = sum(fitness)/N;

迭代开始

初始化完以后就开始迭代,为了保证迭代次数和iter一致,这里我们就直接令t从2开始迭代。

再一次迭代过程中,一个种群执行操作顺序为:染色体变异,染色体交叉,计算适应度,寻找最优染色体,替换当前存储的最优染色体,优胜劣汰。

需要注意的是这里替换当前最优染色体。因为我们将这个种群的个个个体的染色体重新变异、交叉过了,所以最优染色体也会变化。但是这一代的最优染色体不一定比上一次迭代的最优染色体好,所以需要判定是否将最优染色体这个位置给换掉。

因此迭代过程中的代码为

for t = 2:iter
    chrom = MutChrom(chrom, mut, N, N_chrom, chrom_range, t, iter); %变异
    chrom = AcrChrom(chrom, acr, N, N_chrom); %交叉
    fitness = CalFitness(chrom, N, N_chrom); %计算适应度
    chrom_best_temp = FindBest(chrom, fitness, N_chrom); %寻找最优染色体
    if chrom_best_temp(end)>chrom_best(end) %替换掉当前储存的最优
        chrom_best = chrom_best_temp;
    end
    %%替换掉最劣
    [chrom, fitness] = ReplaceWorse(chrom, chrom_best, fitness);
    fitness_best(t) = chrom_best(end); %将当前最优存入矩阵当中
    fitness_ave(t) = CalAveFitness(fitness); %将当前平均适应度存入矩阵当中
end

其中MutChrom函数用来对种群进行染色体变异操作。这里面的操作比较多,主要可以分为三步:

  1. 判断某节点是否变异;
  2. 判断变异是增加还是减少;
  3. 判断变异后的值是否越界。

下面代码表示为

function chrom_new = MutChrom(chrom, mut, N, N_chrom, chrom_range, t, iter)
for i = 1:N
    for j = 1:N_chrom
        mut_rand = rand; %是否变异
        if mut_rand <=mut
            mut_pm = rand; %增加还是减少
            mut_num = rand*(1-t/iter)^2;
            if mut_pm<=0.5
                chrom(i, j)= chrom(i, j)*(1-mut_num);
            else
                chrom(i, j)= chrom(i, j)*(1+mut_num);
            end
            chrom(i, j) = IfOut(chrom(i, j), chrom_range(:, j)); %检验是否越界
        end
    end
end
chrom_new = chrom;

越界函数IfOut函数我们看它是左越界还是右越界,如果是左越界,则让节点值等于区间下限;如果是右越界,则让节点值等于区间上限。

function c_new = IfOut(c, range)
if c<range(1) || c>range(2)
    if abs(c-range(1))<abs(c-range(2))
        c_new = range(1);
    else
        c_new = range(2);
    end
else
    c_new = c;
end

AcrChrom函数是染色体交叉函数。逻辑相较染色体变异来说比较简单,大致可以分为以下几点

  1. 判断该节点是否交叉;
  2. 随机寻找一个与其交叉的节点;
  3. 对两个节点进行交叉。
function chrom_new = AcrChrom(chrom, acr, N, N_chrom)
for i = 1:N
    acr_rand = rand;
    if acr_rand<acr %如果交叉
        acr_chrom = floor((N-1)*rand+1); %要交叉的染色体
        acr_node = floor((N_chrom-1)*rand+1); %要交叉的节点
        %交叉开始
        temp = chrom(i, acr_node);
        chrom(i, acr_node) = chrom(acr_chrom, acr_node); 
        chrom(acr_chrom, acr_node) = temp;
    end
end
chrom_new = chrom;

ReplaceWorse函数则是优胜劣汰这个过程,将种群中的最劣染色体替换掉。这里是直接用最优染色体替换,并且替换掉的是最后几个染色体,目的是加快收敛速度,但可能会陷入局部最优解。

function [chrom_new, fitness_new] = ReplaceWorse(chrom, chrom_best, fitness)

max_num = max(fitness);
min_num = min(fitness);
limit = (max_num-min_num)*0.2+min_num;

replace_corr = fitness<limit;

replace_num = sum(replace_corr);
chrom(replace_corr, :) = ones(replace_num, 1)*chrom_best(1:end-1);
fitness(replace_corr) = ones(replace_num, 1)*chrom_best(end);
chrom_new = chrom;
fitness_new = fitness;

end

输出遗传算法迭代图

在这里我们只输出一个标准图为迭代过程中种群的平均适应度与最优适应度

在之前我们已经得到了每一代的平均适应度fitness_ave与最优适应度fitness_best,所以可以直接输出图像

figure(1)
plot(1:iter, fitness_ave, 'r', 1:iter, fitness_best, 'b')
grid on
legend('平均适应度', '最优适应度')

之后我们还想要看得出的点在实际图像中哪个位置,所以我们可以增加一个用来作图的函数PlotModel

function y = PlotModel(chrom)
x = chrom(1);
y = chrom(2);
z = chrom(3);
figure(2)
scatter3(x, y, z, 'ko')
hold on
[X, Y] = meshgrid(-10:0.1:10);
Z =sin(X)+cos(Y)+0.1*X+0.1*Y;
mesh(X, Y, Z)
y=1;

遗传算法主程序

上面就是所有程序片段,因此把主程序的代码联立起来为

clc, clear, close all

%%基础参数
N = 100;  %种群内个体数目
N_chrom = 2; %染色体节点数
iter = 2000; %迭代次数
mut = 0.2;  %突变概率
acr = 0.2; %交叉概率
best = 1;

chrom_range = [-10 -10;10 10];%每个节点的值的区间
chrom = zeros(N, N_chrom);%存放染色体的矩阵
fitness = zeros(N, 1);%存放染色体的适应度
fitness_ave = zeros(1, iter);%存放每一代的平均适应度
fitness_best = zeros(1, iter);%存放每一代的最优适应度
chrom_best = zeros(1, N_chrom+1);%存放当前代的最优染色体与适应度

%%初始化
chrom = Initialize(N, N_chrom, chrom_range); %初始化染色体
fitness = CalFitness(chrom, N, N_chrom); %计算适应度
chrom_best = FindBest(chrom, fitness, N_chrom); %寻找最优染色体
fitness_best(1) = chrom_best(end); %将当前最优存入矩阵当中
fitness_ave(1) = CalAveFitness(fitness); %将当前平均适应度存入矩阵当中

for t = 2:iter
    chrom = MutChrom(chrom, mut, N, N_chrom, chrom_range, t, iter); %变异
    chrom = AcrChrom(chrom, acr, N, N_chrom); %交叉
    fitness = CalFitness(chrom, N, N_chrom); %计算适应度
    chrom_best_temp = FindBest(chrom, fitness, N_chrom); %寻找最优染色体
    if chrom_best_temp(end)>chrom_best(end) %替换掉当前储存的最优
        chrom_best = chrom_best_temp;
    end
    %%替换掉最劣
    [chrom, fitness] = ReplaceWorse(chrom, chrom_best, fitness);
    fitness_best(t) = chrom_best(end); %将当前最优存入矩阵当中
    fitness_ave(t) = CalAveFitness(fitness); %将当前平均适应度存入矩阵当中
end

%%作图
figure(1)
plot(1:iter, fitness_ave, 'r', 1:iter, fitness_best, 'b')
grid on
legend('平均适应度', '最优适应度')
e = PlotModel(chrom_best)

%%输出结果
disp(['最优染色体为', num2str(chrom_best(1:end-1))])
disp(['最优适应度为', num2str(chrom_best(end))])

输出结果

我们运行一下, 可以得到最大点为$(7.9541, 6.3834)$,最大值为3.4237。

可以做出最大值点在空间中的位置如图所示。证明我们的结论比较正确,起码没有落到周围的极大值的峰上。


下章预告

本章只是求解了一个二元函数,下一章我们将来解决一个实际模型,来看一下遗传算法怎么求解不同的模型。

喜欢的话麻烦点个喜欢哦~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容