GA-BP遗传神经网络预测

本人毕业设计是

基于遗传算法优化的城市公交系统车站客流量预测

在学习过程中

不断积累经验并优化改进模型

学习完后

认为遗传神经网络预测模型

可以在大多专业领域应用实现预测效果

通俗地总结分享一下

自己最满意的流程和方法供小白参考

有误请指正和讨论

目录

导入特征数据和目标数据

使用mapminmax函数对数据归一化处理

提取数据特征数量

设置遗传算法参数

设置两层隐藏层的神经元个数

计算整个网络层的节点数之和

 设置种群长度和初始参数范围

流程框架

流程代码

建模方法特点

适应度计算函数

选择操作函数

交叉操作函数

变异操作函数

神经网络算法模块的设置

使用mapminmax函数对得到的最优数据反归一化

绘制实验误差曲线图

实际值与预测值曲线图

设置实验结果提示窗口

运行结果图


 

导入特征数据和目标数据

自行分析整理出

影响目标数据的因素作为特征数据

每一个因素为一个特征种类

每一个特征需要多个样本数据来反映

☆☆☆☆☆

以下为5组特征数据

1组目标数据

1组预测特征数据

clear;
clc;
%导入数据
data1=[1.87,2.07,2.25,2.4,2.5,2.64,2.7,2.9,3.1,3.25,3.4,3.72,3.95];%2009年~2021年的机动车数量/(亿辆)
data2=[41.19,42.05,45.33,47.49,50.96,52.88,56.18,60.86,65.12,67.34,69.33,70.44,70.94];%2009年~2021年的公共汽电车数量/(万辆)
data3=[25460,32237,35884,38243,41738,45052,48905,52789,56786,60590,65730,70643,75770];%2009年~2021年的公共汽电车线路数/(条)
data4=[28.92,63.37,67.29,71.46,74.89,81.78,89.43,98.12,106.9,119.9,133.6,148.21,159.38];%2009年~2021年的公共汽电车线路网里程/(万公里)
data5=[186.63,317.86,331.73,346.82,348.96,346.69,352.33,358.32,355.2,346.1,354.13,302.79,335.27];%2009年~2021年的公共汽电车运营里程/(亿公里)
data6=[742.91,670.12,715.79,749.8,771.17,781.88,765.4,745.23,722.87,697,691.76,442.36,489.16];%2009年~2021年的公共汽电车客流量/(亿人次)
newdata=[4.17;67.45;79955;171.31;330];%每个值分别为2022年的:机动车数量、公共汽电车数量、线路数、线路网里程、运营里程
P=[data1;data2;data3;data4;data5];   %特征数据
T=data6;                             %目标数据

使用mapminmax函数对数据归一化处理

具体用法及原理

学习MATLAB官方帮助文档mapminmax

后面还要对预测特征数据归一化处理

此时,使用mapminmax的'apply'命令

调用特征数据归一化得到的结构体PS1

完成归一化处理

[P_regular,PS1]=mapminmax(P,-1,1);
[T_regular,PS2]=mapminmax(T,-1,1);

提取数据特征数量

input_num=size(P,1);   %输入特征个数
output_num=size(T,1);  %输出特征个数

设置遗传算法参数

iter_num=300;        %进化迭代次数
group_num=100;       %种群规模
cross_pro=0.625;     %交叉概率
mutation_pro=0.05;   %变异概率,相对来说比较小

设置两层隐藏层的神经元个数

hidden_num1=8;   %第一层隐藏层神经元个数
hidden_num2=6;   %第二层隐藏层神经元个数(比第一层小)

计算整个网络层的节点数之和

总结点数=输入特征数×第一层隐藏层节点数+第一层隐藏层节点数+第一层隐藏层节点数×第二层隐藏层节点数+第二层隐藏层节点数+...+第n层隐藏层节点数+第n层隐藏层节点数×第n+1层隐藏层节点数+第n+1层隐藏层节点数+第n+1层隐藏层节点数×输出特征数+输出特征数。

