Skip to content

Instantly share code, notes, and snippets.

@leonaburime
Created July 22, 2014 16:31
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save leonaburime/ccffc9cf8271406f36c1 to your computer and use it in GitHub Desktop.
Neural Network implementation in Java. Uses Apache Common Math library.
package NeuralNetwork;
import org.apache.commons.lang3.*;
import org.apache.commons.math3.linear.*;
import org.apache.commons.math3.stat.StatUtils;
import javax.swing.*;
import java.util.*;
/**
* Created by Leon Aburime using IntelliJ on 7/18/2014.
**/
public class NeuralNetwork {
public double[][] xor_in = {
{0,0},
{0,1},
{1,0},
{1,1}
};
public double[] xor_out = { 0,1,1,0 };
public double[][] or_in = {
{0,0},
{0,1},
{1,0},
{1,1}
};
public double[] or_out = { 0,1,1,1 };
public int bias_value = 1;
public double learning_rate = 0.1;
public int num_iterations = 1000;
public RealMatrix input_weights;//n x m matrix of weights for inpyut layer
public RealVector hidden_layer_weights;// n x 1 number of weights for input layer
public RealVector hidden_layer_nodes;
public static void main(String[] args) {
NeuralNetwork nn = new NeuralNetwork();
//Can be changed to 'or' or 'xor'
double[][] input = nn.xor_in;
double[] output = nn.xor_out;
nn.fit( input, output );//Training the algorithm
nn.predict( input,output);//Lets see how we did
}
public static double activate(double sum){
return Math.tanh(sum);
}
public static double derivative_activate(double value){
return 1.0 - Math.pow(value, 2);
}
//Append a column of ones for biasing to our input matrix
public static RealMatrix addBiasToColumn(RealMatrix matrix, double bias_value){
int num_rows = matrix.getRowDimension();
int num_columns = matrix.getColumnDimension();
double[] bias = new double[num_rows];//Create array based on number of rows
Arrays.fill(bias, bias_value);//Fill it with our bias value
//Copy matrix and bias column into new_arr
double[][] new_arr = Arrays.copyOf(matrix.transpose().getData(), num_columns + 1);
new_arr[num_columns] = bias;
return MatrixUtils.createRealMatrix( new_arr ).transpose();
}
//Create and fill random Apache Common RandomVector of weights
public static RealVector createRandomVector(int length){
Random generator = new Random();
double[] arr = new double[length];
for(int i=0; i<length; i++) {
arr[i] = generator.nextDouble();
}
return MatrixUtils.createRealVector(arr);
}
//Create row x column matrix of random values
public static RealMatrix createRandomMatrix(int row, int column){
Random generator = new Random();
double[][] arr = new double[row][column];
for(int i=0; i<row; i++) {
for(int j=0; j<column; j++) {
arr[i][j] = generator.nextDouble();
}
}
return MatrixUtils.createRealMatrix(arr);
}
//Sample Prediction of our input so we can so we performed
private void predict(double[][] input, double[] output){
//Lets turn the input into a matrix for easier indexing
RealMatrix mat = MatrixUtils.createRealMatrix(input);
//Lets add a bias column to it
RealMatrix mat_bias = addBiasToColumn(mat, this.bias_value);
//Lets cycle through each input row and train our network
for(int i=0; i<mat.getRowDimension(); i++){
RealVector vec = mat_bias.getRowVector(i);
System.out.println("Input " + mat.getRowVector(i) + " -> Actual: " + output[i] +
" - Predicted : " + this.feedforward(vec, this.hidden_layer_nodes));
}
}
private void fit(double[][] input, double[] output){
//Lets turn our input into a matrix
RealMatrix mat = MatrixUtils.createRealMatrix(input);
//Lets turn the output into a vector
RealVector vec = MatrixUtils.createRealVector(output);
RealMatrix matrix_bias = addBiasToColumn(mat, this.bias_value);
//Lets create hidden nodes
int num_rows = matrix_bias.getRowDimension();
int num_columns = matrix_bias.getColumnDimension();
this.hidden_layer_nodes = createRandomVector( num_rows );
//Lets create our input and hidden layer weights
this.input_weights = createRandomMatrix(num_rows, num_columns);
this.hidden_layer_weights = createRandomVector(num_rows );
for(int i=0; i< this.num_iterations; i++){
for(int j=0; j< num_rows; j++) {
RealVector row_input = matrix_bias.getRowVector(j);
//Calculate the guess of our 'feedforward' summation algorithm
double guess = this.feedforward(row_input, this.hidden_layer_nodes),
correct = output[j],
error = correct - guess;
//Now lets backpropagate to find out the error
this.backpropagate(row_input, guess, error);
//Lets print out the error to see if its decreasing along the way
if( i % 100 == 0 ){
System.out.println("Error(Input " + j + "): " + 0.5 * Math.pow(error,2));
}
}
}
}
private double feedforward(RealVector input, RealVector hidden_nodes){
//Step 1: Multiply the input weights by the inputs, then store them in each hidden node
for(int i=0; i<hidden_nodes.getDimension(); i++ ){
double sum = StatUtils.sum(this.input_weights.getRowVector(i).ebeMultiply(input).toArray());
hidden_nodes.setEntry( i, activate(sum) );
}
double guess = 0, total = 0;
//Step 2: Lets multiply the hidden nodes weights to the hidden weight inputs
total += StatUtils.sum( this.hidden_layer_weights.ebeMultiply(hidden_nodes).toArray());
//Now we take the hyperbolic tangent to cap it between -1 and 1 for our guess
guess =activate(total);
return guess;
}
private void backpropagate(RealVector input, double guess, double error){
double[] delta_hidden_nodes =new double[this.hidden_layer_nodes.getDimension()];
//Step 1: Lets get the error of our guess
double delta_output = error * derivative_activate(guess);
//Step 2: Adjust weights for hidden layer -> output
RealVector factor = this.hidden_layer_nodes.mapMultiply(this.learning_rate * delta_output);
this.hidden_layer_weights = this.hidden_layer_weights.add(factor);
//Step 3: Lets get the hidden layer errors
for(int i=0; i<this.hidden_layer_nodes.getDimension(); i++){
double out = this.hidden_layer_nodes.getEntry(i),
val = derivative_activate(out)*delta_output*this.hidden_layer_weights.getEntry(i);
delta_hidden_nodes[i] = val;
}
//Step 4: Lets change the weights going into the hidden layer
for(int i=0; i<this.input_weights.getRowDimension(); i++){
for(int j=0; j<this.input_weights.getColumnDimension(); j++){
double current_value = this.input_weights.getEntry(i, j);
double new_value = this.learning_rate*input.getEntry(j)*delta_hidden_nodes[i] + current_value;
this.input_weights.setEntry(i,j, new_value );
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment