package org.neuroph.contrib.model.modelselection;

import org.neuroph.contrib.model.errorestimation.Bootstrapping;
import org.neuroph.eval.CrossValidation;
import org.neuroph.eval.classification.ClassificationMetrics;
import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.core.events.LearningEvent;
import org.neuroph.core.events.LearningEventListener;
import org.neuroph.nnet.MultiLayerPerceptron;
import org.neuroph.nnet.learning.BackPropagation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import org.neuroph.eval.ClassifierEvaluator;
import org.neuroph.eval.CrossValidation;

/**
 * @param  Type which defined which LearningRule will be used during model optimization
 */
public class MultilayerPerceptronOptimazer implements NeurophModelOptimizer {

    private static Logger LOG = LoggerFactory.getLogger(MultilayerPerceptronOptimazer.class);

    /**
     *
     */
    private Set> allArchitectures = new HashSet<>();

    private List optimalArchitecure;
    /**
     * Optimal optimizer which will be selected during optimization process
     */
    private NeuralNetwork optimalClassifier;
    /**
     * Average metric scores for selected optimal classififer
     */
    private ClassificationMetrics optimalResult;
    /**
     * Method used for classifier error estimation (KFold, Bootstrap)
     */
    private CrossValidation errorEstimationMethod;
    /**
     * Learning rule used during classifier learning stage
     */
    private BackPropagation learningRule;

    private int maxLayers = 1;
    private int minNeuronsPerLayer = 1;
    private int maxNeuronsPerLayer = 30;
    private int neuronIncrement = 1;

    /**
     * If ErrorEstimationMethod is not provided use KFoldCrossValidation by default
     */
    public MultilayerPerceptronOptimazer() {
       // errorEstimationMethod = new KFoldCrossValidation(10);
    }

    public MultilayerPerceptronOptimazer withMaxLayers(int maxLayers) {
        this.maxLayers = maxLayers;
        return this;
    }

    public MultilayerPerceptronOptimazer withNeuronIncrement(int neuronIncrement) {
        this.neuronIncrement = neuronIncrement;
        return this;
    }

    public MultilayerPerceptronOptimazer withMaxNeurons(int maxNeurons) {
        this.maxNeuronsPerLayer = maxNeurons;
        return this;
    }

    public MultilayerPerceptronOptimazer withMinNeurons(int minNeurons) {
        this.minNeuronsPerLayer = minNeurons;
        return this;
    }


    public MultilayerPerceptronOptimazer withErrorEstimationMethod(CrossValidation errorEstimationMethod) {
        this.errorEstimationMethod = errorEstimationMethod;
        return this;
    }

    public MultilayerPerceptronOptimazer withLearningRule(BackPropagation learningRule) {
        this.learningRule = learningRule;
        return this;
    }


    /**
     * @param dataSet training set used for error estimation
     * @return neural network model with optimized architecture for provided data set
     */
    @Override
    public NeuralNetwork createOptimalModel(DataSet dataSet) {

        List neurons = new ArrayList<>();
        neurons.add(minNeuronsPerLayer);
        findArchitectures(1, minNeuronsPerLayer, neurons);

        LOG.info("Total [{}] different network topologies found", allArchitectures.size());

        for (List architecture : allArchitectures) {
            try {
                architecture.add(0, dataSet.getInputSize());
                architecture.add(dataSet.getOutputSize());
                
                LOG.info("Architecture: [{}]", architecture);
                
                MultiLayerPerceptron network = new MultiLayerPerceptron(architecture);
                LearningListener listener = new LearningListener(10, learningRule.getMaxIterations());
                learningRule.addListener(listener);
                network.setLearningRule(learningRule);
                
                errorEstimationMethod = new CrossValidation(network, dataSet, 10);
                errorEstimationMethod.run();
                // FIX
                ClassificationMetrics[] result = ClassificationMetrics.createFromMatrix(errorEstimationMethod.getEvaluator(ClassifierEvaluator.MultiClass.class).getResult());
                
                // nadji onaj sa najmanjim f measure
                if (optimalResult == null || optimalResult.getFMeasure()< result[0].getFMeasure()) {
                    LOG.info("Architecture [{}] became optimal architecture  with metrics {}", architecture, result);
                    optimalResult = result[0];
                    optimalClassifier = network;
                    optimalArchitecure = architecture;
                }
                
                LOG.info("#################################################################");
            } catch (InterruptedException ex) {
                java.util.logging.Logger.getLogger(MultilayerPerceptronOptimazer.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                java.util.logging.Logger.getLogger(MultilayerPerceptronOptimazer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }


        LOG.info("Optimal Architecture: {}", optimalArchitecure);
        return optimalClassifier;
    }

    private void findArchitectures(int currentLayer, int lastLayerNeuronCount, List nerons) {
        allArchitectures.add(new ArrayList<>(nerons));

        if (lastLayerNeuronCount + neuronIncrement <= maxNeuronsPerLayer) {
            int indexOfLastElement = nerons.size() - 1;
            List newList = new ArrayList<>(nerons);
            newList.set(indexOfLastElement, lastLayerNeuronCount + neuronIncrement);
            findArchitectures(currentLayer, lastLayerNeuronCount + neuronIncrement, newList);
        }
        if (currentLayer + 1 <= maxLayers) {
            List newList = new ArrayList<>(nerons);
            newList.add(1);
            findArchitectures(currentLayer + 1, minNeuronsPerLayer, newList);
        }
    }


    static class LearningListener implements LearningEventListener {

        private double[] foldErrors;
        private int foldSize;

        public LearningListener(int foldSize, int maxIterations) {

            this.foldSize = foldSize;
            this.foldErrors = new double[maxIterations];
        }

        public void handleLearningEvent(LearningEvent event) {
            BackPropagation bp = (BackPropagation) event.getSource();
            foldErrors[bp.getCurrentIteration() - 1] += bp.getTotalNetworkError() / foldSize;
        }
    }

}

 

Ads help maintain this website.