Bito辅助学习遗传算法每个操作的代码实现

前言

        是用Bito这类ChatGPT的人工智能帮助自己学习真的很牛,比起搁网上查来查去要方便很多,简直就是自学必备神技。就想着通过这样的方式去帮助自己理解算法代码和修改代码。搁网上抄的代码,即使很理解流程,也会显得很难修改,至少我是这样。通过Bito的帮助,随时随地就可以问和修改,某种意义上也很锻炼人。

        写这篇博客,主要注重对于遗传算法的一个理解,以及Bito的一个使用辅助理解代码,里面很多的概念的东西和为什么要这样是需要不断揣摩的,在使用Bito分析调试代码的一个过程中,会提供给你更多的一些东西,往下看吧。这里仅提供自己使用学习中的经验。只是经验分享。

        原本打算直接用Bito求解试试,但是生成的代码还是有很多问题,一时半会也不会调,就以我自己用的一套遗传算法,给出模板,用Bito分析学习算法中具体的实施过程。

一些算法理解上的经验分享

  • 优化算法的理解:基于线性规划来理解的,优化算法优化的是你的决策变量也就是算法里的种群,优化算法中的适应度函数就是目标函数。(1)
  • 优化算法的使用:
  1. 最关键就是理解个体(2)适应度函数,以优化一维函数最大值为例来理解(3),个体就是你的变量X,适应度函数就是Y值。
  2. 遗传算法:个体=基因编码。粒子群算法:个体=粒子的x,y坐标值。= :等价于
  3. 优化一个变量,使用遗传算法,优化两个变量,使用粒子群算法。
  • 遗传算法中的变异是为了跳出局部最优解,粒子群算法中的群体学习因子也是。

(1)没加约束条件哈,还不咋特别懂。有空研究。

(2)这里理解成个体,所有的个体加起来是一个种群。

(3)建议就以简单的优化个函数的最大值为例入门,很有启发。

示例:

Fun(x) = x \cdot \sin(x) \cdot \cos(2x) - 2x \cdot \sin(3x) + 3x \cdot \sin(4x)

图像如下:

直接尝试求解:

输入:请编写一个基本的遗传算法程序,求解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分析代码:

使用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. 操作的顺序:首先:选择操作是选出下一代种群的父代个体(1),所以计算适应度的操作要放在选择操作前接着:优秀的基因->交叉,变异->50个子代的基因(即子代个体),最后:更新种群,就是把交叉变异的返回值赋给Populations。
  2. 交叉操作是:使用单点交叉的话,父代中两条优秀基因,再看交叉率是否交叉,以交叉点分前成后两端,再两条基因互换。这里采用的是二进制编码。
  3. 变异操作:每个个体的一条基因上某个位置上的0变成1或1变成0,当然也要考虑到概率。

(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

种群的初始化

。。。。。。。。。。。等待后续哈

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是神经网络与遗传算法结合的 MATLAB 代码示例: ```matlab % 定义神经网络类 classdef NeuralNetwork < handle properties weights1 weights2 end methods % 初始化权重 function obj = NeuralNetwork(input_size, hidden_size, output_size) obj.weights1 = randn(input_size, hidden_size); obj.weights2 = randn(hidden_size, output_size); end % 前向传播计算输出 function output = forward(obj, inputs) hidden = inputs * obj.weights1; hidden = tanh(hidden); output = hidden * obj.weights2; end end end % 定义遗传算法类 classdef GeneticAlgorithm < handle properties population_size gene_length mutation_rate fitness_function elitism population fitness end methods % 初始化种群 function obj = GeneticAlgorithm(population_size, gene_length, mutation_rate, fitness_function, elitism) obj.population_size = population_size; obj.gene_length = gene_length; obj.mutation_rate = mutation_rate; obj.fitness_function = fitness_function; obj.elitism = elitism; obj.population = randi([0, 1], population_size, gene_length); obj.fitness = zeros(population_size, 1); end % 选择操作 function parents = selection(obj) % 使用轮盘赌选择算法 fitness_sum = sum(obj.fitness); selection_prob = obj.fitness / fitness_sum; selected_indices = randsample(obj.population_size, 2, true, selection_prob); parents = obj.population(selected_indices, :); end % 交叉操作 function offspring = crossover(obj, parents) % 使用单点交叉算法 crossover_point = randi(obj.gene_length - 1); offspring = [parents(1, 1:crossover_point), parents(2, crossover_point+1:end)]; end % 变异操作 function mutated_offspring = mutation(obj, offspring) % 使用随机单点变异算法 for i = 1:length(offspring) if rand() < obj.mutation_rate offspring(i) = ~offspring(i); end end mutated_offspring = offspring; end % 进化操作 function evolve(obj) % 计算适应度 for i = 1:obj.population_size obj.fitness(i) = obj.fitness_function(obj.population(i, :)); end % 计算精英个体 if obj.elitism [~, elite_index] = max(obj.fitness); elite = obj.population(elite_index, :); end % 创建新种群 new_population = zeros(obj.population_size, obj.gene_length); for i = 1:obj.population_size parents = obj.selection(); offspring = obj.crossover(parents); mutated_offspring = obj.mutation(offspring); new_population(i, :) = mutated_offspring; end % 保留精英个体 if obj.elitism new_population(1, :) = elite; end % 更新种群 obj.population = new_population; end end end % 定义适应度函数 function fitness = fitness_function(gene) % 将二进制基因转换为实数 x = bi2de(gene) / (2^length(gene) - 1); % 计算目标函数值 y = sin(10 * pi * x) / x + 5; % 返回适应度 fitness = y; end % 初始化遗传算法和神经网络 population_size = 20; gene_length = 20; mutation_rate = 0.01; elitism = true; ga = GeneticAlgorithm(population_size, gene_length, mutation_rate, @fitness_function, elitism); nn = NeuralNetwork(1, 3, 1); % 训练神经网络 max_generation = 100; for i = 1:max_generation % 获取当前种群中的最优个体 [~, best_index] = max(ga.fitness); best_gene = ga.population(best_index, :); % 将二进制基因转换为实数 x = bi2de(best_gene) / (2^length(best_gene) - 1); % 使用最优个体来训练神经网络 nn.weights1 = x * nn.weights1; nn.weights2 = x * nn.weights2; % 进化种群 ga.evolve(); end % 测试神经网络 input = 0.5; output = nn.forward(input); disp(output); ``` 在这个示例中,我们使用遗传算法来优化神经网络的权重。我们首先定义了一个包含一个隐藏层的神经网络,以及一个遗传算法类。遗传算法类包含了种群初始化、选择、交叉、变异和进化等操作,并使用适应度函数来评估个体的适应度。然后,我们定义了一个简单的目标函数,用于测试遗传算法和神经网络的性能。最后,我们初始化遗传算法和神经网络,并使用遗传算法来优化神经网络的权重。在每一代进化中,我们使用当前种群中的最优个体来训练神经网络。完成进化后,我们使用训练好的神经网络来测试输入的输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值