☆☆☆☆☆

以下是2层隐藏层的网络层节点数之和

num_all=input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2+...
+hidden_num2+hidden_num2*output_num+output_num; %节点总数

 设置种群长度和初始参数范围

lenchrom=ones(1,num_all);                       %种群总长度
limit=[-1*ones(num_all,1) 1*ones(num_all,1)];   %初始参数给定范围

遗传算法部分

主要思想就是

优化神经网络的权重和阈值(偏置)初始选择

其初始选择

对于神经网络的预测效果好坏

是有较大影响的

流程框架

GA-BP遗传神经网络预测_第1张图片

流程代码

%% 实验开始
TIME=[];
num_iter_all=5;   %实验次数
input_data=P_regular;
output_data=T_regular;
test=[];
EMS_all=[];
titlestr=['实验运行中,请稍等......'];
mm=waitbar(0,titlestr);%实验循环进度条
set(mm,'Position',[245 376.8750 270 56.2500])
for NN=1:num_iter_all
    t1=clock;%每次实验开始的时间
    str=['实验运行第',num2str(NN),'次中,请稍等......'];
    waitbar(NN/num_iter_all,mm,str); %实验进度条
 %% 基因编译
    for i=1:group_num
        initial=rand(1,length(lenchrom));  %产生0-1的随机数
        initial_chrom(i,:)=limit(:,1)'+(limit(:,2)-limit(:,1))'.*initial; %变成染色体的形式,一行为一条染色体
        fitness_value=fitness(initial_chrom(i,:),input_num,hidden_num1,hidden_num2,output_num,input_data,output_data);%计算初始适应度
        fitness_group(i)=fitness_value;
    end
    [bestfitness,bestindex]=min(fitness_group);
    bestchrom=initial_chrom(bestindex,:);  %最好的染色体
    avgfitness=sum(fitness_group)/group_num; %染色体的平均适应度
    trace=[avgfitness bestfitness]; % 记录每一代进化中最好的适应度和平均适应度
 %% 迭代过程
    input_chrom=initial_chrom;
    titlestr=['GA迭代中,请稍等......'];
    kk=waitbar(0,titlestr);%遗传迭代循环进度条
    set(kk,'Position',[925 376.8750 270 56.2500])
    for num=1:iter_num
        str=['GA迭代第',num2str(num),'次中,请稍等......',num2str(num/iter_num*100),'%'];
        waitbar(num/iter_num,kk,str); %GA迭代进度条
        % 选择
        [new_chrom,new_fitness]=select(input_chrom,fitness_group,group_num);   %把表现好的挑出来,还是和种群数量一样
        % 交叉
        new_chrom=Cross(cross_pro,lenchrom,new_chrom,group_num,limit);
        % 变异
        new_chrom=Mutation(mutation_pro,lenchrom,new_chrom,group_num,num,iter_num,limit);
        % 计算每次迭代后的适应度
        for j=1:group_num
            sgroup=new_chrom(j,:); %个体 
new_fitness(j)=fitness(sgroup,input_num,hidden_num1,hidden_num2,output_num,input_data,output_data);
        end
        %找到最小和最大适应度的染色体及它们在种群中的位置
        [newbestfitness,newbestindex]=min(new_fitness);
        [worestfitness,worestindex]=max(new_fitness);
        % 代替上一次进化中最好的染色体
        if  newbestfitness

建模方法特点

关闭了遗传算法的适应度迭代图

和神经网络训练误差图

但保存在了MATLAB打开的文件夹里

☆☆☆☆☆

模型中对整个实验循环

(神经网络每次预测的值是不唯一的,选取实验误差最小的模型数据作为最终预测值)

遗传算法迭代循环神经网络训练循环

设置了进度条显示

(循环次数设置的比较大,可以查看实验进程)

