MATLAB神经网络43个案例——遗传算法优化BP神经网络

        在本书第二章案例中,用BP神经网络拟合非线性函数,在此基础上用遗传算法对神经网络进行进一步优化。主要优化对象为神经网络的权值阈值,以此达到更为精准的效果。

        本文主要对代码进行解析,书中的实例代码有一些差错,运行不了。本文进行了一些修正,供大家参考。

遗传算法主函数

算法大致流程: 

一、构建神经网络

%% 网络结构建立
%读取数据
load data input output

%节点个数
inputnum=2;
hiddennum=5;
outputnum=1;

%训练数据和预测数据
input_train=input(1:1900,:)';
input_test=input(1901:2000,:)';
output_train=output(1:1900)';
output_test=output(1901:2000)';

%选连样本输入输出数据归一化
[inputn,inputps]=mapminmax(input_train);
[outputn,outputps]=mapminmax(output_train);

%构建网络
net=newff(inputn,outputn,hiddennum);

二、遗传算法参数初始化

%% 遗传算法参数初始化
maxgen=20;                         %进化代数,即迭代次数
sizepop=10;                        %种群规模
pcross=[0.2];                      %交叉概率选择,0和1之间
pmutation=[0.1];                   %变异概率选择,0和1之间

%节点总数  w1+b1+w2+b2 
numsum=inputnum*hiddennum+hiddennum+hiddennum*outputnum+outputnum;%2*5+5+5*1+1=21
%w1=输入层与隐藏层之间的权值
%b1=隐藏层阈值
%w2=隐藏层与输出层之间的权值
%b2=输出层阈值

