Java tutorial
/*********************************************************************** This file is part of KEEL-software, the Data Mining tool for regression, classification, clustering, pattern mining and so on. Copyright (C) 2004-2010 F. Herrera (herrera@decsai.ugr.es) L. Snchez (luciano@uniovi.es) J. Alcal-Fdez (jalcala@decsai.ugr.es) S. Garca (sglopez@ujaen.es) A. Fernndez (alberto.fernandez@ujaen.es) J. Luengo (julianlm@decsai.ugr.es) 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 3 of the License, 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. If not, see http://www.gnu.org/licenses/ **********************************************************************/ package keel.Algorithms.Neural_Networks.IRPropPlus_Clas; import keel.Algorithms.Neural_Networks.NNEP_Common.data.DoubleTransposedDataSet; import net.sf.jclec.IConfigure; import org.apache.commons.configuration.Configuration; /** * <p> * @author Juan Carlos Fernandez Caballero (University of Cordoba) 27/10/2007 * @author Modified by Pedro Antonio Gutierrez Pea (University of Cordoba) 27/10/2007 * @version 0.1 * @since JDK1.5 * </p> */ public class IRPropPlus implements IConfigure { /** * <p> * Local search procedure based in a backtraking Strategy * </p> */ ///////////////////////////////////////////////////////////////// // --------------------------------------- Serialization constant ///////////////////////////////////////////////////////////////// private static final long serialVersionUID = 6842976526620430756L; ///////////////////////////////////////////////////////////////// // --------------------------------------------------- Properties ///////////////////////////////////////////////////////////////// /** Initial Delta for RpropPlus Algorithm **/ protected double initialStepSize; /** Minimum Value for Delta in RpropPlus Algorithm **/ protected double minimumDelta; /** Maximum Value for Delta in RpropPlus Algorithm **/ protected double maximumDelta; /** Value of positive Eta **/ protected double positiveEta; /** Value of negative Eta **/ protected double negativeEta; /** Value of stop condition **/ protected int epochs; ///////////////////////////////////////////////////////////////// // ------------------------------------------ Auxiliar Properties ///////////////////////////////////////////////////////////////// /** Input array */ protected double[][] x; /** Output array */ protected double[][] y; /** Output errors */ protected double[] error; /** Current coefficient array */ protected double[] a; /** Reduced step size array */ protected boolean[] reducedStepSize = null; ///////////////////////////////////////////////////////////////// // ------------------------------------------------- Constructors ///////////////////////////////////////////////////////////////// /** * <p> * Empty constructor. * </p> */ public IRPropPlus() { super(); } ///////////////////////////////////////////////////////////////// // --------------------------------------- Get and set properties ///////////////////////////////////////////////////////////////// /** * <p> * Returns the maximum delta value, that is, the maximum increment or * step size of the corresponding coefficients * * @return double Maximum delta value * </p> */ public double getMaximumDelta() { return maximumDelta; } /** * <p> * Sets the maximum delta value, that is, the maximum increment or * step size of the corresponding coefficients * * @param maximumDelta New maximum delta value * </p> */ public void setMaximumDelta(double maximumDelta) { this.maximumDelta = maximumDelta; } /** * <p> * Returns the minimum delta value, that is, the minimum increment or * step size of the corresponding coefficients * * @return double Maximum delta value * </p> */ public double getMinimumDelta() { return minimumDelta; } /** * <p> * Sets the minimum delta value, that is, the minimum increment or * step size of the corresponding coefficients * * @param minimumDelta New minimum delta value * </p> */ public void setMinimumDelta(double minimumDelta) { this.minimumDelta = minimumDelta; } /** * <p> * Returns the negative eta value, that is, the increment * of the step size at each ephoc * * @return double Negative eta value * </p> */ public double getNegativeEta() { return negativeEta; } /** * <p> * Sets the negative eta value, that is, the increment * of the step size at each epoch * * @param negativeEta New negative eta value * </p> */ public void setNegativeEta(double negativeEta) { this.negativeEta = negativeEta; } /** * <p> * Returns the positive eta value, that is, the increment * of the step size at each epoch * * @return double Positive eta value * </p> */ public double getPositiveEta() { return positiveEta; } /** * <p> * Sets the positive eta value, that is, the increment * of the step size at each epoch * * @param positiveEta New positive eta value * </p> */ public void setPositiveEta(double positiveEta) { this.positiveEta = positiveEta; } /** * <p> * Returns an array of booleans, indicating which coefficients * have to be treated as more sensible, using reduced step size * for these coefficients * * @return boolean[] The reduced step size boolean array * </p> */ public boolean[] getReducedStepSize() { return reducedStepSize; } /** * <p> * Sets an array of booleans, indicating which coefficients * have to be treated as more sensible, using reduced step size * for these coefficients * * @param reducedStepSize New reduced step size boolean array * </p> */ public void setReducedStepSize(boolean[] reducedStepSize) { this.reducedStepSize = reducedStepSize; } /////////////////////////////////////////////////////////////////// // ------------------------------- Implementing IOptimizer methods //////////////////////////////////////////////////////////////////// /** * <p> * Sets training data * * @param trainData DoubleTransposedDataSet to be used in training * </p> */ public void setTrainingData(DoubleTransposedDataSet trainData) { //Input array and error of each observation array double[][] x = new double[trainData.getNofobservations()][]; for (int i = 0; i < trainData.getNofobservations(); i++) x[i] = trainData.getInputs(i); this.x = x; //Output array double[][] y = new double[trainData.getNofobservations()][]; for (int i = 0; i < trainData.getNofobservations(); i++) y[i] = trainData.getOutputs(i); this.y = y; } /** * <p> * One local iRprop plus search in a IOptimizableFunc. * * @param function IOptimizableFunc to operate. * @return IOptimizableFunc Optimized function * </p> */ public IOptimizableFunc optimize(IOptimizableFunc function) { //Initial values for the algorithm double[] initialA = function.getCoefficients(); this.a = initialA; //Apply the iRprop+ double[] result = this.solve(function); //Set the coefficients array function.setCoefficients(result); return function; } /////////////////////////////////////////////////////////////////// // ---------------------------------------------- Protected methods /////////////////////////////////////////////////////////////////// /** * <p> * Apply the iRprop+ over a function that implements the IOptimizableFunc * interface. * * @param f function to apply the iRprop+ method * @return double array with the coefficients optimized * </p> */ protected double[] solve(IOptimizableFunc f) { // Stop forced int stop = 0; // Number of epochs without improving error int epochsWithoutImproving = 0; // Actual gradients double[] actualGradient = null; // Last gradients double[] lastGradient = new double[this.a.length]; // Step-size double[] increaseStepSize = new double[this.a.length]; // Increases double[] increaseCoefficients = new double[this.a.length]; // Weights or Coefficients double[] coefficients = this.a; // Actual Error. One error by each input double actualError = 0.0; // Last Error double lastError = 0.0; // Initialization of arrays for (int i = 0; i < this.a.length; i++) { lastGradient[i] = increaseCoefficients[i] = 0.0; increaseStepSize[i] = this.initialStepSize; } while (stop < this.epochs) { // Actual gradient and error for each weight or coefficient actualGradient = f.gradient(this.x, this.y); actualError = f.getLastError(); //System.out.println("Epoch: " + stop + " Error: " + actualError); // Actualization of coefficients // All coefficients treated equally if (reducedStepSize == null) { for (int i = 0; i < this.a.length; i++) { if (lastGradient[i] * actualGradient[i] > 0) { increaseStepSize[i] = Math.min(increaseStepSize[i] * this.positiveEta, maximumDelta); increaseCoefficients[i] = -(Math.signum(actualGradient[i]) * increaseStepSize[i]); coefficients[i] = coefficients[i] + increaseCoefficients[i]; } else if (lastGradient[i] * actualGradient[i] == 0) { increaseCoefficients[i] = -(Math.signum(actualGradient[i]) * increaseStepSize[i]); coefficients[i] = coefficients[i] + increaseCoefficients[i]; } else // (lastGradient[i]*actualGradient[i] < 0) OR Infinite problems { increaseStepSize[i] = Math.max(increaseStepSize[i] * this.negativeEta, minimumDelta); if (actualError > lastError) coefficients[i] = coefficients[i] - increaseCoefficients[i]; actualGradient[i] = 0.0; } } //for } // Actualization of coefficients // Some coefficients treated as more sensible else { for (int i = 0; i < this.a.length; i++) { // Reduced step size double finalPositiveEta = this.positiveEta; double finalNegativeEta = this.negativeEta; if (reducedStepSize[i]) { finalPositiveEta = 1 + ((finalPositiveEta - 1) * 0.5); finalNegativeEta *= 0.5; } if (lastGradient[i] * actualGradient[i] > 0) { increaseStepSize[i] = Math.min(increaseStepSize[i] * finalPositiveEta, maximumDelta); increaseCoefficients[i] = -(Math.signum(actualGradient[i]) * increaseStepSize[i]); coefficients[i] = coefficients[i] + increaseCoefficients[i]; } else if (lastGradient[i] * actualGradient[i] == 0) { increaseCoefficients[i] = -(Math.signum(actualGradient[i]) * increaseStepSize[i]); coefficients[i] = coefficients[i] + increaseCoefficients[i]; } else // (lastGradient[i]*actualGradient[i] < 0) OR Infinite problems { increaseStepSize[i] = Math.max(increaseStepSize[i] * finalNegativeEta, minimumDelta); if (actualError > lastError) coefficients[i] = coefficients[i] - increaseCoefficients[i]; actualGradient[i] = 0.0; } } //for } if (lastError == actualError) { epochsWithoutImproving++; if (epochsWithoutImproving >= 20) stop = this.epochs; } else epochsWithoutImproving = 0; // Updating gradient and error for the next step for (int i = 0; i < this.a.length; i++) lastGradient[i] = actualGradient[i]; lastError = actualError; f.setCoefficients(coefficients); stop++; } //While // Return the result return a; } ///////////////////////////////////////////////////////////////// // ---------------------------- Implementing IConfigure interface ///////////////////////////////////////////////////////////////// /** * <p> * @param settings Settings Configuration * </p> */ public void configure(Configuration settings) { initialStepSize = settings.getDouble("initial-step-size[@value]", 0.0125); minimumDelta = settings.getDouble("minimum-delta[@value]", 0.0); maximumDelta = settings.getDouble("maximum-delta[@value]", 50.0); positiveEta = settings.getDouble("positive-eta[@value]", 1.2); negativeEta = settings.getDouble("negative-eta[@value]", 0.2); epochs = settings.getInt("cycles[@value]", 25); } }