☆☆☆☆☆

在遗传算法优化模块中:

适应度计算函数

function fitness_value=fitness(input_chrom,input_num,hidden_num1,hidden_num2,output_num,input_data,output_data)
%该函数用来计算适应度值
%input_chrom     输入种群
%input_num        输入层的节点数,即数据特征数量
%output_num      隐含层节点数,隐藏层神经元的个数
%input_data        训练输入数据
%output_data     训练输出数据
%fitness_value    个体适应度值
w1=input_chrom(1:input_num*hidden_num1);   %输入层和第一层隐藏层之间的权重参数
B1=input_chrom(input_num*hidden_num1+1:input_num*hidden_num1+hidden_num1); %第一层隐藏层神经元的偏置
w2=input_chrom(input_num*hidden_num1+hidden_num1+1:input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2);  %第一层隐藏层和第二层隐藏层之间的权重参数
B2=input_chrom(input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2+1:input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2+hidden_num2); %第二层隐藏层神经元的偏置
w3=input_chrom(input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2+hidden_num2+1:input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2+hidden_num2+hidden_num2*output_num);%第二层隐藏层和输出层之间的权重参数
B3=input_chrom(input_num*hidden_num1+hidden_num1+hidden_num1*hidden_num2+hidden_num2+hidden_num2*output_num+1:end);%输出层神经元的偏置
%网络权值赋值
W1=reshape(w1,hidden_num1,input_num);
W2=reshape(w2,hidden_num2,hidden_num1);
W3=reshape(w3,output_num,hidden_num2);
B1=reshape(B1,hidden_num1,1);
B2=reshape(B2,hidden_num2,1);
B3=reshape(B3,output_num,1);
[~,n]=size(input_data);
A1=tansig(W1*input_data+repmat(B1,1,n));   %需与主函数中激活函数相同
A2=tansig(W2*A1+repmat(B2,1,n));           %需与主函数中激活函数相同
A3=purelin(W3*A2+repmat(B3,1,n));          %需与主函数中激活函数相同
error=sumsqr(output_data-A3);
fitness_value=error; %误差即为适应度
end

利用神经网络的权重和阈值

计算输入数据的预测值

从而计算适应度值=预测值与输出值差的平方和

其中:

输入层与第一层隐藏层之间的权重值w1=索引输入染色体值initial_chrom的范围(1:输入染色体的第1个到输入特征数目×第一层隐藏层节点数);

第一层隐藏层神经元的偏置B1=索引输入染色体值initial_chrom的范围(w1索引范围的末值+1:w1索引范围的末值+第一层隐藏层节点数);

第一层隐藏层和第二层隐藏层之间的权重值w2=索引输入染色体值initial_chrom的范围(B1索引范围的末值+1:B1索引范围的末值+第一层隐藏层节点数×第二层隐藏层节点数);

第二层隐藏层神经元的偏置B2=索引输入染色体值initial_chrom的范围(w2索引范围的末值+1:w2索引范围的末值+第二层隐藏层节点数);

第二层隐藏层和输出层之间的权重值w3=索引输入染色体值initial_chrom的范围(B2索引范围的末值+1:B2索引范围的末值+第二层隐藏层节点数);

输出层神经元的偏置B3=索引输入染色体值initial_chrom的范围(w3索引范围的末值+1:end);

☆☆☆☆☆

以上权重和偏置的各索引

范围必须设置正确

否则后面的网络权值reshape重组时

与网络结构不匹配会报错

(后面神经网络中初始权重和偏置的索引范围同理)

 

选择操作函数

