接我上一条的笔记,今天我加了遗传算法进行优化BP神经网络,其基本思想就是用个体代表网络的初始权值和阈值、个体值初始化的BP神经网络的预测误差作为该个体的适应度值,通过选择、交叉、变异操作寻找最优个体,即最优的BP神经网络初始权值。
了解过BP神经网络的朋友都知道,BP神经网络初始神经元之间的权值和阈值一般随机选择,因此容易陷入局部最小值,通过引入遗传算法就可以很好找到全局最小值,废话不多说,直接上。(代码仅供参考,小白起步)
题目:拟合非线性函数:y=x1x1+x2x2(平方和)
设置网络:输入层2个神经元,隐含层5个神经元,输出层1个神经元
先来理解一下种群、个体、染色体、基因都分别是什么?种群由全部个体组成,其包含了所有个体的信息,由此我们可以联想到可以定义一个结构体来表示种群,来囊括所有个体的信息;个体,在遗传算法中我们可以理解成解决一个问题的方案,一个问题有不同种解决方案(也就是不同的个体),模拟自然界中选择、淘汰个体以得到对解决问题最有用的个体;而一个个体中,有染色体,染色体又由基因组成,所以针对本案例我们不难理解,染色体其实由4部分构成:输入层到隐含层之间的连接权值(一个二维矩阵)、隐含层到输出层之间的连接权值(一个二维矩阵)、隐含层神经元阈值(一维矩阵)、输出层神经元阈值(一维矩阵),而基因就是神经元与神经元之间的连接权值(一个数值)。
具体会发生什么、怎么发生,我们通过下面代码一步一步来:
%% 该代码为基于遗传算法神经网络的预测代码
% 清空环境变量
clc
clear
%
%%网络结构建立
%读取数据
load data input output
%节点个数
inputnum=2;
hiddennum=5;
outputnum=1;
%训练数据和预测数据
input_train=input(1:1900,:)';%取1到1900行的数据来训练
input_test=input(1901:2000,:)';%取1901到2000行的数据来测试
output_train=output(1:1900);
output_test=output(1901:2000);
%选连样本输入输出数据归一化
[inputn,inputps]=mapminmax(input_train);%归一化到[-1,1]之间,inputps用来作下一次同样的归一化
[outputn,outputps]=mapminmax(output_train);
%构建网络
net=newff(inputn,outputn,hiddennum);%单隐含层,5个隐含层神经元
%% 遗传算法参数初始化
maxgen=20; %进化代数,即迭代次数
sizepop=10; %种群规模
pcross=0.2; %交叉概率选择,0和1之间
pmutation=0.1; %变异概率选择,0和1之间
%节点总数:输入隐含层权值、隐含阈值、隐含输出层权值、输出阈值(4个基因组成一条染色体)
numsum=inputnum*hiddennum+hiddennum+hiddennum*outputnum+outputnum;%21个,10,5,5,1
lenchrom=ones(1,numsum);%个体长度,暂时先理解为染色体长度,是1行numsum列的矩阵
bound=[-3*ones(numsum,1) 3*ones(numsum,1)]; %是numsum行2列的串联矩阵,第1列是-3,第2列是3
%------------------------------------------------------种群初始化--------------------------------------------------------
individuals=struct('fitness',zeros(1,sizepop), 'chrom',[]); %将种群信息定义为一个结构体:10个个体的适应度值,10条染色体编码信息
avgfitness=[]; %每一代种群的平均适应度,一维
bestfitness=[]; %每一代种群的最佳适应度
bestchrom=[]; %适应度最好的染色体,储存基因信息
%初始化种群
for i=1:sizepop
%随机产生一个种群
individuals.chrom(i,:)=Code(lenchrom,bound); %编码(binary(二进制)和grey的编码结果为一个实数,float的编码结果为一个实数向量)
x=individuals.chrom(i,:);
%计算适应度
individuals.fitness(i)=fun(x,inputnum,hiddennum,outputnum,net,inputn,outputn); %染色体的适应度
end
通过上面代码我们就知道,结构体individuals就是种群,里面包含了两个矩阵,一个用来放全部个体的适应度值,一个用来存放染色体的信息。好,函数从Code开始,也就是给染色体进行编码,让每个基因都赋值初始值。
function ret=Code(lenchrom,bound)
%本函数将变量编码,用于随机初始化一个种群
% lenchrom input : 染色体长度(其实就是1行21列的矩阵)
% bound input : 变量的取值范围
% ret output: 染色体的编码值
flag=0;
while flag==0
pick=rand(1,length(lenchrom));%length得到一个矩阵里较大的行数或者列数,lenchrom是1行numsum列矩阵故返回numsum,即pick是1行numsum列的随机数矩阵
%bound(:,