## Copyright (C) 2006 Michel D. Schmid ## ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} address@hidden = __trainlm (@var{net},@var{mInputN},@var{mOutput},@var{[]},@var{[]},@var{VV}) ## A neural feed-forward network will be trained with @code{__trainlm} ## ## @example ## [netOut,tr,out,E] = __trainlm(net,mInputN,mOutput,[],[],VV); ## @end example ## @noindent ## ## left side arguments: ## @example ## netOut: the trained network of the net structure @code{MLPnet} ## tr : ## out: ## E : Error ## @end example ## @noindent ## ## right side arguments: ## @example ## net : the untrained network, created with @code{newff} ## mInputN: normalized input matrix ## mOutput: output matrix ## [] : unused parameter ## [] : unused parameter ## VV : validize structure ## out: ## E : Error ## @end example ## @noindent ## ## ## @noindent ## are equivalent. ## @end deftypefn ## @seealso{newff,prestd,trastd} ## Author: Michel D. Schmid ## Comments: see in "A neural network toolbox for Octave User's Guide" [4] ## for variable naming... there have inputs or targets only one letter, ## e.g. for inputs is P written. To write a program, this is stupid, you can't ## search for 1 letter variable... that's why it is written here like Pp, or Tt ## instead only P or T. function [net] = __trainlm(net,Im,Pp,Tt,VV) ## check range of input arguments error(nargchk(5,5,nargin)) ## Initialize ##------------ ## get parameters for training epochs = net.trainParam.epochs; goal = net.trainParam.goal; maxFail = net.trainParam.max_fail; minGrad = net.trainParam.min_grad; mu = net.trainParam.mu; muInc = net.trainParam.mu_inc; muDec = net.trainParam.mu_dec; muMax = net.trainParam.mu_max; show = net.trainParam.show; time = net.trainParam.time; ## parameter checking checkParameter(epochs,goal,maxFail,minGrad,mu,\ muInc,muDec,muMax,show,time); ## Constants shortStr = "TRAINLM"; # TODO: shortStr is longer as TRAINLM !!!!!!!!!!! doValidation = !isempty(VV); stop = ""; #startTime = clock(); # TODO: maybe this row can be placed # some rows later ## the weights are used in column vector format xx = __getx(net); # x is the variable with respect to, but no # variables with only one letter!! ## define identity matrix muI = eye(length(xx)); startTime = clock(); # if the next some tests are OK, I can delete # startTime = clock(); 9 rows above.. ## calc performance of the actual net [perf,vE,Aa,Nn] = __calcperf(net,xx,Im,Tt); if (doValidation) ## calc performance if validation is used VV.net = net; # save the actual net in the validate # structure... if no train loop will show better validate # performance, this will be the returned net vperf = __calcperf(net,xx,VV.Im,VV.Tt); VV.perf = vperf; VV.numFail = 0; # one of the stop criterias endif nLayers = net.numLayers; for iEpochs = 0:epochs # longest loop & one of the stop criterias ve = vE{nLayers,1}; ## calc jacobian ## Jj is jacobian matrix [Jj] = __calcjacobian(net,Im,Nn,Aa,vE); ## rerange error vector for jacobi matrix ve = ve(:); Jjve = (Jj' * ve); # will be used to calculate the gradient normGradX = sqrt(Jjve'*Jjve); ## record training progress for later plotting ## if requested trainRec.perf(iEpochs+1) = perf; trainRec.mu(iEpochs+1) = mu; if (doValidation) trainRec.vperf(iEpochs+1) = VV.perf; endif ## stoping criteria [stop,currentTime] = stopifnecessary(stop,startTime,perf,goal,\ iEpochs,epochs,time,normGradX,minGrad,mu,muMax,\ doValidation,VV,maxFail); ## show train progress showtrainprogress(show,stop,iEpochs,epochs,time,currentTime, \ goal,perf,minGrad,normGradX,shortStr,net); ## show performance plot, if needed if !isnan(show) # if no performance plot is needed ## now make it possible to define after how much loops the ## performance plot should be updated if (mod(iEpochs,show)==0) plot(1:length(trainRec.perf),trainRec.perf); if (doValidation) hold on; plot(1:length(trainRec.vperf),trainRec.vperf,"--g"); endif endif endif # if !(strcmp(show,"NaN")) # legend("Training","Validation"); ## stop if one of the criterias is reached. if length(stop) if (doValidation) net = VV.net; endif break endif ## calculate DeltaX while (mu <= muMax) ## calculate change in x ## see [4], page 12-21 dx = -((Jj' * Jj) + (muI*mu)) \ Jjve; ## add changes in x to actual x values (xx) x1 = xx + dx; ## now add x1 to a new network to see if performance will be better net1 = __setx(net,x1); ## calc now new performance with the new net [perf1,vE1,Aa1,N1] = __calcperf(net1,x1,Im,Tt); if (perf1 < perf) ## this means, net performance with new weight values is better... ## so save the new values xx = x1; net = net1; Nn = N1; Aa = Aa1; vE = vE1; perf = perf1; mu = mu * muDec; if (mu < 1e-20) # 1e-20 is properly the hard coded parameter in MATLAB(TM) mu = 1e-20; endif break endif mu = mu * muInc; endwhile ## validate with DeltaX if (doValidation) vperf = __calcperf(net,xx,VV.Im,VV.Tt); if (vperf < VV.perf) VV.perf = vperf; VV.net = net; ## if actual validation performance is better, ## set numFail to zero again VV.numFail = 0; elseif (vperf > VV.perf) VV.numFail = VV.numFail + 1; endif endif endfor #for iEpochs = 0:epochs #======================================================= # # additional functions # #======================================================= function checkParameter(epochs,goal,maxFail,minGrad,mu,\ muInc, muDec, muMax, show, time) ## Parameter Checking ## epochs must be a positive integer if ( !isposint(epochs) ) error("Epochs is not a positive integer.") endif ## goal can be zero or a positive double if ( (goal<0) | !(isa(goal,"double")) ) error("Goal is not zero or a positive real value.") endif ## maxFail must be also a positive integer if ( !isposint(maxFail) ) # this will be used, to see if validation can # break the training error("maxFail is not a positive integer.") endif if (!isa(minGrad,"double")) | (!isreal(minGrad)) | (!isscalar(minGrad)) | \ (minGrad < 0) error("minGrad is not zero or a positive real value.") end ## mu must be a positive real value. this parameter is responsible ## for moving from stepest descent to quasi newton if ((!isa(mu,"double")) | (!isreal(mu)) | (any(size(mu)) != 1) | (mu <= 0)) error("mu is not a positive real value.") endif ## muDec defines the decrement factor if ((!isa(muDec,"double")) | (!isreal(muDec)) | (any(size(muDec)) != 1) | \ (muDec < 0) | (muDec > 1)) error("muDec is not a real value between 0 and 1.") endif ## muInc defines the increment factor if (~isa(muInc,"double")) | (!isreal(muInc)) | (any(size(muInc)) != 1) | \ (muInc < 1) error("muInc is not a real value greater than 1.") endif ## muMax is the upper boundary for the mu value if (!isa(muMax,"double")) | (!isreal(muMax)) | (any(size(muMax)) != 1) | \ (muMax <= 0) error("muMax is not a positive real value.") endif ## check for actual mu value if (mu > muMax) error("mu is greater than muMax.") end ## check if show is activated if (!isnan(show)) if (!isposint(show)) error(["Show is not " "NaN" " or a positive integer."]) endif endif ## check at last the time argument, must be zero or a positive real value if (!isa(time,"double")) | (!isreal(time)) | (any(size(time)) != 1) | \ (time < 0) error("Time is not zero or a positive real value.") end endfunction # parameter checking # # ----------------------------------------------------------------------------- # function showtrainprogress(show,stop,iEpochs,epochs,time,currentTime, \ goal,perf,minGrad,normGradX,shortStr,net) ## check number of inputs error(nargchk(12,12,nargin)); ## show progress if isfinite(show) & (!rem(iEpochs,show) | length(stop)) fprintf(shortStr); # outputs the training algorithm if isfinite(epochs) fprintf(", Epoch %g/%g",iEpochs, epochs); endif if isfinite(time) fprintf(", Time %4.1f%%",currentTime/time*100); # \todo: Time wird nicht ausgegeben endif if isfinite(goal) fprintf(", %s %g/%g",upper(net.performFcn),perf,goal); # outputs the performance function endif if isfinite(minGrad) fprintf(", Gradient %g/%g",normGradX,minGrad); endif fprintf("\n") if length(stop) fprintf("%s, %s\n\n",shortStr,stop); endif fflush(stdout); # writes output to stdout as soon as output messages are available endif endfunction # # ----------------------------------------------------------------------------- # function [stop,currentTime] = stopifnecessary(stop,startTime,perf,goal,\ iEpochs,epochs,time,normGradX,minGrad,mu,muMax,\ doValidation,VV,maxFail) ## check number of inputs error(nargchk(14,14,nargin)); currentTime = etime(clock(),startTime); if (perf <= goal) stop = "Performance goal met."; elseif (iEpochs == epochs) stop = "Maximum epoch reached, performance goal was not met."; elseif (currentTime > time) stop = "Maximum time elapsed, performance goal was not met."; elseif (normGradX < minGrad) stop = "Minimum gradient reached, performance goal was not met."; elseif (mu > muMax) stop = "Maximum MU reached, performance goal was not met."; elseif (doValidation) if (VV.numFail > maxFail) stop = "Validation stop."; endif endif endfunction # ===================================================================== # # END additional functions # # ===================================================================== endfunction