/*********************************************************************** 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. S�nchez (luciano@uniovi.es) J. Alcal�-Fdez (jalcala@decsai.ugr.es) S. Garc�a (sglopez@ujaen.es) A. Fern�ndez (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.NNEP_Clas.neuralnet; import keel.Algorithms.Neural_Networks.NNEP_Clas.problem.classification.softmax.ISoftmaxClassifier; import keel.Algorithms.Neural_Networks.NNEP_Common.neuralnet.AbstractNeuralNet; /** * <p> * @author Written by Pedro Antonio Gutierrez Penia (University of Cordoba) 16/7/2007 * @author Modified by Aaron Ruiz Mora (University of Cordoba) 16/7/2007 * </p> * @version 0.1 * @since JDK1.5 */ public class NeuralNetClassifier extends AbstractNeuralNet implements ISoftmaxClassifier { /** * <p> * Neural net used as a classifier, with the posibility * of estimating probability of each class * </p> */ ///////////////////////////////////////////////////////////////// // -------------------------------------------------- Constructor ///////////////////////////////////////////////////////////////// /** * <p> * Empty constructor * </p> */ public NeuralNetClassifier() { super(); } ///////////////////////////////////////////////////////////////// // -------------------- Implementing ISoftmaxClassifier interface ///////////////////////////////////////////////////////////////// /** * <p> * Obtain the associated class of one observation * * @param inputs Double array with all inputs of the observation * * @return byte [] Array indicating the class of the observation * For example, {0,0,1} indicates that observation * is of the third class, {0,1,0} indicates that * observation is of the second class * </p> */ public byte[] classify(double []inputs){ //Obtain outputs double obtained[] = rawOutputs(inputs); //Classes array byte[] classes = new byte[outputLayer.getNofneurons()+1]; //Maximum value (initially first output) double max = obtained[0]; classes[0] = 1; //Index of the maximum value (initially first output) int index = 0; //For each output node for(int j=1; j<obtained.length; j++ ) if(obtained[j]>=max){ classes[j] = 1; if(obtained[j]>max) classes[index] = 0; max = obtained[j]; index = j; } return classes; } /** * <p> * Obtain the associated class of a set of observations, through * their inputs values * * @param inputs Double matrix with all inputs of all observations * * @return byte[] Matrix indicating the class of the observation * For example, {0,0,1} indicates that observation * is of the third class, {0,1,0} indicates that * observation is of the second class * </p> */ public byte[][] classify(double [][]inputs){ //Obtain outputs double obtained[][] = rawOutputs(inputs); //Classes matrix byte[][] classes = new byte[outputLayer.getNofneurons()+1][inputs[0].length]; //Array of maximum values (initially first output) double max[] = new double[inputs[0].length]; System.arraycopy(obtained[0],0,max,0,inputs[0].length); //Array of indexes maximum values (initially first output) int maxIndex[] = new int[inputs[0].length]; for(int i=0; i<maxIndex.length; i++){ classes[0][i] = 1; maxIndex[i] = 0; } //For each output node for(int j=1; j<obtained.length; j++ ) for(int i=0; i<inputs[0].length; i++) if(obtained[j][i]>=max[i]){ classes[j][i] = 1; if(obtained[j][i]>max[i]) classes[maxIndex[i]][i] = 0; max[i] = obtained[j][i]; maxIndex[i] = j; } return classes; } /** * <p> * Obtain the raw output of the classifier for each class * * @param inputs Double array with all inputs of the observation * * @return double [] Array with the outputs of each class * of the observation * </p> */ public double[] rawOutputs(double []inputs){ // Obtained outputs double obtained[] = new double[outputLayer.getNofneurons()+1]; // i-th output for(int i=0; i<obtained.length-1; i++) obtained[i] = outputLayer.getNeuron(i).operate(inputs); // 0 output obtained[obtained.length-1] = 0; return obtained; } /** * <p> * Obtain the raw outputs of classes of a set of observations, * through their inputs values * * @param inputs Double matrix with all inputs of all observations * * @return double[] Matrix indicating the output of each class * of the observation * </p> */ public double[][] rawOutputs(double [][]inputs){ // Obtained outputs double obtained[][] = new double[outputLayer.getNofneurons()+1][]; // i-th output for(int i=0; i<obtained.length-1; i++) obtained[i] = outputLayer.getNeuron(i).operate(inputs); // 0 output obtained[obtained.length-1] = new double[inputs[0].length]; for(int j=0; j<inputs[0].length; j++) obtained[obtained.length-1][j] = 0; return obtained; } /** * <p> * Obtain the normalized softmax probabilities of classes of * one observation * * @param inputs Double array with all inputs of the observation * * @return double [] Array indicating the probability of each class * of the observation * </p> */ public double[] softmaxProbabilities(double []inputs){ // Obtain outputs double probabilities[] = rawOutputs(inputs); // Sum of exp(rawOutputs) values double expSum = 0; for(int i=0; i<probabilities.length; i++){ if(i!=probabilities.length-1) probabilities[i] = Math.exp(probabilities[i]); else probabilities[i] = 1; expSum += probabilities[i]; } // Test problems with very high outputs if(Double.isInfinite(expSum) || Double.isNaN(expSum)){ // Obtain outputs probabilities = rawOutputs(inputs); // Sum of exp(rawOutputs) values expSum = 0; for(int i=0; i<probabilities.length; i++){ probabilities[i] /= 50000.; if(i!=probabilities.length-1) probabilities[i] = Math.exp(probabilities[i]); else probabilities[i] = 1; expSum += probabilities[i]; } } // Normalize outputs for(int i=0; i<probabilities.length; i++){ probabilities[i] /= expSum; } return probabilities; } /** * <p> * Obtain the normalized softmax probabilities of classes * of a set of observations, through their inputs values * * @param inputs Double matrix with all inputs of all observations * * @return double[] Matrix indicating the probability of each class * of the observation * </p> */ public double[][] softmaxProbabilities(double [][]inputs){ // Obtain outputs double probabilities[][] = rawOutputs(inputs); // Sum of exp(rawOutputs) values double[] expSum = new double[inputs[0].length]; for(int i=0; i<expSum.length; i++) expSum[i] = 0; for(int i=0; i<probabilities.length; i++){ for(int j=0; j<inputs[0].length; j++){ if(i!=probabilities.length-1) probabilities[i][j] = Math.exp(probabilities[i][j]); else probabilities[i][j] = 1; expSum[j] += probabilities[i][j]; } } for(int j=0; j<inputs[0].length; j++){ // Test problems with very high outputs if(Double.isInfinite(expSum[j]) || Double.isNaN(expSum[j])){ // Obtain outputs probabilities = rawOutputs(inputs); for(int i=0; i<expSum.length; i++) expSum[i] = 0; // Sum of exp(rawOutputs) values for(int i=0; i<probabilities.length; i++){ for(int k=0; k<inputs[0].length; k++){ probabilities[i][k] /= 50000.; if(i!=probabilities.length-1) probabilities[i][k] = Math.exp(probabilities[i][k]); else probabilities[i][k] = 1; expSum[k] += probabilities[i][k]; } } j = inputs[0].length; } } // Normalize outputs for(int i=0; i<probabilities.length; i++) for(int j=0; j<inputs[0].length; j++) probabilities[i][j] /= expSum[j]; return probabilities; } }