/************************************************************************* Like MLPCreate0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecreate0(int nin, int nout, int ensemblesize, ref mlpensemble ensemble) { mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron(); mlpbase.mlpcreate0(nin, nout, ref net); mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble); }
/************************************************************************* Calculation of all types of errors -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeallerrorsx(mlpensemble ensemble, double[,] densexy, sparse.sparsematrix sparsexy, int datasetsize, int datasettype, int[] idx, int subset0, int subset1, int subsettype, alglib.smp.shared_pool buf, mlpbase.modelerrors rep) { int i = 0; int j = 0; int nin = 0; int nout = 0; bool iscls = new bool(); int srcidx = 0; hpccores.mlpbuffers pbuf = null; mlpbase.modelerrors rep0 = new mlpbase.modelerrors(); mlpbase.modelerrors rep1 = new mlpbase.modelerrors(); int i_ = 0; int i1_ = 0; // // Get network information // nin = mlpbase.mlpgetinputscount(ensemble.network); nout = mlpbase.mlpgetoutputscount(ensemble.network); iscls = mlpbase.mlpissoftmax(ensemble.network); // // Retrieve buffer, prepare, process data, recycle buffer // alglib.smp.ae_shared_pool_retrieve(buf, ref pbuf); if( iscls ) { bdss.dserrallocate(nout, ref pbuf.tmp0); } else { bdss.dserrallocate(-nout, ref pbuf.tmp0); } apserv.rvectorsetlengthatleast(ref pbuf.x, nin); apserv.rvectorsetlengthatleast(ref pbuf.y, nout); apserv.rvectorsetlengthatleast(ref pbuf.desiredy, nout); for(i=subset0; i<=subset1-1; i++) { srcidx = -1; if( subsettype==0 ) { srcidx = i; } if( subsettype==1 ) { srcidx = idx[i]; } alglib.ap.assert(srcidx>=0, "MLPEAllErrorsX: internal error"); if( datasettype==0 ) { for(i_=0; i_<=nin-1;i_++) { pbuf.x[i_] = densexy[srcidx,i_]; } } if( datasettype==1 ) { sparse.sparsegetrow(sparsexy, srcidx, ref pbuf.x); } mlpeprocess(ensemble, pbuf.x, ref pbuf.y); if( mlpbase.mlpissoftmax(ensemble.network) ) { if( datasettype==0 ) { pbuf.desiredy[0] = densexy[srcidx,nin]; } if( datasettype==1 ) { pbuf.desiredy[0] = sparse.sparseget(sparsexy, srcidx, nin); } } else { if( datasettype==0 ) { i1_ = (nin) - (0); for(i_=0; i_<=nout-1;i_++) { pbuf.desiredy[i_] = densexy[srcidx,i_+i1_]; } } if( datasettype==1 ) { for(j=0; j<=nout-1; j++) { pbuf.desiredy[j] = sparse.sparseget(sparsexy, srcidx, nin+j); } } } bdss.dserraccumulate(ref pbuf.tmp0, pbuf.y, pbuf.desiredy); } bdss.dserrfinish(ref pbuf.tmp0); rep.relclserror = pbuf.tmp0[0]; rep.avgce = pbuf.tmp0[1]/Math.Log(2); rep.rmserror = pbuf.tmp0[2]; rep.avgerror = pbuf.tmp0[3]; rep.avgrelerror = pbuf.tmp0[4]; alglib.smp.ae_shared_pool_recycle(buf, ref pbuf); }
/************************************************************************* Calculation of all types of errors -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ private static void mlpeallerrors(mlpensemble ensemble, double[,] xy, int npoints, ref double relcls, ref double avgce, ref double rms, ref double avg, ref double avgrel) { int i = 0; double[] buf = new double[0]; double[] workx = new double[0]; double[] y = new double[0]; double[] dy = new double[0]; int nin = 0; int nout = 0; int i_ = 0; int i1_ = 0; relcls = 0; avgce = 0; rms = 0; avg = 0; avgrel = 0; nin = mlpbase.mlpgetinputscount(ensemble.network); nout = mlpbase.mlpgetoutputscount(ensemble.network); workx = new double[nin]; y = new double[nout]; if( mlpbase.mlpissoftmax(ensemble.network) ) { dy = new double[1]; bdss.dserrallocate(nout, ref buf); } else { dy = new double[nout]; bdss.dserrallocate(-nout, ref buf); } for(i=0; i<=npoints-1; i++) { for(i_=0; i_<=nin-1;i_++) { workx[i_] = xy[i,i_]; } mlpeprocess(ensemble, workx, ref y); if( mlpbase.mlpissoftmax(ensemble.network) ) { dy[0] = xy[i,nin]; } else { i1_ = (nin) - (0); for(i_=0; i_<=nout-1;i_++) { dy[i_] = xy[i,i_+i1_]; } } bdss.dserraccumulate(ref buf, y, dy); } bdss.dserrfinish(ref buf); relcls = buf[0]; avgce = buf[1]; rms = buf[2]; avg = buf[3]; avgrel = buf[4]; }
/************************************************************************* Serializer: serialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ public static void mlpeserialize(alglib.serializer s, mlpensemble ensemble) { s.serialize_int(scodes.getmlpeserializationcode()); s.serialize_int(mlpefirstversion); s.serialize_int(ensemble.ensemblesize); apserv.serializerealarray(s, ensemble.weights, -1); apserv.serializerealarray(s, ensemble.columnmeans, -1); apserv.serializerealarray(s, ensemble.columnsigmas, -1); mlpbase.mlpserialize(s, ensemble.network); }
/************************************************************************* Training neural networks ensemble using early stopping. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 6, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpetraines(mlpensemble ensemble, double[,] xy, int npoints, double decay, int restarts, ref int info, mlptrain.mlpreport rep) { int i = 0; int k = 0; int ccount = 0; int pcount = 0; double[,] trnxy = new double[0,0]; double[,] valxy = new double[0,0]; int trnsize = 0; int valsize = 0; int tmpinfo = 0; mlptrain.mlpreport tmprep = new mlptrain.mlpreport(); int nin = 0; int nout = 0; int wcount = 0; int i_ = 0; int i1_ = 0; info = 0; nin = mlpbase.mlpgetinputscount(ensemble.network); nout = mlpbase.mlpgetoutputscount(ensemble.network); wcount = mlpbase.mlpgetweightscount(ensemble.network); if( (npoints<2 || restarts<1) || (double)(decay)<(double)(0) ) { info = -1; return; } if( mlpbase.mlpissoftmax(ensemble.network) ) { for(i=0; i<=npoints-1; i++) { if( (int)Math.Round(xy[i,nin])<0 || (int)Math.Round(xy[i,nin])>=nout ) { info = -2; return; } } } info = 6; // // allocate // if( mlpbase.mlpissoftmax(ensemble.network) ) { ccount = nin+1; pcount = nin; } else { ccount = nin+nout; pcount = nin+nout; } trnxy = new double[npoints, ccount]; valxy = new double[npoints, ccount]; rep.ngrad = 0; rep.nhess = 0; rep.ncholesky = 0; // // train networks // for(k=0; k<=ensemble.ensemblesize-1; k++) { // // Split set // do { trnsize = 0; valsize = 0; for(i=0; i<=npoints-1; i++) { if( (double)(math.randomreal())<(double)(0.66) ) { // // Assign sample to training set // for(i_=0; i_<=ccount-1;i_++) { trnxy[trnsize,i_] = xy[i,i_]; } trnsize = trnsize+1; } else { // // Assign sample to validation set // for(i_=0; i_<=ccount-1;i_++) { valxy[valsize,i_] = xy[i,i_]; } valsize = valsize+1; } } } while( !(trnsize!=0 && valsize!=0) ); // // Train // mlptrain.mlptraines(ensemble.network, trnxy, trnsize, valxy, valsize, decay, restarts, ref tmpinfo, tmprep); if( tmpinfo<0 ) { info = tmpinfo; return; } // // save results // i1_ = (0) - (k*wcount); for(i_=k*wcount; i_<=(k+1)*wcount-1;i_++) { ensemble.weights[i_] = ensemble.network.weights[i_+i1_]; } i1_ = (0) - (k*pcount); for(i_=k*pcount; i_<=(k+1)*pcount-1;i_++) { ensemble.columnmeans[i_] = ensemble.network.columnmeans[i_+i1_]; } i1_ = (0) - (k*pcount); for(i_=k*pcount; i_<=(k+1)*pcount-1;i_++) { ensemble.columnsigmas[i_] = ensemble.network.columnsigmas[i_+i1_]; } rep.ngrad = rep.ngrad+tmprep.ngrad; rep.nhess = rep.nhess+tmprep.nhess; rep.ncholesky = rep.ncholesky+tmprep.ncholesky; } }
/************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). Modified Levenberg-Marquardt algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpebagginglm(mlpensemble ensemble, double[,] xy, int npoints, double decay, int restarts, ref int info, mlptrain.mlpreport rep, mlptrain.mlpcvreport ooberrors) { info = 0; mlpebagginginternal(ensemble, xy, npoints, decay, restarts, 0.0, 0, true, ref info, rep, ooberrors); }
/************************************************************************* 'interactive' variant of MLPEProcess for languages like Python which support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeprocessi(mlpensemble ensemble, double[] x, ref double[] y) { y = new double[0]; mlpeprocess(ensemble, x, ref y); }
/************************************************************************* Return normalization type (whether ensemble is SOFTMAX-normalized or not). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static bool mlpeissoftmax(mlpensemble ensemble) { bool result = new bool(); result = mlpbase.mlpissoftmax(ensemble.network); return result; }
/************************************************************************* Return ensemble properties (number of inputs and outputs). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeproperties(mlpensemble ensemble, ref int nin, ref int nout) { nin = 0; nout = 0; nin = ensemble.nin; nout = ensemble.nout; }
/************************************************************************* Randomization of MLP ensemble -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlperandomize(mlpensemble ensemble) { int i = 0; for(i=0; i<=ensemble.ensemblesize*ensemble.wcount-1; i++) { ensemble.weights[i] = math.randomreal()-0.5; } }
/************************************************************************* Unserialization of MLPEnsemble strucure INPUT PARAMETERS: RA - real array which stores ensemble OUTPUT PARAMETERS: Ensemble- restored structure -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeunserialize(double[] ra, mlpensemble ensemble) { int i = 0; int ssize = 0; int ntotal = 0; int ccount = 0; int hsize = 0; int offs = 0; int i_ = 0; int i1_ = 0; ap.assert((int)Math.Round(ra[1])==mlpevnum, "MLPEUnserialize: incorrect array!"); // // load info // hsize = 13; ensemble.ensemblesize = (int)Math.Round(ra[2]); ensemble.nin = (int)Math.Round(ra[3]); ensemble.nout = (int)Math.Round(ra[4]); ensemble.wcount = (int)Math.Round(ra[5]); ensemble.issoftmax = (int)Math.Round(ra[6])==1; ensemble.postprocessing = (int)Math.Round(ra[7])==1; ssize = (int)Math.Round(ra[8]); ntotal = (int)Math.Round(ra[9]); ccount = (int)Math.Round(ra[10]); offs = (int)Math.Round(ra[11]); ensemble.serializedlen = (int)Math.Round(ra[12]); // // Allocate arrays // ensemble.structinfo = new int[ssize-1+1]; ensemble.weights = new double[ensemble.ensemblesize*ensemble.wcount-1+1]; ensemble.columnmeans = new double[ensemble.ensemblesize*ccount-1+1]; ensemble.columnsigmas = new double[ensemble.ensemblesize*ccount-1+1]; ensemble.tmpweights = new double[ensemble.wcount-1+1]; ensemble.tmpmeans = new double[ccount-1+1]; ensemble.tmpsigmas = new double[ccount-1+1]; ensemble.neurons = new double[ntotal-1+1]; ensemble.dfdnet = new double[ntotal-1+1]; ensemble.serializedmlp = new double[ensemble.serializedlen-1+1]; ensemble.y = new double[ensemble.nout-1+1]; // // load data // for(i=offs; i<=offs+ssize-1; i++) { ensemble.structinfo[i-offs] = (int)Math.Round(ra[i]); } offs = offs+ssize; i1_ = (offs) - (0); for(i_=0; i_<=ensemble.ensemblesize*ensemble.wcount-1;i_++) { ensemble.weights[i_] = ra[i_+i1_]; } offs = offs+ensemble.ensemblesize*ensemble.wcount; i1_ = (offs) - (0); for(i_=0; i_<=ensemble.ensemblesize*ccount-1;i_++) { ensemble.columnmeans[i_] = ra[i_+i1_]; } offs = offs+ensemble.ensemblesize*ccount; i1_ = (offs) - (0); for(i_=0; i_<=ensemble.ensemblesize*ccount-1;i_++) { ensemble.columnsigmas[i_] = ra[i_+i1_]; } offs = offs+ensemble.ensemblesize*ccount; i1_ = (offs) - (0); for(i_=0; i_<=ensemble.serializedlen-1;i_++) { ensemble.serializedmlp[i_] = ra[i_+i1_]; } offs = offs+ensemble.serializedlen; }
/************************************************************************* Serialization of MLPEnsemble strucure INPUT PARAMETERS: Ensemble- original OUTPUT PARAMETERS: RA - array of real numbers which stores ensemble, array[0..RLen-1] RLen - RA lenght -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeserialize(mlpensemble ensemble, ref double[] ra, ref int rlen) { int i = 0; int ssize = 0; int ntotal = 0; int ccount = 0; int hsize = 0; int offs = 0; int i_ = 0; int i1_ = 0; ra = new double[0]; rlen = 0; hsize = 13; ssize = ensemble.structinfo[0]; if( ensemble.issoftmax ) { ccount = ensemble.nin; } else { ccount = ensemble.nin+ensemble.nout; } ntotal = ensemble.structinfo[mlpntotaloffset]; rlen = hsize+ssize+ensemble.ensemblesize*ensemble.wcount+2*ccount*ensemble.ensemblesize+ensemble.serializedlen; // // RA format: // [0] RLen // [1] Version (MLPEVNum) // [2] EnsembleSize // [3] NIn // [4] NOut // [5] WCount // [6] IsSoftmax 0/1 // [7] PostProcessing 0/1 // [8] sizeof(StructInfo) // [9] NTotal (sizeof(Neurons), sizeof(DFDNET)) // [10] CCount (sizeof(ColumnMeans), sizeof(ColumnSigmas)) // [11] data offset // [12] SerializedLen // // [..] StructInfo // [..] Weights // [..] ColumnMeans // [..] ColumnSigmas // ra = new double[rlen-1+1]; ra[0] = rlen; ra[1] = mlpevnum; ra[2] = ensemble.ensemblesize; ra[3] = ensemble.nin; ra[4] = ensemble.nout; ra[5] = ensemble.wcount; if( ensemble.issoftmax ) { ra[6] = 1; } else { ra[6] = 0; } if( ensemble.postprocessing ) { ra[7] = 1; } else { ra[7] = 9; } ra[8] = ssize; ra[9] = ntotal; ra[10] = ccount; ra[11] = hsize; ra[12] = ensemble.serializedlen; offs = hsize; for(i=offs; i<=offs+ssize-1; i++) { ra[i] = ensemble.structinfo[i-offs]; } offs = offs+ssize; i1_ = (0) - (offs); for(i_=offs; i_<=offs+ensemble.ensemblesize*ensemble.wcount-1;i_++) { ra[i_] = ensemble.weights[i_+i1_]; } offs = offs+ensemble.ensemblesize*ensemble.wcount; i1_ = (0) - (offs); for(i_=offs; i_<=offs+ensemble.ensemblesize*ccount-1;i_++) { ra[i_] = ensemble.columnmeans[i_+i1_]; } offs = offs+ensemble.ensemblesize*ccount; i1_ = (0) - (offs); for(i_=offs; i_<=offs+ensemble.ensemblesize*ccount-1;i_++) { ra[i_] = ensemble.columnsigmas[i_+i1_]; } offs = offs+ensemble.ensemblesize*ccount; i1_ = (0) - (offs); for(i_=offs; i_<=offs+ensemble.serializedlen-1;i_++) { ra[i_] = ensemble.serializedmlp[i_+i1_]; } offs = offs+ensemble.serializedlen; }
/************************************************************************* Copying of MLPEnsemble strucure INPUT PARAMETERS: Ensemble1 - original OUTPUT PARAMETERS: Ensemble2 - copy -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecopy(mlpensemble ensemble1, mlpensemble ensemble2) { int i = 0; int ssize = 0; int ccount = 0; int ntotal = 0; int i_ = 0; // // Unload info // ssize = ensemble1.structinfo[0]; if( ensemble1.issoftmax ) { ccount = ensemble1.nin; } else { ccount = ensemble1.nin+ensemble1.nout; } ntotal = ensemble1.structinfo[mlpntotaloffset]; // // Allocate space // ensemble2.structinfo = new int[ssize-1+1]; ensemble2.weights = new double[ensemble1.ensemblesize*ensemble1.wcount-1+1]; ensemble2.columnmeans = new double[ensemble1.ensemblesize*ccount-1+1]; ensemble2.columnsigmas = new double[ensemble1.ensemblesize*ccount-1+1]; ensemble2.tmpweights = new double[ensemble1.wcount-1+1]; ensemble2.tmpmeans = new double[ccount-1+1]; ensemble2.tmpsigmas = new double[ccount-1+1]; ensemble2.serializedmlp = new double[ensemble1.serializedlen-1+1]; ensemble2.neurons = new double[ntotal-1+1]; ensemble2.dfdnet = new double[ntotal-1+1]; ensemble2.y = new double[ensemble1.nout-1+1]; // // Copy // ensemble2.nin = ensemble1.nin; ensemble2.nout = ensemble1.nout; ensemble2.wcount = ensemble1.wcount; ensemble2.ensemblesize = ensemble1.ensemblesize; ensemble2.issoftmax = ensemble1.issoftmax; ensemble2.postprocessing = ensemble1.postprocessing; ensemble2.serializedlen = ensemble1.serializedlen; for(i=0; i<=ssize-1; i++) { ensemble2.structinfo[i] = ensemble1.structinfo[i]; } for(i_=0; i_<=ensemble1.ensemblesize*ensemble1.wcount-1;i_++) { ensemble2.weights[i_] = ensemble1.weights[i_]; } for(i_=0; i_<=ensemble1.ensemblesize*ccount-1;i_++) { ensemble2.columnmeans[i_] = ensemble1.columnmeans[i_]; } for(i_=0; i_<=ensemble1.ensemblesize*ccount-1;i_++) { ensemble2.columnsigmas[i_] = ensemble1.columnsigmas[i_]; } for(i_=0; i_<=ensemble1.serializedlen-1;i_++) { ensemble2.serializedmlp[i_] = ensemble1.serializedmlp[i_]; } }
/************************************************************************* Creates ensemble from network. Only network geometry is copied. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecreatefromnetwork(mlpbase.multilayerperceptron network, int ensemblesize, mlpensemble ensemble) { int i = 0; int ccount = 0; int i_ = 0; int i1_ = 0; ap.assert(ensemblesize>0, "MLPECreate: incorrect ensemble size!"); // // network properties // mlpbase.mlpproperties(network, ref ensemble.nin, ref ensemble.nout, ref ensemble.wcount); if( mlpbase.mlpissoftmax(network) ) { ccount = ensemble.nin; } else { ccount = ensemble.nin+ensemble.nout; } ensemble.postprocessing = false; ensemble.issoftmax = mlpbase.mlpissoftmax(network); ensemble.ensemblesize = ensemblesize; // // structure information // ensemble.structinfo = new int[network.structinfo[0]-1+1]; for(i=0; i<=network.structinfo[0]-1; i++) { ensemble.structinfo[i] = network.structinfo[i]; } // // weights, means, sigmas // ensemble.weights = new double[ensemblesize*ensemble.wcount-1+1]; ensemble.columnmeans = new double[ensemblesize*ccount-1+1]; ensemble.columnsigmas = new double[ensemblesize*ccount-1+1]; for(i=0; i<=ensemblesize*ensemble.wcount-1; i++) { ensemble.weights[i] = math.randomreal()-0.5; } for(i=0; i<=ensemblesize-1; i++) { i1_ = (0) - (i*ccount); for(i_=i*ccount; i_<=(i+1)*ccount-1;i_++) { ensemble.columnmeans[i_] = network.columnmeans[i_+i1_]; } i1_ = (0) - (i*ccount); for(i_=i*ccount; i_<=(i+1)*ccount-1;i_++) { ensemble.columnsigmas[i_] = network.columnsigmas[i_+i1_]; } } // // serialized part // mlpbase.mlpserializeold(network, ref ensemble.serializedmlp, ref ensemble.serializedlen); // // temporaries, internal buffers // ensemble.tmpweights = new double[ensemble.wcount-1+1]; ensemble.tmpmeans = new double[ccount-1+1]; ensemble.tmpsigmas = new double[ccount-1+1]; ensemble.neurons = new double[ensemble.structinfo[mlpntotaloffset]-1+1]; ensemble.dfdnet = new double[ensemble.structinfo[mlpntotaloffset]-1+1]; ensemble.y = new double[ensemble.nout-1+1]; }
/************************************************************************* Average relative error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average relative error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static double mlpeavgrelerror(mlpensemble ensemble, double[,] xy, int npoints) { double result = 0; mlpbase.modelerrors rep = new mlpbase.modelerrors(); mlpeallerrorsx(ensemble, xy, ensemble.network.dummysxy, npoints, 0, ensemble.network.dummyidx, 0, npoints, 0, ensemble.network.buf, rep); result = rep.avgrelerror; return result; }
/************************************************************************* Randomization of MLP ensemble -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlperandomize(mlpensemble ensemble) { int i = 0; int wcount = 0; wcount = mlpbase.mlpgetweightscount(ensemble.network); for(i=0; i<=ensemble.ensemblesize*wcount-1; i++) { ensemble.weights[i] = math.randomreal()-0.5; } }
/************************************************************************* Return ensemble properties (number of inputs and outputs). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeproperties(mlpensemble ensemble, ref int nin, ref int nout) { nin = 0; nout = 0; nin = mlpbase.mlpgetinputscount(ensemble.network); nout = mlpbase.mlpgetoutputscount(ensemble.network); }
/************************************************************************* Return normalization type (whether ensemble is SOFTMAX-normalized or not). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static bool mlpeissoftmax(mlpensemble ensemble) { bool result = new bool(); result = ensemble.issoftmax; return result; }
/************************************************************************* Procesing INPUT PARAMETERS: Ensemble- neural networks ensemble X - input vector, array[0..NIn-1]. Y - (possibly) preallocated buffer; if size of Y is less than NOut, it will be reallocated. If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeprocess(mlpensemble ensemble, double[] x, ref double[] y) { int i = 0; int es = 0; int wc = 0; int cc = 0; double v = 0; int nout = 0; int i_ = 0; int i1_ = 0; if( alglib.ap.len(y)<mlpbase.mlpgetoutputscount(ensemble.network) ) { y = new double[mlpbase.mlpgetoutputscount(ensemble.network)]; } es = ensemble.ensemblesize; wc = mlpbase.mlpgetweightscount(ensemble.network); if( mlpbase.mlpissoftmax(ensemble.network) ) { cc = mlpbase.mlpgetinputscount(ensemble.network); } else { cc = mlpbase.mlpgetinputscount(ensemble.network)+mlpbase.mlpgetoutputscount(ensemble.network); } v = (double)1/(double)es; nout = mlpbase.mlpgetoutputscount(ensemble.network); for(i=0; i<=nout-1; i++) { y[i] = 0; } for(i=0; i<=es-1; i++) { i1_ = (i*wc) - (0); for(i_=0; i_<=wc-1;i_++) { ensemble.network.weights[i_] = ensemble.weights[i_+i1_]; } i1_ = (i*cc) - (0); for(i_=0; i_<=cc-1;i_++) { ensemble.network.columnmeans[i_] = ensemble.columnmeans[i_+i1_]; } i1_ = (i*cc) - (0); for(i_=0; i_<=cc-1;i_++) { ensemble.network.columnsigmas[i_] = ensemble.columnsigmas[i_+i1_]; } mlpbase.mlpprocess(ensemble.network, x, ref ensemble.y); for(i_=0; i_<=nout-1;i_++) { y[i_] = y[i_] + v*ensemble.y[i_]; } } }
/************************************************************************* Procesing INPUT PARAMETERS: Ensemble- neural networks ensemble X - input vector, array[0..NIn-1]. Y - (possibly) preallocated buffer; if size of Y is less than NOut, it will be reallocated. If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpeprocess(mlpensemble ensemble, double[] x, ref double[] y) { int i = 0; int es = 0; int wc = 0; int cc = 0; double v = 0; int i_ = 0; int i1_ = 0; if( ap.len(y)<ensemble.nout ) { y = new double[ensemble.nout]; } es = ensemble.ensemblesize; wc = ensemble.wcount; if( ensemble.issoftmax ) { cc = ensemble.nin; } else { cc = ensemble.nin+ensemble.nout; } v = (double)1/(double)es; for(i=0; i<=ensemble.nout-1; i++) { y[i] = 0; } for(i=0; i<=es-1; i++) { i1_ = (i*wc) - (0); for(i_=0; i_<=wc-1;i_++) { ensemble.tmpweights[i_] = ensemble.weights[i_+i1_]; } i1_ = (i*cc) - (0); for(i_=0; i_<=cc-1;i_++) { ensemble.tmpmeans[i_] = ensemble.columnmeans[i_+i1_]; } i1_ = (i*cc) - (0); for(i_=0; i_<=cc-1;i_++) { ensemble.tmpsigmas[i_] = ensemble.columnsigmas[i_+i1_]; } mlpbase.mlpinternalprocessvector(ensemble.structinfo, ensemble.tmpweights, ensemble.tmpmeans, ensemble.tmpsigmas, ref ensemble.neurons, ref ensemble.dfdnet, x, ref ensemble.y); for(i_=0; i_<=ensemble.nout-1;i_++) { y[i_] = y[i_] + v*ensemble.y[i_]; } } }
/************************************************************************* Average relative error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average relative error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static double mlpeavgrelerror(mlpensemble ensemble, double[,] xy, int npoints) { double result = 0; double relcls = 0; double avgce = 0; double rms = 0; double avg = 0; double avgrel = 0; mlpeallerrors(ensemble, xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel); result = avgrel; return result; }
/************************************************************************* Calculation of all types of errors -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ private static void mlpeallerrors(mlpensemble ensemble, double[,] xy, int npoints, ref double relcls, ref double avgce, ref double rms, ref double avg, ref double avgrel) { int i = 0; double[] buf = new double[0]; double[] workx = new double[0]; double[] y = new double[0]; double[] dy = new double[0]; int i_ = 0; int i1_ = 0; relcls = 0; avgce = 0; rms = 0; avg = 0; avgrel = 0; workx = new double[ensemble.nin-1+1]; y = new double[ensemble.nout-1+1]; if( ensemble.issoftmax ) { dy = new double[0+1]; bdss.dserrallocate(ensemble.nout, ref buf); } else { dy = new double[ensemble.nout-1+1]; bdss.dserrallocate(-ensemble.nout, ref buf); } for(i=0; i<=npoints-1; i++) { for(i_=0; i_<=ensemble.nin-1;i_++) { workx[i_] = xy[i,i_]; } mlpeprocess(ensemble, workx, ref y); if( ensemble.issoftmax ) { dy[0] = xy[i,ensemble.nin]; } else { i1_ = (ensemble.nin) - (0); for(i_=0; i_<=ensemble.nout-1;i_++) { dy[i_] = xy[i,i_+i1_]; } } bdss.dserraccumulate(ref buf, y, dy); } bdss.dserrfinish(ref buf); relcls = buf[0]; avgce = buf[1]; rms = buf[2]; avg = buf[3]; avgrel = buf[4]; }
/************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). L-BFGS algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpebagginglbfgs(mlpensemble ensemble, double[,] xy, int npoints, double decay, int restarts, double wstep, int maxits, ref int info, mlptrain.mlpreport rep, mlptrain.mlpcvreport ooberrors) { info = 0; mlpebagginginternal(ensemble, xy, npoints, decay, restarts, wstep, maxits, false, ref info, rep, ooberrors); }
/************************************************************************* Like MLPCreateR1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecreater1(int nin, int nhid, int nout, double a, double b, int ensemblesize, mlpensemble ensemble) { mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron(); mlpbase.mlpcreater1(nin, nhid, nout, a, b, net); mlpecreatefromnetwork(net, ensemblesize, ensemble); }
/************************************************************************* Serializer: allocation -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ public static void mlpealloc(alglib.serializer s, mlpensemble ensemble) { s.alloc_entry(); s.alloc_entry(); s.alloc_entry(); apserv.allocrealarray(s, ensemble.weights, -1); apserv.allocrealarray(s, ensemble.columnmeans, -1); apserv.allocrealarray(s, ensemble.columnsigmas, -1); mlpbase.mlpalloc(s, ensemble.network); }
/************************************************************************* Like MLPCreateC2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecreatec2(int nin, int nhid1, int nhid2, int nout, int ensemblesize, mlpensemble ensemble) { mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron(); mlpbase.mlpcreatec2(nin, nhid1, nhid2, nout, net); mlpecreatefromnetwork(net, ensemblesize, ensemble); }
/************************************************************************* Serializer: unserialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ public static void mlpeunserialize(alglib.serializer s, mlpensemble ensemble) { int i0 = 0; int i1 = 0; // // check correctness of header // i0 = s.unserialize_int(); alglib.ap.assert(i0==scodes.getmlpeserializationcode(), "MLPEUnserialize: stream header corrupted"); i1 = s.unserialize_int(); alglib.ap.assert(i1==mlpefirstversion, "MLPEUnserialize: stream header corrupted"); // // Create network // ensemble.ensemblesize = s.unserialize_int(); apserv.unserializerealarray(s, ref ensemble.weights); apserv.unserializerealarray(s, ref ensemble.columnmeans); apserv.unserializerealarray(s, ref ensemble.columnsigmas); mlpbase.mlpunserialize(s, ensemble.network); // // Allocate termoraries // ensemble.y = new double[mlpbase.mlpgetoutputscount(ensemble.network)]; }
/************************************************************************* Creates ensemble from network. Only network geometry is copied. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecreatefromnetwork(mlpbase.multilayerperceptron network, int ensemblesize, mlpensemble ensemble) { int i = 0; int ccount = 0; int wcount = 0; int i_ = 0; int i1_ = 0; alglib.ap.assert(ensemblesize>0, "MLPECreate: incorrect ensemble size!"); // // Copy network // mlpbase.mlpcopy(network, ensemble.network); // // network properties // if( mlpbase.mlpissoftmax(network) ) { ccount = mlpbase.mlpgetinputscount(ensemble.network); } else { ccount = mlpbase.mlpgetinputscount(ensemble.network)+mlpbase.mlpgetoutputscount(ensemble.network); } wcount = mlpbase.mlpgetweightscount(ensemble.network); ensemble.ensemblesize = ensemblesize; // // weights, means, sigmas // ensemble.weights = new double[ensemblesize*wcount]; ensemble.columnmeans = new double[ensemblesize*ccount]; ensemble.columnsigmas = new double[ensemblesize*ccount]; for(i=0; i<=ensemblesize*wcount-1; i++) { ensemble.weights[i] = math.randomreal()-0.5; } for(i=0; i<=ensemblesize-1; i++) { i1_ = (0) - (i*ccount); for(i_=i*ccount; i_<=(i+1)*ccount-1;i_++) { ensemble.columnmeans[i_] = network.columnmeans[i_+i1_]; } i1_ = (0) - (i*ccount); for(i_=i*ccount; i_<=(i+1)*ccount-1;i_++) { ensemble.columnsigmas[i_] = network.columnsigmas[i_+i1_]; } } // // temporaries, internal buffers // ensemble.y = new double[mlpbase.mlpgetoutputscount(ensemble.network)]; }
/************************************************************************* Internal bagging subroutine. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ private static void mlpebagginginternal(mlpensemble ensemble, double[,] xy, int npoints, double decay, int restarts, double wstep, int maxits, bool lmalgorithm, ref int info, mlptrain.mlpreport rep, mlptrain.mlpcvreport ooberrors) { double[,] xys = new double[0,0]; bool[] s = new bool[0]; double[,] oobbuf = new double[0,0]; int[] oobcntbuf = new int[0]; double[] x = new double[0]; double[] y = new double[0]; double[] dy = new double[0]; double[] dsbuf = new double[0]; int ccnt = 0; int pcnt = 0; int i = 0; int j = 0; int k = 0; double v = 0; mlptrain.mlpreport tmprep = new mlptrain.mlpreport(); int nin = 0; int nout = 0; int wcount = 0; int i_ = 0; int i1_ = 0; info = 0; nin = mlpbase.mlpgetinputscount(ensemble.network); nout = mlpbase.mlpgetoutputscount(ensemble.network); wcount = mlpbase.mlpgetweightscount(ensemble.network); // // Test for inputs // if( (!lmalgorithm && (double)(wstep)==(double)(0)) && maxits==0 ) { info = -8; return; } if( ((npoints<=0 || restarts<1) || (double)(wstep)<(double)(0)) || maxits<0 ) { info = -1; return; } if( mlpbase.mlpissoftmax(ensemble.network) ) { for(i=0; i<=npoints-1; i++) { if( (int)Math.Round(xy[i,nin])<0 || (int)Math.Round(xy[i,nin])>=nout ) { info = -2; return; } } } // // allocate temporaries // info = 2; rep.ngrad = 0; rep.nhess = 0; rep.ncholesky = 0; ooberrors.relclserror = 0; ooberrors.avgce = 0; ooberrors.rmserror = 0; ooberrors.avgerror = 0; ooberrors.avgrelerror = 0; if( mlpbase.mlpissoftmax(ensemble.network) ) { ccnt = nin+1; pcnt = nin; } else { ccnt = nin+nout; pcnt = nin+nout; } xys = new double[npoints, ccnt]; s = new bool[npoints]; oobbuf = new double[npoints, nout]; oobcntbuf = new int[npoints]; x = new double[nin]; y = new double[nout]; if( mlpbase.mlpissoftmax(ensemble.network) ) { dy = new double[1]; } else { dy = new double[nout]; } for(i=0; i<=npoints-1; i++) { for(j=0; j<=nout-1; j++) { oobbuf[i,j] = 0; } } for(i=0; i<=npoints-1; i++) { oobcntbuf[i] = 0; } // // main bagging cycle // for(k=0; k<=ensemble.ensemblesize-1; k++) { // // prepare dataset // for(i=0; i<=npoints-1; i++) { s[i] = false; } for(i=0; i<=npoints-1; i++) { j = math.randominteger(npoints); s[j] = true; for(i_=0; i_<=ccnt-1;i_++) { xys[i,i_] = xy[j,i_]; } } // // train // if( lmalgorithm ) { mlptrain.mlptrainlm(ensemble.network, xys, npoints, decay, restarts, ref info, tmprep); } else { mlptrain.mlptrainlbfgs(ensemble.network, xys, npoints, decay, restarts, wstep, maxits, ref info, tmprep); } if( info<0 ) { return; } // // save results // rep.ngrad = rep.ngrad+tmprep.ngrad; rep.nhess = rep.nhess+tmprep.nhess; rep.ncholesky = rep.ncholesky+tmprep.ncholesky; i1_ = (0) - (k*wcount); for(i_=k*wcount; i_<=(k+1)*wcount-1;i_++) { ensemble.weights[i_] = ensemble.network.weights[i_+i1_]; } i1_ = (0) - (k*pcnt); for(i_=k*pcnt; i_<=(k+1)*pcnt-1;i_++) { ensemble.columnmeans[i_] = ensemble.network.columnmeans[i_+i1_]; } i1_ = (0) - (k*pcnt); for(i_=k*pcnt; i_<=(k+1)*pcnt-1;i_++) { ensemble.columnsigmas[i_] = ensemble.network.columnsigmas[i_+i1_]; } // // OOB estimates // for(i=0; i<=npoints-1; i++) { if( !s[i] ) { for(i_=0; i_<=nin-1;i_++) { x[i_] = xy[i,i_]; } mlpbase.mlpprocess(ensemble.network, x, ref y); for(i_=0; i_<=nout-1;i_++) { oobbuf[i,i_] = oobbuf[i,i_] + y[i_]; } oobcntbuf[i] = oobcntbuf[i]+1; } } } // // OOB estimates // if( mlpbase.mlpissoftmax(ensemble.network) ) { bdss.dserrallocate(nout, ref dsbuf); } else { bdss.dserrallocate(-nout, ref dsbuf); } for(i=0; i<=npoints-1; i++) { if( oobcntbuf[i]!=0 ) { v = (double)1/(double)oobcntbuf[i]; for(i_=0; i_<=nout-1;i_++) { y[i_] = v*oobbuf[i,i_]; } if( mlpbase.mlpissoftmax(ensemble.network) ) { dy[0] = xy[i,nin]; } else { i1_ = (nin) - (0); for(i_=0; i_<=nout-1;i_++) { dy[i_] = v*xy[i,i_+i1_]; } } bdss.dserraccumulate(ref dsbuf, y, dy); } } bdss.dserrfinish(ref dsbuf); ooberrors.relclserror = dsbuf[0]; ooberrors.avgce = dsbuf[1]; ooberrors.rmserror = dsbuf[2]; ooberrors.avgerror = dsbuf[3]; ooberrors.avgrelerror = dsbuf[4]; }
/************************************************************************* Copying of MLPEnsemble strucure INPUT PARAMETERS: Ensemble1 - original OUTPUT PARAMETERS: Ensemble2 - copy -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ public static void mlpecopy(mlpensemble ensemble1, mlpensemble ensemble2) { int ccount = 0; int wcount = 0; int i_ = 0; // // Unload info // if( mlpbase.mlpissoftmax(ensemble1.network) ) { ccount = mlpbase.mlpgetinputscount(ensemble1.network); } else { ccount = mlpbase.mlpgetinputscount(ensemble1.network)+mlpbase.mlpgetoutputscount(ensemble1.network); } wcount = mlpbase.mlpgetweightscount(ensemble1.network); // // Allocate space // ensemble2.weights = new double[ensemble1.ensemblesize*wcount]; ensemble2.columnmeans = new double[ensemble1.ensemblesize*ccount]; ensemble2.columnsigmas = new double[ensemble1.ensemblesize*ccount]; ensemble2.y = new double[mlpbase.mlpgetoutputscount(ensemble1.network)]; // // Copy // ensemble2.ensemblesize = ensemble1.ensemblesize; for(i_=0; i_<=ensemble1.ensemblesize*wcount-1;i_++) { ensemble2.weights[i_] = ensemble1.weights[i_]; } for(i_=0; i_<=ensemble1.ensemblesize*ccount-1;i_++) { ensemble2.columnmeans[i_] = ensemble1.columnmeans[i_]; } for(i_=0; i_<=ensemble1.ensemblesize*ccount-1;i_++) { ensemble2.columnsigmas[i_] = ensemble1.columnsigmas[i_]; } mlpbase.mlpcopy(ensemble1.network, ensemble2.network); }