function [new_chrom,new_fitness]=select(input_chrom,fitness_group,group_num)
% 用轮盘赌在原来的函数里选择
% fitness_group    种群信息
% group_num     种群规模
% newgroup        选择后的新种群
%求适应度值倒数  
fitness1=10./fitness_group; %individuals.fitness为个体适应度值
%个体选择概率
sumfitness=sum(fitness1);
sumf=fitness1./sumfitness;
%采用轮盘赌法选择新个体
index=[];
for i=1:1000   %group_num为种群数
    pick=rand;
    while pick==0   
        pick=rand;       
    end
   for j=1:group_num   
        pick=pick-sumf(j);       
        if pick<0       
            index=[index j];           
            break; 
        end
   end
   if length(index) == group_num
        break;
  end
end

%新种群
new_chrom=input_chrom(index,:);   
new_fitness=fitness_group(index);
end

交叉操作函数

function new_chrom=Cross(cross_pro,lenchrom,input_chrom,group_num,limit)
%随机选择两个染色体位置交叉
% cross_pro                   交叉概率
% lenchrom                   染色体的长度,即所有参数的数量
% input_chrom              染色体群,经过选择遗传下来的表现比较好的
% group_num                种群规模
% new_chrom                交叉后的染色体
 for i=1:group_num  %每一轮for循环中,可能会进行一次交叉操作,染色体是随机选择的,交叉位置也是随机选择的,
                  %但该轮for循环中是否进行交叉操作则由交叉概率决定(continue控制)        
    pick=rand(1,2);   % 随机选择两个染色体进行交叉
     while prod(pick)==0       %连乘
         pick=rand(1,2);
     end
    index=ceil(pick.*group_num);  % 交叉概率决定是否进行交叉
    pick=rand;
     while pick==0
         pick=rand;
     end
     if pick>cross_pro
         continue;
     end
         % 随机选择交叉位
         pick=rand;
         while pick==0
             pick=rand;
         end
         flag=0;
       while flag==0
         pos=ceil(pick*length(lenchrom)); %随机选择进行交叉的位置,即选择第几个变量进行交叉,注意:两个染色体交叉的位置相同
         pick=rand; %交叉开始
         v1=input_chrom(index(1),pos);
         v2=input_chrom(index(2),pos);
         input_chrom(index(1),pos)=pick*v2+(1-pick)*v1;
         input_chrom(index(2),pos)=pick*v1+(1-pick)*v2; %交叉结束
       
       %判断交叉后的两条染色体可不可行  
        limit1=mean(limit);
        f11=isempty(find(input_chrom(index(1),:)>limit1(2), 1));
        f12=isempty(find(input_chrom(index(1),:)limit1(2), 1));
        f22=isempty(find(input_chrom(index(2),:)

变异操作函数

function new_chrom=Mutation(mutation_pro,lenchrom,input_chrom,group_num,num,iter_num,limit)
% 本函数完成变异操作
% mutation_pro           变异概率
% lenchrom                 染色体长度
% input_chrom   输入交叉过后的染色体
% group_num              种群规模
% iter_num             最大迭代次数
% limit                  每个个体的上限和下限
% num                   当前迭代次数
% new_chrom           变异后的染色体
for i=1:group_num   %每一轮for循环中,可能会进行一次变异操作,染色体是随机选择的,变异位置也是随机选择的,
    %但该轮for循环中是否进行变异操作则由变异概率决定(continue控制)
    % 随机选择一个染色体进行变异
    pick=rand;
    while pick==0
        pick=rand;
    end
    index=ceil(pick*group_num);
    % 变异概率决定该轮循环是否进行变异
    pick=rand;
    if pick>mutation_pro
        continue;
    end
    flag=0;
    while flag==0
        % 变异位置
        pick=rand;
        while pick==0     
            pick=rand;
        end
        pos=ceil(pick*sum(lenchrom));  %随机选择了染色体变异的位置,即选择了第pos个变量进行变异
        pick=rand; %变异开始    
        fg=(pick*(1-num/iter_num))^2;
        if pick>0.5
            input_chrom(index,pos)=input_chrom(index,pos)+(limit(pos,2)-input_chrom(index,pos))*fg;
        else
            input_chrom(index,pos)=input_chrom(index,pos)-(input_chrom(index,pos)-limit(pos,1))*fg;
        end   %变异结束
        
        limit1=mean(limit);
        f1=isempty(find(input_chrom(index,:)>limit1(2)));
        f2=isempty(find(input_chrom(index,:)

神经网络算法模块的设置

经过多次测试

第一层和第二层隐藏层的激活函数用‘tansig

输出层的激活函数用‘purelin

训练算法函数用‘trainlm

预测效果是最好的

☆☆☆☆☆

网络的权重和阈值索引的是

遗传算法优化模块迭代进化后的最优值bestchrom

各权重和偏置索引最优值bestchrom的范围

同遗传算法中的适应度计算中的设置相同

☆☆☆☆☆

由于,神经网络的训练易陷入最小值

训练次数设置很大也不容易找到更优预测

所以,隐藏层数设置为2层、减少训练次数

同样能够完成优化

且隐藏层增加1层并不会对所耗时间有太大影响

整体模型预测

效果更好,消耗时间更短

☆☆☆☆☆

整个实验中

对遗传算法的每一代

适应度值、神经网络训练值、预测值、误差值

都进行了存储

并选择了最优值

使用mapminmax函数对得到的最优数据反归一化

使用mapminmax函数的返回命令'reverse'

调用归一化时得到的结构体PS2

完成最优数据反归一化

⭐⭐⭐⭐⭐

绘制实验误差曲线图

实际值与预测值曲线图

设置实验结果提示窗口

%% 提取2022年的预测数据
Ab=a(1,14);
disp('2022年的预测客流量为:')
disp(Ab)
%% 绘制曲线图
%绘制GA-BP误差曲线
figure('visible','on');
plot(EMS_all,'LineWidth',2)
xlabel('实验优化次数')
ylabel('误差')
titlestr=('GA-BP实验误差曲线');
title(titlestr)
%绘制目标数据与预测数据曲线图
figure
x1=2009:1:2021;%实际值年份
x2=2009:1:2022;%预测值年份
axy3=plot(x1,T,'b-','linewidth',1);
hold on
axy4=plot(x2,test(n,:),'r--.','linewidth',1);
xlabel('年份')
ylabel('客流量/亿人次')
titlestr=['GABP遗传神经网络算法预测——我国城市公交系统车站客流量','  误差:',num2str(m),'%','     2022年预测客流量为:',num2str(Ab),'亿人次'];
title(titlestr)
set(gca,'xtick',2009:1:2022);
legend([axy3(1),axy4(1)],'真实数据','预测数据')
axis([2009 2022 400 800])
grid on
%% 绘制结果提示窗口
titlestr1=['实验',num2str(num_iter_all),'次','所耗时间:',num2str(time),' 秒','     最小误差为: 第  ',num2str(n(1)),'  次的  ',num2str(m(1)),'%'];
titlestr2=['2022年预测客流量为 :    ',num2str(Ab),'  亿人次'];
disp(titlestr1)
disp(titlestr2)
h=msgbox({titlestr1;titlestr2},'GA-BP模型预测结果');
% 文本居中
th = findall(0, 'Tag','MessageBox' );
boxPosition = get(h,'position');
textPosition = get(th, 'position');
set(th, 'position', [boxPosition(3).*0.5 textPosition(2) textPosition(3)]);
set(th, 'HorizontalAlignment', 'center');

运行结果图

GA-BP遗传神经网络预测_第2张图片

 GA-BP遗传神经网络预测_第3张图片

GA-BP遗传神经网络预测_第4张图片

GA-BP遗传神经网络预测_第5张图片

GA-BP遗传神经网络预测_第6张图片

GA-BP遗传神经网络预测_第7张图片

 

(本文为原创,禁止抄袭,转发请注明来源)

 

你可能感兴趣的:(matlab,神经网络,算法,性能优化)