赞
踩
是用Bito这类ChatGPT的人工智能帮助自己学习真的很牛,比起搁网上查来查去要方便很多,简直就是自学必备神技。就想着通过这样的方式去帮助自己理解算法代码和修改代码。搁网上抄的代码,即使很理解流程,也会显得很难修改,至少我是这样。通过Bito的帮助,随时随地就可以问和修改,某种意义上也很锻炼人。
写这篇博客,主要注重对于遗传算法的一个理解,以及Bito的一个使用辅助理解代码,里面很多的概念的东西和为什么要这样是需要不断揣摩的,在使用Bito分析调试代码的一个过程中,会提供给你更多的一些东西,往下看吧。这里仅提供自己使用学习中的经验。只是经验分享。
原本打算直接用Bito求解试试,但是生成的代码还是有很多问题,一时半会也不会调,就以我自己用的一套遗传算法,给出模板,用Bito分析学习算法中具体的实施过程。
(1)没加约束条件哈,还不咋特别懂。有空研究。
(2)这里理解成个体,所有的个体加起来是一个种群。
(3)建议就以简单的优化个函数的最大值为例入门,很有启发。
图像如下:
输入:请编写一个基本的遗传算法程序,求解Fun = @(x) x.*sin(x).*cos(2*x)-2*x.*sin(3*x)+3*x.*sin(4*x)的最大值,变量范围(0,50),使matlab
去跑了一下,是有报错的,接下来就一个一个该就好了,在这个过程中去学习遗传算法更加具体的部分。其实这样的修改大概率还是不行的,有时还是原封不动啥都不该,毕竟不是那个4.0的
直接输入:代码中出先错误请修改
错误使用 randsample
W 必须包含非负值且至少有一个正值。
出错 调试>gaSelection (第 46 行)
selectedIndices = randsample(1:length(fitness), length(fitness), true,selectionProb);结果还是不行,没必要写了哈。
使用Bito辅助理解的话,可以试着这样输入
输入:分析以上代码,给出更加详细的代码分析和注释
输出结果如下:
这段代码实现了一个遗传算法来优化函数 Fun 的最大值。
1. Fun
函数定义了适应度函数,即需要优化的目标函数。
2. 设置了遗传算法的参数,包括种群大小、变量个数、迭代次数和变量的上下界。
3. 初始化种群,使用随机数生成种群中的个体,个体的取值范围在变量的上下界之间。
4. 迭代优化过程,进行指定次数的迭代。
5. 在每次迭代中,计算种群中每个个体的适应度值。
6. 选择操作使用轮盘赌选择法根据个体的适应度值选择下一代种群。
7. 交叉操作使用单点交叉将选择的个体进行交叉产生新的个体。
8. 变异操作使用均匀变异对交叉后的个体进行变异。
9. 更新种群,将变异后的个体作为下一代种群。
10. 计算最优解和最优值,找到适应度值最大的个体及其对应的变量取值。
11. 输出结果,显示最优解和最优值。
输入:结合代码,详细分析每个过程
输出结果如下:
Bito直接求解多半还是不行,也不咋会去调,他给的代码一时半会还真看不懂,拿来分析代码,辅助理解算法还凑合。
输入:详细说明遗传算法中的参数
遗传算法中的参数有以下几个:
1. 种群大小(Population Size):表示每一代中的个体数量。种群大小决定了搜索空间的覆盖程度和算法的收敛速度。一般来说,种群大小越大,搜索空间越广,但计算成本也会增加。
2. 变量个数(Number of Variables):表示优化问题中变量的数量。每个个体代表一个解,解的维度等于变量的个数。(一维函数就是一个变量,二维函数就是两个变量)
3. 迭代次数(Number of Generations):表示遗传算法的迭代次数,即进行遗传操作的次数。迭代次数决定了算法搜索空间的探索程度。
4. 变量范围(Variable Range):表示变量的取值范围。在遗传算法中,每个变量都有一个上界和下界,用于限制个体的取值范围。
5. 选择操作(Selection Operation):用于选择下一代个体的操作。常见的选择操作包括轮盘赌选择、锦标赛选择等,根据个体的适应度值选择优秀个体。
6. 交叉操作(Crossover Operation):用于生成下一代个体的操作。交叉操作通过将两个个体的某些部分进行交叉,产生新的个体。
7. 变异操作(Mutation Operation):用于引入新的基因变异,增加种群的多样性。变异操作通过随机改变个体的某些基因值,引入新的解。
这些参数在遗传算法中起着重要的作用,可以通过调整它们来改变算法的性能和搜索结果。根据具体的问题和需求,可以通过实验和经验来选择合适的参数值。
补充:基因的位数或长度,染色体个数就是变量个数,交叉率和变异率
最需花时间理解的是选择操作,交叉操作,变异操作。
(以种群数为50个,维度为1即每个个体一条基因为例)
(1)爸妈们,也就是上一代中优秀的个体才能当爸妈,才能把基因遗传下去,这里也可以理解成选出上一代中优秀的个体, 优良 = 适应度高
其中个人觉得最主要的问题是:选择操作选出几个个体当父代,个人认为这里是必须要理解的。很多问题就放在后面的代码分析中。这里就体现了Bito的优势,自己琢磨时,会有很多的疑问,直接问就好了。
给出我的代码模板,以此分析整个代码算法的具体实现:
- clear
- clc
- close all
-
- % 定义目标函数
- %Fun = @(t) t + 10*sin(5*t) + 7*cos(4*t);
- Fun = @(x) x.*sin(x).*cos(2*x)-2*x.*sin(3*x)+3*x.*sin(4*x);
- min_X = 0;
- max_X = 50;
-
- % 绘制图形
- figure(1)
- fplot(Fun,[min_X max_X]);
-
- % 调用遗传算法函数求解函数最大值
- num_Pops = 100; % 种群数量
- length_Genes = 20; % 基因长度(二进制位数)
- num_Iters = 200; % 迭代次数
- rate_Muta = 0.05; % 变异率
- rate_Cros = 1; % 交叉率
- num_Tours = 10; % 锦标赛大小
-
- [best_X, best_F] = GA(Fun, num_Pops, length_Genes, num_Iters, rate_Muta,rate_Cros,num_Tours, min_X, max_X);
- % - Fun :适应度函数
- % - num_Pops :种群数量
- % - length_Genes :基因长度
- % - num_Iters :迭代次数
- % - rate_Muta :变异率
- % - rate_Cros :交叉率
- % - num_Tours :锦标赛选择中参与竞争的个体数量
- % - min_X :X的最小值
- % - max_X :X的最大值
- % - Pops :种群的染色体编码
- % - maxvalue_all_Fitness_Iters :每次迭代的最大适应度值
- % - iter :迭代次数
- % - value_all_Fitness :所有个体的适应度值
- % - maxvalue_all_Fitness :最大适应度值
- % - Parents_Pops :父代个体的染色体编码
- % - Offsprings_Pops :子代个体的染色体编码
- % - competitors_Index :竞争者的索引
- % - competitors_value_all_Fitness :竞争者的适应度值
- % - maxIndex :适应度值最大的竞争者的索引
- % - crossover_Position :交叉点位置
- % - Offspring_Chromosome :子代染色体
- % - num_Offsprings_Pops :子代个体数量
- % - Real_Chromosome_Pops :转换为实数值的染色体编码
-
- % 遗传算法函数
- function [best_X, best_F] = GA(Fun, num_Pops, length_Genes, num_Iters, rate_Muta,rate_Cros, num_Tours, min_X, max_X)
- % 初始化一个种群,个数,基因长度
- Pops = Initialize_all_Pops(num_Pops, length_Genes);
- disp(['初始化种群',num2str(num_Pops),'个完毕']);
- disp(['基因长度为',num2str(length_Genes),',染色体中只有一条基因']);
- disp(['共迭代',num2str(num_Iters),'次']);
-
- % 创建一个数组来保存每次迭代的最大适应度
- maxvalue_all_Fitness_Iters = zeros(1,num_Iters);
-
- % 开始迭代
- for iter = 1:num_Iters
- % disp(' ');
- % disp(['开始第',num2str(iter),'代']);
-
- rng('shuffle'); %初始化随机数发生器
- % 计算所有个体适应度
- value_all_Fitness = Calculate_value_all_Fitness(Fun, Pops, min_X, max_X);
- maxvalue_all_Fitness = max(value_all_Fitness);
- %disp(['第',num2str(iter),'代中最大适应度是',num2str(maxvalue_all_Fitness)]);
-
- % 记录最大适应度
- maxvalue_all_Fitness_Iters(iter) = maxvalue_all_Fitness;
-
- % 选择父代一,是指通过竞标赛选择出一半的优良个体作为父代一
- % 父代二在一般的优良个体中随机挑选
- % 父代一站Pops的一半
- Parents_Pops = Select_Parents_Pops(Pops, value_all_Fitness, num_Tours);
-
-
- % 交叉产生子代
- % 子代只站种群个数Pops的一半
- Offsprings_Pops = Crossover(Parents_Pops, length_Genes ,rate_Cros);
-
- % 交叉产生的子代基因变异
- % 基因位取反
- Offsprings_Pops = Mutate(Offsprings_Pops, rate_Muta);
-
- % 合并父代和子代
- % 一半竞争的优良父代和由优良父代产生的一半子代=Pops
- Pops = [Parents_Pops; Offsprings_Pops];
- %disp(['子代',num2str(num_Pops),'个产生完毕']);
-
- figure(2);
- % 绘制适应度变化曲线
- Plot_max_Iters_Fitness(maxvalue_all_Fitness_Iters, iter);
- end
-
- % 计算最优解
- % 此时的Pops优化到最好了
- value_all_Fitness = Calculate_value_all_Fitness(Fun, Pops, min_X, max_X);
- [ ~ , best_F_Index ] = max(value_all_Fitness);
- best_X = BinaryToReal(Pops(best_F_Index,:),min_X,max_X);
- best_F = max(value_all_Fitness);
- disp('最优解为:');
- disp(best_X);
- disp('最大值为:');
- disp(best_F);
- end
-
- % 初始化种群
- function Pops = Initialize_all_Pops(num_Pops, length_Genes)
- Pops = randi([0, 1], num_Pops, length_Genes);
-
- end
-
- % 计算所有个体的适应度
- function value_all_Fitness = Calculate_value_all_Fitness(Fun, Pops, min_X, max_X)
- % 将二进制编码转换为实数值,X
- Real_Chromosome_Pops = BinaryToReal(Pops, min_X, max_X);
- % 计算适应度,Y
- value_all_Fitness = Fun(Real_Chromosome_Pops);
- % 绘制成图
-
- figure(1);
- x=min_X:0.01:max_X;
- plot(x,Fun(x),'c-',Real_Chromosome_Pops,value_all_Fitness,'ro');
- pause(0.01);
- end
-
- % 选择父代
- function Parents_Pops = Select_Parents_Pops(Pops, value_all_Fitness, num_Tours)
- num_Pops = size(Pops, 1);
- length_Genes = size(Pops,2);
- num_Parents = num_Pops / 2;
- % 创建出一个矩阵来储存父代的优良个体
- Parents_Pops = zeros(num_Parents, length_Genes);
-
- for i = 1:num_Parents
- % 生成一个从整数 1 到 num_Pops 中随机选择的num_Tours个唯一整数(没有重复元素)的随机排列。
- % - num_Pops是种群的数量,num_Tours是每次锦标赛中参与竞争的个体数量。
- competitors_Index = randperm(num_Pops, num_Tours);
- % 根据竞争者索引从size_all_Fitness中获取适应度值。
- competitors_value_all_Fitness = value_all_Fitness(competitors_Index);
- [~, maxIndex] = max(competitors_value_all_Fitness);
- Parents_Pops(i,:) = Pops(competitors_Index(maxIndex),:);
- end
- end
-
- % 交叉操作:和修改圈一样
- % 一对父代基因交叉产生一个子代
- function Offsprings_Pops = Crossover(Parents_Pops, length_Genes, rate_Cros)
- num_Parents1 = size(Parents_Pops, 1);
- Offsprings_Pops = zeros(num_Parents1, length_Genes);
-
- for i = 1:num_Parents1
- Parent1 = Parents_Pops(i,:);
- % randi([1, num_Parents1]):从25个优良个体中随机选另一个父代二
- Parent2 = Parents_Pops(randi([1, num_Parents1]),:);
-
- % 判断是否进行交叉操作
- % 此代码的目的是确保每次运行时都使用不同的随机数序列,以增加随机性。
- % 这在某些需要随机性的应用程序中非常有用,例如模拟、优化算法等。
- %rng('shuffle'); %初始化随机数发生器
- if rand() < rate_Cros
- % 随机选择交叉点
- crossover_Position = randi([1, length_Genes-1]);
- % 单点交叉操作
- Offsprings_Pops(i,:) = SinglePoint_Crossover(Parent1, Parent2, crossover_Position);
- else
- Offsprings_Pops(i,:) = Parent1; % 不进行交叉,直接复制父代一
- end
- end
-
- end
-
- % 单点交叉操作
- function Offspring_Chromosome = SinglePoint_Crossover(Parent1, Parent2, crossover_Position)
- % 创建一个子代染色体
- % 父代一和父代二成一对共num_Pops/2对
- % 父代一和父代二的基因矩阵进行拼接
- Offspring_Chromosome = [Parent1(1:crossover_Position), Parent2(crossover_Position+1:end)];
- end
-
- % 变异操作
- function Offsprings_Pops = Mutate(Offsprings_Pops, rate_Muta)
- num_Offsprings_Pops = size(Offsprings_Pops, 1);
- length_Genes = size(Offsprings_Pops, 2);
-
- % 对每个子代个体的每个基因开始遍历
- % 遍历每一个基因位
- for i = 1:num_Offsprings_Pops
- for j = 1:length_Genes
- % 根据变异率随机翻转(取反)基因位
- %rng('shuffle'); %初始化随机数发生器
- if rand() < rate_Muta
- Offsprings_Pops(i, j) = ~Offsprings_Pops(i, j);
- end
- end
- end
- end
-
- % 绘制适应度变化曲线
- function Plot_max_Iters_Fitness(max_Iters_value_all_Fitness, iter)
- plot(1:iter, max_Iters_value_all_Fitness(1:iter), 'b');
- title('最大适应度变化曲线');
- xlabel('迭代次数');
- ylabel('最大适应度值');
- drawnow;
- end
-
- % 将二进制编码转换为实数值
- function Real_Chromosome_Pops = BinaryToReal(Binary_Chromosome_Pops, min_X, max_X)
- length_Genes = size(Binary_Chromosome_Pops, 2);
- num_Pops = size(Binary_Chromosome_Pops, 1);
- Real_Chromosome_Pops = zeros(num_Pops, 1);
- % 变量种群中每一个个体
- for i = 1:num_Pops
- % 遍历个体中每一个基因
- % 二进制转十进制的通过累加权值实现
- for j = 1:length_Genes
- Real_Chromosome_Pops(i,1) = Real_Chromosome_Pops(i,1) + Binary_Chromosome_Pops(i,j) * (2^(length_Genes-j));
- end
- % 把十进制数映射到可行域中
- Real_Chromosome_Pops(i,1) = min_X + (max_X - min_X) * Real_Chromosome_Pops(i,1) / (2^length_Genes - 1);
- end
- end
。。。。。。。。。。。等待后续哈
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。