iris.Network.java Source code

Java tutorial

Introduction

Here is the source code for iris.Network.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package iris;

import java.util.ArrayList;
import java.util.List;
import weka.classifiers.Classifier;
import weka.core.Instance;
import weka.core.Instances;

/**
 *
 * 
 */
public class Network extends Classifier {
    // Allows for checking of the classification of the node
    Instances trainingData;
    // A network has multiple layers
    List<Layer> layers = new ArrayList<>();
    List<Integer> neuronsInEachLayer = new ArrayList<>();

    double learningRate = .001;
    // Bias input
    double bias = -1.0;
    int numIterations = 0;
    int inputCount = 0;

    @Override
    public void buildClassifier(Instances trainingSet) throws Exception {
        trainingData = trainingSet;
        // Set the number of inputs to the network to the number of attributes
        // i.e., 4 for the IRIS set
        setInputCount(trainingSet.numAttributes() - 1);

        buildNetwork(inputCount, neuronsInEachLayer);

        List<Double> values = new ArrayList<>();
        //stores the values our output layer gave us after feed forward
        List<Double> finalValues = new ArrayList<>();

        for (int i = 0; i < trainingSet.numInstances(); i++) {
            // Set values of instance
            for (int j = 0; j < trainingSet.instance(i).numAttributes() - 1; j++) {
                values.add(trainingSet.instance(i).value(j));
            }
            //gets the new values of what we calculated for the classification
            //this is probably where we want to loop x amount of times
            for (int k = 0; k < numIterations; k++) {
                getOutputs(values);
                backPropogate(trainingSet.instance(i));
            }
            values.clear(); // reset list
        }
    }

    @Override
    public double classifyInstance(Instance newInstance) throws Exception {
        List<Double> values = new ArrayList<>();
        List<Double> finalValues = new ArrayList<>();

        for (int i = 0; i < newInstance.numAttributes() - 1; i++) {
            values.add(newInstance.value(i));
        }

        finalValues = getOutputs(values);

        double maxIndex = 0;

        //sets maxIndex to the highest value we calculated, i.e., what we think
        //the classification of the flower is according to our calculations.
        for (int i = 0; i < finalValues.size(); i++) {
            if (finalValues.get(i) > finalValues.get((int) maxIndex)) {
                maxIndex = i;
            }
        }

        return maxIndex;
    }

    public Network(List<Integer> neuronsPerLayer, int numIteration) {
        neuronsInEachLayer = neuronsPerLayer;
        numIterations = numIteration;
    }

    // Network Constructor
    public void buildNetwork(int inputCount, List<Integer> neuronsInLayer) {
        // Add 1 input to account for bias
        layers.add(new Layer(neuronsInLayer.get(0), inputCount + 1));

        for (int i = 1; i < neuronsInLayer.size(); i++) {
            layers.add(new Layer(neuronsInLayer.get(i), // neuronCount
                    neuronsInLayer.get(i - 1) + 1)); // inputCount
        }
    }

    public void teach() throws Exception {
        // Loop through all instances in training set
        for (int i = 0; i < trainingData.numInstances(); i++) {
            // If classification is wrong, we need to update weights
            if (trainingData.instance(i).value(4) != classifyInstance(trainingData.instance(i))) {
                backPropogate(trainingData.instance(i));
            }
            // else do nothing
        }
    }

    // go through network and update weights accordingly
    public void backPropogate(Instance instance) throws Exception {
        // Loop through until we are happy with the classification
        // Start at the output layer and work back
        for (int i = layers.size() - 1; i >= 0; i--) {
            // Check for output layer
            if (i == layers.size() - 1) {
                // Loop through neurons in output layer
                for (int j = 0; j < neuronsInEachLayer.get(i); j++) {
                    // Set variables for weight update equation
                    double activationValue = layers.get(i).getNeuron(j).outputValue;
                    double targetValue = 0;
                    double leftValue = 0;
                    // Set node index to classifications
                    if (instance.classValue() == j) {
                        targetValue = 1;
                    }

                    // Setting error value for node
                    layers.get(i).getNeuron(j).error = activationValue * (1 - activationValue)
                            * (activationValue - targetValue);
                    double error = layers.get(i).getNeuron(j).error; // because im lazy

                    // Loop and update weights
                    for (int k = 0; k < layers.get(i).getNeuron(j).weights.size(); k++) {
                        leftValue = layers.get(i - 1).getNeuron(j).outputValue; // get the K node in the layer to the left corresponding to the weight we're changing
                        layers.get(i).getNeuron(j).setNewWeight(k,
                                (layers.get(i).getNeuron(j).getWeight(k) - (learningRate * error * leftValue))); // set new weight
                    }
                }
            }
            // Else, it's a hidden layer
            else {
                // Loop through neurons in hidden layer
                for (int j = 0; j < neuronsInEachLayer.get(i); j++) {
                    // Set variables for weight update
                    double activationValue = layers.get(i).getNeuron(j).outputValue;
                    double rightWeight = 0;
                    double rightError = 0;
                    double leftValue = 0;

                    double sumWeightsWithError = 0;
                    // Calculate Sum of rightWeights * rightError

                    for (int a = 0; a < layers.get(i + 1).neurons.size(); a++) // loop through number of neurons to the right
                    {
                        sumWeightsWithError += (layers.get(i + 1).neurons.get(a).getWeight(j)
                                * layers.get(i + 1).neurons.get(a).error);
                    }

                    // Set error at the node
                    layers.get(i).getNeuron(j).error = (activationValue * (1 - activationValue)
                            * sumWeightsWithError);
                    double error = layers.get(i).getNeuron(j).error; // because im lazy

                    // Update weights loop
                    for (int k = 0; k < layers.get(i).getNeuron(j).weights.size(); k++) {
                        //                           if (i == 0)
                        //                           {
                        //                               leftValue = layers.get(i).getNeuron(j).outputValue;
                        //                           }
                        //                           else
                        //                           {
                        leftValue = layers.get(i).getNeuron(j).outputValue;
                        //}
                        layers.get(i).getNeuron(j).setNewWeight(k,
                                layers.get(i).getNeuron(j).getWeight(k) - (learningRate * error * leftValue));
                    }
                }
            }
        }

        // End of Layers loop, update all weights in network
        // Loop through each layer
        for (int i = 0; i < layers.size(); i++) {
            // Loop through each neuron in this layer
            for (int j = 0; j < neuronsInEachLayer.get(i); j++) {
                layers.get(i).getNeuron(j).updateWeights();
            }
        }

    }

    public List<Double> getOutputs(List<Double> inputs) {
        List<Double> outputs = new ArrayList<>(inputs);

        for (Layer layer : layers) {
            addBias(outputs);

            outputs = layer.outputResult(outputs);
        }

        return outputs;
    }

    // Adds the bias to the neuron
    public void addBias(List<Double> outputs) {
        outputs.add(bias);
    }

    // Sets the bias value
    public void setBias(Double bias) {
        this.bias = bias;
    }

    // Gets the layer at parameter index
    public Layer getLayer(int index) {
        return layers.get(index);
    }

    public int getInputCount() {
        return inputCount;
    }

    public void setInputCount(int count) {
        inputCount = count;
    }
}