我刚接触神经网络的那会它还没有像现在那么火热,当时我对它的效果很不屑,因为它在小样本的时候效果很差,但是到了研究生阶段再次遇到它的时候我对它有了新的认识,包括其内部的算法,有时间的话会另开一文再议,本文为16年我在数学建模中对神经网络算法的理解。
简介
神经网络与之前的模拟退火,遗传算法并称为三大智能算法.但其与后两者的功能完全不同.他所解决的不是优化问题,而是类似于拟合,插值的问题.
虽然其算法理论复杂,但是由于在MATLAB中的易于使用,所以也是处理数值分析问题的最后杀手锏.
使用
神经网络只是一个一类算法的总称,下面我们演示其中一个最常见,也是最通用的一种—BP神经网络.
例1:使用神经网络做x^2+y^2
的插值
确定自变量为p行q列矩阵,p指实验次数,q指自变量个数:
1 2 3
| x1=[1:3:20]'; x2=[1:3:20]'; x=[x1,x2]
|
确定因变量为p行r列矩阵,p指实验次数,r指因变量个数:
拷贝EzBp.m
文件到当前目录,调用函数EzBP(x,y)
:
若弹出神经网络的控制台,如:
表明成功.
测试结果.net表示学习完毕的神经网络,is方便我们对测试数据归一化,os方便我们将神经网络的返回的结果反归一化,得到我们的结果.
现在我们用(11,11)测试一下(正确结果应该是11^2+11^2=242).
1 2 3 4 5 6 7
| testnum=[11,11]'
inputNum=mapminmax('apply',testNum,is);
outputNum=net(inputNum);
res=mapminmax('reverse',outputNum,os)
|
结果(你的可能跟我不一样):
函数内部源码
整个函数不难,结合一下流程图自己就能看懂.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| function [net,ps,ts]=EzBP(P,T,x);
nntwarn off P=P'; T=T'; [P,ps]=mapminmax(P); [T,ts]=mapminmax(T); [pr,pc]=size(P); [tr,tc]=size(T);
inputNum=pr; outputNum=tr; hiddenNum=2*inputNum+1;
net=newff(minmax(P),[hiddenNum,outputNum],{'tansig','tansig'});
net.trainParam.epochs=1e5; net.trainParam.goal=1e-5; net.trainParam.lr=0.05; net.trainParam.show=10;
if nargin==3 net.trainParam.showwindow=false; w1num=inputNum*hiddenNum; w2num=outputNum*hiddenNum; w1=x(1:w1num); B1=x(w1num+1:w1num+hiddenNum); w2=x(w1num+hiddenNum+1:w1num+hiddenNum+w2num); B2=x(w1num+hiddenNum+w2num+1:w1num+hiddenNum+w2num+outputNum); 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}=reshape(B2,outputNum,1); end net=train(net,P,T); end
|
优化技巧
神经网络的效果的好坏由(1)所选用的训练数据(2)神经元个数,(3)激励算子所决定.下面介绍一些简单的优化方法.
归一化,取典型值
这是最简单的一种,归一化在EzBP函数里已经默认提供,说一下去典型值的意思:
举个例子,我们要拟合y=2*x
,给的训练数据是x=1:10,y=2*x
.那我把1.5
放进去,出来的值很可能就是3.0±0.1
的值,很靠谱吧?
而我把100
放进去,呵呵,那就不晓得是什么离谱的值了.现在知道什么叫典型的意思了吧.一般的,我们把每一变量的最大值和最低值放到网络中学习,而选用一部分中间的值作为验证.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function [train,test]=ChooseData(data) feature=[]; for eachCow=data [maxNum,maxPos]=max(eachCow); [minNum,minPos]=min(eachCow); feature=union(feature,maxPos); feature=union(feature,minPos); end dataNum=size(data,1); rand_=randperm(dataNum); needToChoose=floor(dataNum*0.9) train=union(feature,rand_(1:needToChoose)); test=rand_(needToChoose:end); train=data(train,:); test=data(test,:); end
|
交叉验证
交叉验证是在训练数据比较少的情况下,增加训练数据的好方法.这里也给出简单的操作函数CvBP(x,y[,n])
.n
为可选参数,n越大训练数据会变得更多.但也不意味着训练结果会更好(过分学习的情况).
demo.m
:
1 2 3 4 5 6 7 8 9 10 11 12
| x1=[1:3:20]'; x2=[1:3:20]'; x=[x1,x2];
y=x1.^2+x2.^2;
net=CvBP(x,y,10);
testNum=[11,11]';
outputNum=net(testNum)
|
CvBP.m
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| function perfectNet=CvBP(P,T,num) pdata=P'; tdata=T';
pTrain=P; tTrain=T;
n=10; mse_max=10e30; desiredInput=[]; desiredOutput=[];
if nargin==2 num=5; end indices = crossvalind('Kfold',length(pTrain),num); for i = 1:num perfp=[]; disp(['The result of ',num2str(i),'/',num2str(num)]) test = (indices == i); trainA = ~test; pCvTrain=pTrain(trainA,:); tCvTrain=tTrain(trainA,:); pCvTest=pTrain(test,:); tCvTest=tTrain(test,:); pCvTrain=pCvTrain'; tCvTrain=tCvTrain'; pCvTest= pCvTest'; tCvTest= tCvTest';
nett=feedforwardnet(n); nett=train(nett,pCvTrain,tCvTrain); testOut=nett(pCvTest); perf=perform(nett,testOut,tCvTest); if mse_max>perf perfectNet=nett; mse_max=perf; desiredInput=pCvTrain; desiredOutput=tCvTrain; end end end
|
结果:
与遗传算法结合
还记得以前介绍的遗传算法嘛?注意到EzBP的第三个参数了嘛?没错,这就是给遗传算法准备的.其实,在初始化神经网络时,每个神经元都有一个初始的值[-0.5,0.5],如果用遗传算法对这个进行优化,就会对结果造成影响.(实际效果不好).
demo.m
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| x1=[1:3:20]'; x2=[1:3:20]'; x=[x1,x2];
y=x1.^2+x2.^2;
[net,is,os]=GABP(x,y);
testNum=[11,11]';
inputNum=mapminmax('apply',testNum,is);
outputNum=net(inputNum);
res=mapminmax('reverse',outputNum,os)
|
GABP.m
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function [net,ps,ts,perf]=GABP(P,T) inputNum=size(P,2); outputNum=size(T,2); P_T=[P T]; [train,test]=ChooseData(P_T); trainX=train(:,1:inputNum); trainY=train(:,inputNum+1:end); testX=test(:,1:inputNum); testY=test(:,inputNum+1:end); hiddenNum=2*inputNum+1; w1num=inputNum*hiddenNum; w2num=outputNum*hiddenNum; N=w1num+hiddenNum+w2num+outputNum;
bound=repmat([-0.5 0.5],N,1); [best,x]=EzGA(bound,@fun,20,{trainX,trainY,testX,testY}); [net,ps,ts,perf]=EzBP(trainX,trainY,x,testX,testY); end
|
总结
神经网络算法是一套历史悠久也比较成熟的机器学习算法.是对付数值分析问题的最后杀手锏.我们一般比较常用的一种神经网络是BP神经网络.本文也以BP神经网络的使用及其优化进行了详细讲解,同时提供了可调用的函数原型.
但想要得到较好效果,还建议学习其他的一些神经网络,了解其各自优势.但由于这一类算法普遍稳定性较差,如果不是万不得已,或是效果超群,不建议使用.同时,若要使用此算法,请务必抽出一部分样本用来检验(严禁拿结果直接来学习,然后返回结果!!)
其算法优劣分析如下(笔者认为):
优点:
- 所适用的类型广泛.如果优化的好,几乎可以解决比赛中遇到的各种问题.e.g.插值,拟合,聚类.
- 对非线性数据的拟合效果优异.实在没看出数据有啥规律,神经网络至少算是一种解决方法.
缺点:
- 需要大量的样本数据
源程序: https://github.com/Anemone95/matlab-nnet