%用来进行染色体编码的参数
lenchrom=ones(1,numsum);  %染色体长度 1*21行向量(全1      
bound=[-3*ones(numsum,1) 3*ones(numsum,1)];  %数据范围[-3 3] 维度21*2

%种群信息初始化
individuals=struct('fitness',zeros(1,sizepop), 'chrom',[]); %将种群信息定义为一个结构体
avgfitness=[];                      %每一代种群的平均适应度
bestfitness=[];                     %每一代种群的最佳适应度
bestchrom=[];                       %适应度最好的染色体

三、计算个体适应度

        注意理解x中的数据的含义,x(21位)实际上携带w1(1~10位)B1(11~15位)w2(16~20位)B2(第21位)的信息。

        对染色体进行寻优的实际意义——找到最优的权值阈值组合

for i=1:sizepop % 1:10
    %个体初始化
    individuals.chrom(i,:)=Code(lenchrom,bound); %编码
    x=individuals.chrom(i,:);%x为编码后的染色体(携带权值阈值信息)
    %计算适应度
    individuals.fitness(i)=fun(x,inputnum,hiddennum,outputnum,net,inputn,outputn); %染色体的适应度
end

FitRecord=[];%拟合记录
%找最好的染色体(适应度最小)和它的下标
[bestfitness bestindex]=min(individuals.fitness);%最小适应度 及其下标
bestchrom=individuals.chrom(bestindex,:);  %最好的染色体 即适应度最小的

avgfitness=sum(individuals.fitness)/sizepop; %染色体的平均适应度
trace=[avgfitness bestfitness]; % 记录初代平均适应度和最优适应度

四、迭代寻优

        整个算法的核心,也是最难理解的地方。本章先对主函数进行分析,其中的选择、交叉、变异函数接下来逐步详细讲解

%% 迭代求解最佳初始阀值和权值
% 进化开始
for i=1:maxgen %迭代20代
    %选择
    individuals=Select(individuals,sizepop); 
    %交叉
    individuals.chrom=Cross(pcross,lenchrom,individuals.chrom,sizepop,bound);
    %变异    
    individuals.chrom=Mutation(pmutation,lenchrom,individuals.chrom,sizepop,i,maxgen,bound);
    
    % 计算适应度 
    for j=1:sizepop 
        x=individuals.chrom(j,:);
        individuals.fitness(j)=fun(x,inputnum,hiddennum,outputnum,net,inputn,outputn);   
    end
    
  %找到这一代最优和最差适应度的染色体及它们在种群中的位置
    [newbestfitness,newbestindex]=min(individuals.fitness);
    [worestfitness,worestindex]=max(individuals.fitness);
    
  %代替上一次进化中最好的染色体
    if bestfitness>newbestfitness %优胜
        bestfitness=newbestfitness;
        bestchrom=individuals.chrom(newbestindex,:);
    end
    %劣汰 淘汰适应度最差的染色体 用最优的取代
    individuals.chrom(worestindex,:)=bestchrom;
    individuals.fitness(worestindex)=bestfitness;
    
    avgfitness=sum(individuals.fitness)/sizepop;
    trace=[trace;avgfitness bestfitness]; %记录每一代进化的平均适应度和最优适应度 21代(加初代
    FitRecord=[FitRecord;individuals.fitness];%记录每一代拟合后的适应度 共20代
end

        遗传算法结果展示 :

figure(1)
hold on
[r c]=size(trace);
plot([1:r],trace(:,1),'r-');%平均适应度
plot([1:r],trace(:,2),'b--');%trace(:,2) 第二列为最优适应度
title(['适应度曲线' '(终止代数=' num2str(maxgen)],'fontsize',12);
xlabel('进化代数','fontsize',12);ylabel('适应度','fontsize',12);
legend('平均适应度','最佳适应度');

五、遗传算法优化BP神经网络

%% 把最优初始阀值权值赋予网络预测
x=bestchrom;%迭代后的最优染色体赋给x
w1=x(1:inputnum*hiddennum);%x(1:10)
B1=x(inputnum*hiddennum+1:inputnum*hiddennum+hiddennum);%x(11:15)
w2=x(inputnum*hiddennum+hiddennum+1:inputnum*hiddennum+hiddennum+hiddennum*outputnum);%x(16:20)
B2=x(inputnum*hiddennum+hiddennum+hiddennum*outputnum+1:inputnum*hiddennum+hiddennum+hiddennum*outputnum+outputnum);%x(21)

%% BP网络参数设置
net.iw{1,1}=reshape(w1,hiddennum,inputnum);
net.lw{2,1}=reshape(w2,outputnum,hiddennum);
net.b{1}=reshape(B1,hiddennum,1);
net.b{2}=B2;

net.trainParam.epochs=100;
net.trainParam.lr=0.1;
net.trainParam.goal=0.00001;

%% BP网络训练
[net,per2]=train(net,inputn,outputn);

%% BP网络预测
inputn_test=mapminmax('apply',input_test,inputps);%数据归一化
an=sim(net,inputn_test);%预测输出
test_simu=mapminmax('reverse',an,outputps);%反归一化后的预测输出
error=test_simu-output_test;%误差=预测输出-期望输出

        优化后的BP神经网络预测结果展示:

figure(2)
plot(test_simu,':og')
hold on
plot(output_test,'-*')
legend('预测输出','期望输出')
title('GA优化后的BP网络预测输出','fontsize',12)
ylabel('函数输出','fontsize',12);xlabel('样本','fontsize',12)

figure(3)
plot(error,'-*')
title('GABP网络预测误差','fontsize',12)
ylabel('误差','fontsize',12);xlabel('样本','fontsize',12)

        

初始化函数

一、编码函数

        编码函数对神经网络的权值和阈值信息进行编码,代码如下:

function ret=Code(lenchrom,bound)
%本函数将变量编码成染色体,用于随机初始化一个种群
% lenchrom   input : 染色体长度
% bound      input : 变量的取值范围
% ret        output: 染色体的编码值
flag=0;
while flag==0
    pick=rand(1,length(lenchrom));%随机数 1*21
    ret=bound(:,1)'+(bound(:,2)-bound(:,1))'.*pick; %线性插值,编码结果以实数向量存入ret中   
    flag=test(lenchrom,bound,ret); %检验染色体的可行性 flag=1可行、结束循环 flag=0再循环
end

二、测试函数

        测试编码后的染色体是否可行,flag为1时可行,flag为0时不可行:

function flag=test(lenchrom,bound,code)
% lenchrom   input : 染色体长度
% bound      input : 变量的取值范围
% code       output: 染色体的编码值
x=code;
flag=1;
if (x(1)<0)&&(x(2)<0)&&(x(3)<0)&&(x(1)>bound(1,2))&&(x(2)>bound(2,2))&&(x(3)>bound(3,2))
    flag=0;
end     

适应度函数

        在遗传算法中,适应度(fitness)的具体含义取决于问题的性质。一般而言,适应度越大越好是常见的情况,因为遗传算法的目标通常是优化问题,即找到问题的最优解或接近最优解的解

例如,如果遗传算法用于解决最大化问题(如最大化某个函数的值),那么个体的适应度值越大,说明该个体的性能越好。相反,如果遗传算法用于解决最小化问题(如最小化成本或误差),那么个体的适应度值越小,说明该个体的性能越好。

总体而言,适应度的选择应该与问题的优化目标相一致,以便遗传算法能够有效地搜索解空间并找到问题的良好解。下面对适应度函数代码进行分析:

function error = fun(x,inputnum,hiddennum,outputnum,net,inputn,outputn)
%该函数用来计算适应度值
%x          input     个体(染色体:包含权值阈值信息)
%inputnum   input     输入层节点数
%outputnum  input     隐含层节点数
%net        input     网络
%inputn     input     训练输入数据
%outputn    input     训练输出数据
%error      output    个体适应度值

%提取
w1=x(1:inputnum*hiddennum);%输入层与隐含层的权值 x(1:10)
B1=x(inputnum*hiddennum+1:inputnum*hiddennum+hiddennum);%隐含层的阈值 x(11:15)
w2=x(inputnum*hiddennum+hiddennum+1:inputnum*hiddennum+hiddennum+hiddennum*outputnum);%隐含层与输出层的权值 x(16:20)
B2=x(inputnum*hiddennum+hiddennum+hiddennum*outputnum+1:inputnum*hiddennum+hiddennum+hiddennum*outputnum+outputnum);
%输出层阈值 x(21:21)

%网络进化参数
net.trainParam.epochs=20;%迭代次数
net.trainParam.lr=0.1;%学习率
net.trainParam.goal=0.00001;%目标函数 最小误差函数
net.trainParam.show=100;%显示训练迭代过程
net.trainParam.showWindow=0;%显示训练窗口
 
%网络权值/阈值赋值
net.iw{1,1}=reshape(w1,hiddennum,inputnum);%iw{1,1} i-h间的权值 5*2
net.lw{2,1}=reshape(w2,outputnum,hiddennum);%iw{2,1} h-o间的权值 1*5
net.b{1}=reshape(B1,hiddennum,1);%隐含层阈值 B1 5*1
net.b{2}=B2;%输出层阈值

%网络训练
net=train(net,inputn,outputn);

an=sim(net,inputn);%an为预测输出

error=sum(abs(an-outputn));%适应度(越小越好)

        由最后一行代码可见,遗传算法中的适应度为:神经网络的预测输出与期望输出差值的绝对值之和。

选择函数

        选择函数涉及到概率论中的轮盘赌问题。轮盘赌是什么呢?听起来很复杂,其实很简单。相信大家都参加过超市的优惠活动,让你转转盘的指针,转盘上有各种奖项。一等奖的扇形区域很小,其余奖项的扇形区域面积逐渐增大。所以当你转动指针,大概率会停在低等奖的区域(因为它所占面积相较于其他奖更大)。

        而遗传算法的选择函数,要选择适应度好的个体进入下一轮操作(交叉、变异)。因此采用这种转轮盘的方式随机选择染色体,适应度越好,那么该染色体被选中的概率也就越大

function ret=select(individuals,sizepop)
% 本函数对每一代种群中的染色体进行选择,以进行后面的交叉和变异
% individuals input  : 种群信息
% sizepop     input  : 种群规模
% ret         output : 经过选择后的种群

%根据个体适应度值进行排序
fitness1=10./individuals.fitness;%由于适应度越小越好 对每个适应度求倒数 k为系数=10
sumfitness=sum(fitness1);%求和
p=fitness1./sumfitness;%每个个体的选择概率(概率之和为1)

%轮盘赌法选择新个体
index=[]; %j的值 选中的个体下标
for i=1:sizepop   %转sizepop(10次轮盘
    pick=rand;%返回一个在区间 (0,1) 内均匀分布的随机数   
  
    for j=1:sizepop
        pick=pick-p(j); %这一步就是转轮盘
        if pick<=0 %对应指针停下       
            index=[index j]; %寻找指针停下的区间,此次转轮盘选中了第j个染色体           
            break; 
            %注意:在转sizepop次轮盘的过程中,有可能会重复选择某些染色体
        end
    end

end

%更新种群信息(选中的染色体及其适应度)
individuals.chrom=individuals.chrom(index,:);
individuals.fitness=individuals.fitness(index);
ret=individuals;

        算法中,pick=pick-p(j) 这句的理解很关键。画个图大家就明白为啥这一步操作就是转轮盘了。把圆盘区域拉成一条线段,区域面积映射在线段上。pick是随机数,该随机数作累减操作,当pick=0时,它就落在了线段中某个区域里(相当于指针停下),这就完成了随机选择染色体。从图直观可见概率为0.4的染色体被选中的概率最大。

        该算法中实际p的可视化图:

交叉函数

function ret=Cross(pcross,lenchrom,chrom,sizepop,bound)
%本函数完成交叉操作
% pcorss                input  : 交叉概率
% lenchrom              input  : 染色体的长度
% chrom                 input  : 染色体群
% sizepop               input  : 种群规模
% ret                   output : 交叉后的染色体
 for i=1:sizepop % 1:10
     %每一轮for循环中,可能会进行一次交叉操作,染色体是随机选择的,交叉位置也是随机选择的,
     %但该轮for循环中是否进行交叉操作则由交叉概率决定(continue控制)
     
     % 随机选择两个染色体进行交叉
     pick=rand(1,2); 
     index=ceil(pick.*sizepop);%随机选取2个染色体来进行交叉

     % 交叉概率决定是否进行交叉
     pick=rand;
     if pick>pcross
         continue;
     end

     flag=0;
     while flag==0
         % 随机选择交叉位
         pick=rand;
%          while pick==0
%              pick=rand;
%          end
         %随机选择进行交叉的位置,即选择第几个变量进行交叉,注意:两个染色体交叉的位置相同
         pos=ceil(pick.*sum(lenchrom));%要进行交叉的染色体元(21位)的位置
%          temp=chrom(index(1),pos);    %两元素调换位置
%          chrom(index(1),pos)=chrom(index(2),pos);
%          chrom(index(2),pos)=temp;
         pick=rand; %交叉开始
         v1=chrom(index(1),pos);%(随机选取的第一个染色体,对应元的位置)
         v2=chrom(index(2),pos);%(随机选取的第二个染色体,对应元的位置)
         %实数交叉法
         chrom(index(1),pos)=pick*v2+(1-pick)*v1;
         chrom(index(2),pos)=pick*v1+(1-pick)*v2; %交叉结束
         flag1=test(lenchrom,bound,chrom(index(1),:));  %检验染色体1的可行性
         flag2=test(lenchrom,bound,chrom(index(2),:));  %检验染色体2的可行性
         
         if   flag1*flag2==0
              flag=0;
         else flag=1;
         end    %如果两个染色体不是都可行,则重新交叉
     end     
 end
ret=chrom;

 

变异函数

        与交叉函数对应,基本思路是一致的。

function ret=Mutation(pmutation,lenchrom,chrom,sizepop,num,maxgen,bound)
% 本函数完成变异操作
% pmutation             input  : 变异概率
% lenchrom              input  : 染色体长度
% chrom                 input  : 染色体群
% sizepop               input  : 种群规模
% num                   input  : 当前迭代次数
% maxgen                input  :最大迭代次数
% bound                 input  : 每个个体的上界和下界
% ret                   output : 变异后的染色体

for i=1:sizepop   %每一轮for循环中,可能会进行一次变异操作,染色体是随机选择的,变异位置也是随机选择的,
    %但该轮for循环中是否进行变异操作则由变异概率决定(continue控制)
    % 随机选择一个染色体进行变异
    pick=rand;
    index=ceil(pick*sizepop);%随机选择1个染色体进行变异

    % 变异概率决定该轮循环是否进行变异
    pick=rand;
    if pick>pmutation
        continue;
    end

    flag=0;
    while flag==0
        pick=rand;
        pos=ceil(pick*sum(lenchrom));  %随机选择了染色体变异的位置,即选择了第pos个变量进行变异
        %变异开始    
        pick=rand; 
        fg=(rand*(1-num/maxgen))^2; %num为遗传算法当前迭代次数 maxgen为总迭代次数
        if pick>0.5
            chrom(index,pos)=chrom(index,pos)+(chrom(index,pos)-bound(pos,2))*fg;
        else
            chrom(index,pos)=chrom(index,pos)+(bound(pos,1)-chrom(index,pos))*fg;
        end
        %变异结束
        flag=test(lenchrom,bound,chrom(index,:));     %检验变异的染色体的可行性
    end
end
ret=chrom;

ENDING

        以主函数算法流程为基础,仔细分析每一个子函数作用,通过调试代码来加深理解,才能对整个算法流程有全面的认知。代码的实验数据来自《MATLAB神经网络43个案例分析》。本文是个人学习记录,以便回顾复习。若有错误之处,请大家指正。

MATLAB 神经网络43案例分析》目录 第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻优 第5章 基于BP_Adaboost的强分类器设计——公司财务预警建模 第6章 PID神经元网络解耦控制算法——多变量系统控制 第7章 RBF网络的回归--非线性函数回归的实现 第8章 GRNN网络的预测----基于广义回归神经网络的货运量预测 第9章 离散Hopfield神经网络的联想记忆——数字识别 第10章 离散Hopfield神经网络的分类——高校科研能力评价 第11章 连续Hopfield神经网络优化——旅行商问题优化计算 第12章 初始SVM分类与回归 第13章 LIBSVM参数实例详解 第14章 基于SVM的数据分类预测——意大利葡萄酒种类识别 第15章 SVM的参数优化——如何更好的提升分类器的性能 第16章 基于SVM的回归预测分析——上证指数开盘指数预测. 第17章 基于SVM的信息粒化时序回归预测——上证指数开盘指数变化趋势和变化空间预测 第18章 基于SVM的图像分割-真彩色图像分割 第19章 基于SVM的手写字体识别 第20章 LIBSVM-FarutoUltimate工具箱及GUI版本介绍与使用 第21章 自组织竞争网络在模式分类中的应用—患者癌症发病预测 第22章 SOM神经网络的数据分类--柴油机故障诊断 第23章 Elman神经网络的数据预测----电力负荷预测模型研究 第24章 概率神经网络的分类预测--基于PNN的变压器故障诊断 第25章 基于MIV的神经网络变量筛选----基于BP神经网络的变量筛选 第26章 LVQ神经网络的分类——乳腺肿瘤诊断 第27章 LVQ神经网络的预测——人脸朝向识别 第28章 决策树分类器的应用研究——乳腺癌诊断 第29章 极限学习机在回归拟合及分类问题中的应用研究——对比实验 第30章 基于随机森林思想的组合分类器设计——乳腺癌诊断 第31章 思维进化算法优化BP神经网络——非线性函数拟合 第32章 小波神经网络的时间序列预测——短时交通流量预测 第33章 模糊神经网络的预测算法——嘉陵江水质评价 第34章 广义神经网络的聚类算法——网络入侵聚类 第35章 粒子群优化算法的寻优算法——非线性函数极值寻优 第36章 遗传算法优化计算——建模自变量降维 第37章 基于灰色神经网络的预测算法研究——订单需求预测 第38章 基于Kohonen网络的聚类算法——网络入侵聚类 第39章 神经网络GUI的实现——基于GUI的神经网络拟合、模式识别、聚类 第40章 动态神经网络时间序列预测研究——基于MATLAB的NARX实现 第41章 定制神经网络的实现——神经网络的个性化建模与仿真 第42章 并行运算与神经网络——基于CPU/GPU的并行神经网络运算 第43神经网络高效编程技巧——基于MATLAB R2012b新版本特性的探讨
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值