Software Programming

Kunuk Nykjaer

Archive for the ‘Java’ Category

Interview-question: How to find all permutations of a given word in a given text? – Java example

leave a comment »

Write a function (in Java) to find all permutations of a given word that appear in a given text. For example, for word abc and text abcxyaxbcayxycab the function should return abc, bca, cab.

Answer:
To find a permutation of a string you can use number theory.

There is a method where you can calculate a hash of a string using prime numbers. Every permutation of the same string will give the same hash value. All other string combination which is not a permutation will give some other hash value.

The hash-value is calculated by c1 * p1 + c2 * p2 + … + cn * pn
where ci is a unique value for the current char in the string and where pi is a unique prime number value for the ci char.

Here is the implementation.
Main.java

// Author: Kunuk Nykjaer
public class Main {
	final static int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 
		19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 
		73, 79, 83, 89, 97, 101, 103, 107, 109, 113 };
	
	public static void main(String[] args) {		
		final char[] text = "abcxaaabbbccyaxbcayaaaxycab"
			.toCharArray();			
		int hash = val(new char[]{'a','b','c'});					
		for (int i = 0; i < text.length - 2; i++) {
			char[] _123 = new char[]{text[i],text[i+1],text[i+2]};			
			if(val(_123)==hash){
				System.out.println(new String(_123) );		
			}
		}
	}	
	static int p(char c) {
		return primes[(int)c - (int)'a'];
	}	
	static int val(char[] cs) {
		return 
		p(cs[0])*(int)cs[0] + p(cs[1])*(int)cs[1] + p(cs[2])*(int)cs[2];
	}
}

The output is: abc bca cab

Reference:
http://stackoverflow.com/questions/10727118/how-to-find-all-permutations-of-a-given-word-in-a-given-text

Written by kunuk Nykjaer

May 25, 2012 at 1:20 pm

Posted in Algorithm, Java

Tagged with

Mario AI EANN (evolutionary artifical neural network)

leave a comment »

I implemented a hybrid of GA and NN for an agent which plays Mario.
Training method with Genetic algorithm using a NN as a candidate in the population.
A mario framework game is provided by http://marioai.com where you get environment information, and you apply actions to the agent.

Here are two videos of my agent. I didn’t really manage to make it a generalized agent (performs good on unseen levels) but it manage well on levels which is has been trained for (over-fitting).

Below the screen is the input to the NN
Two matrix’s, one with levelscene (5×5), the other with enemies (5×5)
And then some states:
isOnGround, canJump, canShoot, marioMode, blockInFront?, enemyInFront?, pitInFront?
Outputs are: jump, left, right, fire/speed

Input 7, no matrix

Input 57, 5×5 matrix

NN topology
one hidden layer with size 20
Total outputs: 4

———-
Training method:
Fitness is distance passed + 1024 win bonus
Population 100
Generations: until level completed or maxloop is exceeded
Tournament selection
Elitism 20% no steady state
Gaussian mutation 2%
Montana uniform crossover

Written by kunuk Nykjaer

December 16, 2010 at 4:00 pm

Hybrid AI example with Java, TicTacToe Reinforcement-Learning and NN

with 2 comments

Training an AI player for the Tic Tac Toe game.
A simple example combining Reinforcement learning with Neural network.
I want to train the AI player to be able to beat an opponent which plays randomly.

The training method is simple.
The AI also plays randomly and after the game finishes A positive reward is given if it wins or a negative reward it if it looses.

The input size for the NN is 18 for the pieces on the board, which represent the state. Hidden layer is also 18.
9 for the AI pieces and 9 for opponents pieces. A 0 value is for no piece and 1 is a piece at the index. The output size is 9. The max value of the values is the preferred action. The back propagation is only for one output neuron, the chosen action.

Because I don’t know the next state for the Q-learning, the states are ‘delayed’ in the Q-learning algorithm.
It uses prev state and current state instead.

Winning results after 70.000 training games:
1000 games played.

Random starts
Hero (ai) = 616
Villain = 304
Draw = 80

Villain starts
Hero (ai) = 475
Villain = 449
Draw = 76

Hero starts
Hero (ai) = 807
Villain = 109
Draw = 84

Eclipse project download url options
Remote download:
http://www.mediafire.com/file/q4mh0lzomltdl8r/HybridRLNN_TicTacToe.zip
Local download, but rename the doc file to a zip file
hybridrlnn_tictactoe-zip.doc

Written by kunuk Nykjaer

October 24, 2010 at 2:28 pm

Hybrid AI example with Java Genetic algo and NN

leave a comment »

This simple example combines Genetic algo with Neural network.
We train the xor by using the weights as the chromosome. The population is candidates of NN.
The fitness function is (1/sumOfSquaredErrors).
The NN has 2 inputs, 2 hidden and 1 output.

After 1000 evolutions, the candidates has the ‘correct’ weights. The back propagation is not used for the NN.

This is a global search. Using only NN is local search, which might get stuck in a local minimum.

Hybrid.java

import java.util.*;

public class Hybrid {

	LinkedList<NN> population = new LinkedList<NN>();
	final static int populationSize = 100;
	static Random rand = new Random();

	public Hybrid() {
		for (int i = 0; i < populationSize; i++) {
			NN c = new NN();
			population.add(c);
		}
	}

	public static void main(String[] args) {
		long BEGIN = System.currentTimeMillis();

		Hybrid h = new Hybrid();
		h.run(1000); // evolutions

		long END = System.currentTimeMillis();
		System.out.println("Time: " + (END - BEGIN) / 1000.0 + " sec.");
	}

	void run(int evolutions) {
		int count = 0;
		System.out.println("Optimal fitness value >= " + (1 / 0.001));
		System.out.println("Fitness random init");
		print();

		while (count < evolutions) {
			count++;
			produceNextGen();
		}

		System.out.println("\nFitness Result after evolutions " + evolutions);
		print();

		System.out.println("First candidate test print");
		NN nn = population.getFirst();
		nn.printAllWeights();
		System.out.println("sumSquaredErrors = " + (1 / nn.fitness()));
		nn.resultPrint();
	}

	void print() {
		System.out.println("-- print");
		for (NN c : population) {
			System.out.println(c);
		}
	}

	/**
	 * Selection strategy: Tournament method Replacement strategy: steady state
	 * find 4 random in population not same let 2 fight, and 2 fight the winners
	 * makes 2 children
	 */
	void produceNextGen() {
		LinkedList<NN> newpopulation = new LinkedList<NN>();
		while (newpopulation.size() < populationSize) {
			int size = population.size();
			int i = rand.nextInt(size);
			int j, k, l;
			j = k = l = i;
			while (j == i)
				j = rand.nextInt(size);
			while (k == i || k == j)
				k = rand.nextInt(size);
			while (l == i || l == j || k == l)
				l = rand.nextInt(size);

			NN c1 = population.get(i);
			NN c2 = population.get(j);
			NN c3 = population.get(k);
			NN c4 = population.get(l);

			double f1 = c1.fitness();
			double f2 = c2.fitness();
			double f3 = c3.fitness();
			double f4 = c4.fitness();

			NN w1, w2;

			if (f1 > f2)
				w1 = c1;
			else
				w1 = c2;
			if (f3 > f4)
				w2 = c3;
			else
				w2 = c4;

			NN child1, child2;

			// Method uniform crossover
			NN[] childs = newChilds(w1, w2);
			child1 = childs[0];
			child2 = childs[1];

			double mutatePercent = 0.01;
			boolean m1 = rand.nextDouble() <= mutatePercent;
			boolean m2 = rand.nextDouble() <= mutatePercent;

			if (m1)
				mutate(child1);
			if (m2)
				mutate(child2);

			boolean isChild1Good = child1.fitness() >= w1.fitness();
			boolean isChild2Good = child2.fitness() >= w2.fitness();

			newpopulation.add(isChild1Good ? child1 : w1);
			newpopulation.add(isChild2Good ? child2 : w2);
		}

		population = newpopulation;
	}

	void mutate(NN c) {
		int i = rand.nextInt(NN.SIZE);
		double range = getRandom() * 2; // range [-1;1[ * 2
		c.chromosome[i] = c.chromosome[i] + range;
		c.setChromosome(c.chromosome); // update
	}

	double getRandom() {
		return (rand.nextDouble() * 2) - 1; // [-1;1[
	}

	// Uniform crossover
	static NN[] newChilds(NN c1, NN c2) {
		NN child1 = new NN();
		NN child2 = new NN();

		double[] chromosome1 = new double[NN.SIZE];
		double[] chromosome2 = new double[NN.SIZE];

		for (int i = 0; i < NN.SIZE; i++) {
			boolean b = rand.nextDouble() >= 0.5;
			if (b) {
				chromosome1[i] = c1.chromosome[i];
				chromosome2[i] = c2.chromosome[i];
			} else {
				chromosome1[i] = c2.chromosome[i];
				chromosome2[i] = c1.chromosome[i];
			}
		}
		child1.setChromosome(chromosome1);
		child2.setChromosome(chromosome2);

		return new NN[] { child1, child2 };
	}
}

NN.java

import java.util.*;

public class NN {
	
	Random rand = new Random();

	// Inputs for xor problem
	final float inputs[][] = { { 1, 1 }, { 1, 0 }, { 0, 1 }, { 0, 0 } };
	// Corresponding outputs
	final float expectedOutputs[][] = { { 0 }, { 1 }, { 1 }, { 0 } };
	double resultOutputs[][] = { { -1 }, { -1 }, { -1 }, { -1 } };
	double output[];

	final int INPUT=0;
	final int HIDDEN=1;
	final int OUTPUT=2;
	
	final static int SIZE = 9; // 2 2 1 layers, gives 9 weights total
	public double[] chromosome = new double[SIZE];

	final ArrayList<Neuron> inputLayer = new ArrayList<Neuron>();
	final ArrayList<Neuron> hiddenLayer = new ArrayList<Neuron>();
	final ArrayList<Neuron> outputLayer = new ArrayList<Neuron>();
	final Neuron bias = new Neuron();
	final static int layers[] = { 2, 2, 1 }; // input, hidden, output
	final static int randomWeightMultiplier = 30;

	float learningRate = 1f;
	float momentum = 0.9f;

	public NN() {		
				
		// create all Neurons and connections
		// connections are created in the neuron class
		for (int i = 0; i < layers.length; i++) {
			if (i == INPUT) { // input layer
				for (int j = 0; j < layers[i]; j++) {
					Neuron neuron = new Neuron();
					inputLayer.add(neuron);
				}
			} else if (i == HIDDEN) { // hidden layer
				for (int j = 0; j < layers[i]; j++) {
					Neuron neuron = new Neuron();
					neuron.addInConnectionsS(inputLayer);
					neuron.addBiasConnection(bias);
					hiddenLayer.add(neuron);
				}
			}

			else if (i == OUTPUT) { // output layer
				for (int j = 0; j < layers[i]; j++) {
					Neuron neuron = new Neuron();
					neuron.addInConnectionsS(hiddenLayer);
					neuron.addBiasConnection(bias);
					outputLayer.add(neuron);
				}
			} else {
				System.out.println("!Error NeuralNetwork init");
			}
		}

		// initialize random weights
		int i = 0;
		for (Neuron neuron : hiddenLayer) {
			ArrayList<Connection> connections = neuron.getAllInConnections();
			for (Connection conn : connections) {
				double newWeight = getRandom();
				conn.setWeight(newWeight);
				chromosome[i++] = newWeight;
			}
		}
		for (Neuron neuron : outputLayer) {
			ArrayList<Connection> connections = neuron.getAllInConnections();
			for (Connection conn : connections) {
				double newWeight = getRandom();
				conn.setWeight(newWeight);
				chromosome[i++] = newWeight;
			}
		}

		// reset id counters
		Neuron.counter = 0;
		Connection.counter = 0;
	}

	// random
	double getRandom() {
		return randomWeightMultiplier * (rand.nextDouble() * 2 - 1); // [-1;1[
	}

	void setInput(float inputs[]) {
		// There is equally many neurons in the input layer as there are
		// input variables
		for (int i = 0; i < inputLayer.size(); i++) {
			inputLayer.get(i).setOutput(inputs[i]);
		}
	}

	double[] getOutput() {
		double[] outputs = new double[outputLayer.size()];
		for (int i = 0; i < outputLayer.size(); i++)
			outputs[i] = outputLayer.get(i).getOutput();
		return outputs;
	}

	/**
	 * Calculate the output of the neural network based on the input The forward
	 * operation
	 */
	void activate() {
		for (Neuron n : hiddenLayer) {
			n.calculateOutput();
		}

		for (Neuron n : outputLayer) {
			n.calculateOutput();
		}
	}

	double[] getAllWeights() {
		double[] ds = new double[SIZE];
		int i = 0;
		// weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = con.getWeight();
				ds[i++] = w;
			}
		}
		// weights for the output layer
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = con.getWeight();
				ds[i++] = w;
			}
		}

		return ds;
	}

	// chromosome
	public void setChromosome(double[] weights) {
		chromosome = weights;
		int i = 0;
		// weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = weights[i];
				con.setWeight(w);
				i++;
			}
		}
		// weights for the output layer
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = weights[i];
				con.setWeight(w);
				i++;
			}
		}
	}

	public void printAllWeights() {
		// weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = con.getWeight();
				System.out.println("n=" + n.id + " c=" + con.id + " w=" + w);
			}
		}
		// weights for the output layer
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = con.getWeight();
				System.out.println("n=" + n.id + " c=" + con.id + " w=" + w);
			}
		}
	}

	double fitness() {
		double error = 0;
		for (int p = 0; p < inputs.length; p++) {
			setInput(inputs[p]);

			activate();

			output = getOutput();
			resultOutputs[p] = output;

			for (int j = 0; j < expectedOutputs[p].length; j++) {
				double err = Math.pow(resultOutputs[p][j]
						- expectedOutputs[p][j], 2);
				error += err;
			}
		}

		return 1 / error; // error can not be 0
	}

	void resultPrint() {
		for (int p = 0; p < inputs.length; p++) {
			System.out.print("INPUTS: ");
			for (int x = 0; x < layers[INPUT]; x++) {
				System.out.print(Float.toString(inputs[p][x]) + " ");
			}

			System.out.print("EXPECTED: ");
			for (int x = 0; x < layers[OUTPUT]; x++) {
				System.out.print(Float.toString(expectedOutputs[p][x]) + " ");
			}

			System.out.print("ACTUAL: ");
			for (int x = 0; x < layers[OUTPUT]; x++) {
				System.out.print(resultOutputs[p][x] + " ");
			}
			System.out.println();
		}
	}

	@Override
	public String toString() {
		return fitness() + "";
	}
}

Connection.java

public class Connection 
{	
	double weight=0;
	double prevDeltaWeight=0; // for momentum
	double deltaWeight=0;
		
	public Neuron leftNeuron;
	Neuron rightNeuron;
	public static int counter = 0;
	public int id;
	
	public Connection(Neuron fromN, Neuron toN){
		leftNeuron = fromN;
		rightNeuron = toN;
		id=counter;
		counter++;		
	}
	
	public double getWeight(){
		return weight;
	}
	public void setWeight(double w){
		weight = w;
	}
	
	public void setDeltaWeight(double w){
		prevDeltaWeight = deltaWeight;
		deltaWeight = w;
	}	
	
	public double getPrevDeltaWeight(){
		return prevDeltaWeight;
	}
		
	public Neuron getFromNeuron() {
		return leftNeuron;
	}
	public void setFromNeuron(Neuron fromNeuron) {
		this.leftNeuron = fromNeuron;
	}
	public Neuron getToNeuron() {
		return rightNeuron;
	}
	public void setToNeuron(Neuron toNeuron) {
		this.rightNeuron = toNeuron;
	}
}

Neuron.java

import java.util.ArrayList;
import java.util.HashMap;

public class Neuron 
{
	public static int counter = 0;
	public int id;
	double prevWeighted_sum;
	Connection biasConnection;
	final double bias = -1;
	double output;
	
	
	ArrayList<Connection> Inconnections = new ArrayList<Connection>();
	HashMap<Integer,Connection> connectionLookup = new HashMap<Integer,Connection>();
	
	public Neuron(){		
		id = counter;
		counter++;
	}
	
	/**
	 * Compute Sj = Wij*Aij + w0j*bias
	 * Apply activation function to get output
	 */
	public void calculateOutput(){
		double s = 0;
		for(Connection con : Inconnections){
			Neuron leftNeuron = con.getFromNeuron();
			double weight = con.getWeight();
			double a = leftNeuron.getOutput(); //output from previous layer
			
			s = s + (weight*a);
		}
		s = s + (biasConnection.getWeight()*bias);	
		output = g(s);
	}
	
	
	double g(double x) {
		return sigmoid(x);
	}

	double sigmoid(double x) {
		return 1.0 / (1.0 +  (Math.exp(-x)));
	}
	
	public void addInConnectionsS(ArrayList<Neuron> inNeurons){
		for(Neuron n: inNeurons){
			Connection con = new Connection(n,this);
			Inconnections.add(con);
			connectionLookup.put(n.getId(), con);
		}
	}
	
	public Connection getConnection(int neuronIndex){
		return connectionLookup.get(neuronIndex);
	}

	public void addInConnection(Connection con){
		Inconnections.add(con);
	}
	public void addBiasConnection(Neuron n){
		Connection con = new Connection(n,this);
		biasConnection = con;
		Inconnections.add(con);
	}
	public ArrayList<Connection> getAllInConnections(){
		return Inconnections;
	}
	
	public int getId(){
		return id;
	}
	public void setId(int i){
		id = i;
	}
	
	public double getBias() {
		return bias;
	}
	public double getOutput() {
		return output;
	}
	public void setOutput(double o){
		output = o;
	}
}

Result:

Optimal fitness value >= 1000.0
Fitness random init
– print
0.5000000009269805
0.500000232951657

Fitness Result after evolutions 1000
– print
3.3354638900410167E22
3.3354638900410167E22

First candidate test print
n=3 c=0 w=31.606277910728974
n=3 c=1 w=-50.54100092882488
n=3 c=2 w=17.775932295503686
n=4 c=3 w=49.91618475014163
n=4 c=4 w=-38.968161757863236
n=4 c=5 w=-20.253031449644787
n=5 c=6 w=55.76690734403492
n=5 c=7 w=-52.90412054261615
n=5 c=8 w=-26.253923811742883
sumSquaredErrors = 2.998083723783629E-23
INPUTS: 1.0 1.0 EXPECTED: 0.0 ACTUAL: 2.6666536854779678E-12
INPUTS: 1.0 0.0 EXPECTED: 1.0 ACTUAL: 0.9999999999997737
INPUTS: 0.0 1.0 EXPECTED: 1.0 ACTUAL: 0.9999999999960367
INPUTS: 0.0 0.0 EXPECTED: 0.0 ACTUAL: 2.6666567449509287E-12
Time: 3.411 sec.

Written by kunuk Nykjaer

October 23, 2010 at 12:09 pm

Neural network backpropagation with Java

with 3 comments

Neural network with backpropagation training xor example.
This framework supports only one hidden layer and the activation function is sigmoid.

In this example there are two inputs neurons, four neurons in hidden layers and one neuron in output layer.
The weights are initialized randomly.

NeuralNetwork.java

import java.text.*;
import java.util.*;

public class NeuralNetwork {
	static {
		Locale.setDefault(Locale.ENGLISH);
	}

	final boolean isTrained = false;
	final DecimalFormat df;
	final Random rand = new Random();
	final ArrayList<Neuron> inputLayer = new ArrayList<Neuron>();
	final ArrayList<Neuron> hiddenLayer = new ArrayList<Neuron>();
	final ArrayList<Neuron> outputLayer = new ArrayList<Neuron>();
	final Neuron bias = new Neuron();
	final int[] layers;
	final int randomWeightMultiplier = 1;

	final double epsilon = 0.00000000001;

	final double learningRate = 0.9f;
	final double momentum = 0.7f;

	// Inputs for xor problem
	final double inputs[][] = { { 1, 1 }, { 1, 0 }, { 0, 1 }, { 0, 0 } };

	// Corresponding outputs, xor training data
	final double expectedOutputs[][] = { { 0 }, { 1 }, { 1 }, { 0 } };
	double resultOutputs[][] = { { -1 }, { -1 }, { -1 }, { -1 } }; // dummy init
	double output[];

	// for weight update all
	final HashMap<String, Double> weightUpdate = new HashMap<String, Double>();

	public static void main(String[] args) {
		NeuralNetwork nn = new NeuralNetwork(2, 4, 1);
		int maxRuns = 50000;
		double minErrorCondition = 0.001;
		nn.run(maxRuns, minErrorCondition);
	}

	public NeuralNetwork(int input, int hidden, int output) {
		this.layers = new int[] { input, hidden, output };
		df = new DecimalFormat("#.0#");

		/**
		 * Create all neurons and connections Connections are created in the
		 * neuron class
		 */
		for (int i = 0; i < layers.length; i++) {
			if (i == 0) { // input layer
				for (int j = 0; j < layers[i]; j++) {
					Neuron neuron = new Neuron();
					inputLayer.add(neuron);
				}
			} else if (i == 1) { // hidden layer
				for (int j = 0; j < layers[i]; j++) {
					Neuron neuron = new Neuron();
					neuron.addInConnectionsS(inputLayer);
					neuron.addBiasConnection(bias);
					hiddenLayer.add(neuron);
				}
			}

			else if (i == 2) { // output layer
				for (int j = 0; j < layers[i]; j++) {
					Neuron neuron = new Neuron();
					neuron.addInConnectionsS(hiddenLayer);
					neuron.addBiasConnection(bias);
					outputLayer.add(neuron);
				}
			} else {
				System.out.println("!Error NeuralNetwork init");
			}
		}

		// initialize random weights
		for (Neuron neuron : hiddenLayer) {
			ArrayList<Connection> connections = neuron.getAllInConnections();
			for (Connection conn : connections) {
				double newWeight = getRandom();
				conn.setWeight(newWeight);
			}
		}
		for (Neuron neuron : outputLayer) {
			ArrayList<Connection> connections = neuron.getAllInConnections();
			for (Connection conn : connections) {
				double newWeight = getRandom();
				conn.setWeight(newWeight);
			}
		}

		// reset id counters
		Neuron.counter = 0;
		Connection.counter = 0;

		if (isTrained) {
			trainedWeights();
			updateAllWeights();
		}
	}

	// random
	double getRandom() {
		return randomWeightMultiplier * (rand.nextDouble() * 2 - 1); // [-1;1[
	}

	/**
	 * 
	 * @param inputs
	 *            There is equally many neurons in the input layer as there are
	 *            in input variables
	 */
	public void setInput(double inputs[]) {
		for (int i = 0; i < inputLayer.size(); i++) {
			inputLayer.get(i).setOutput(inputs[i]);
		}
	}

	public double[] getOutput() {
		double[] outputs = new double[outputLayer.size()];
		for (int i = 0; i < outputLayer.size(); i++)
			outputs[i] = outputLayer.get(i).getOutput();
		return outputs;
	}

	/**
	 * Calculate the output of the neural network based on the input The forward
	 * operation
	 */
	public void activate() {
		for (Neuron n : hiddenLayer)
			n.calculateOutput();
		for (Neuron n : outputLayer)
			n.calculateOutput();
	}

	/**
	 * all output propagate back
	 * 
	 * @param expectedOutput
	 *            first calculate the partial derivative of the error with
	 *            respect to each of the weight leading into the output neurons
	 *            bias is also updated here
	 */
	public void applyBackpropagation(double expectedOutput[]) {

		// error check, normalize value ]0;1[
		for (int i = 0; i < expectedOutput.length; i++) {
			double d = expectedOutput[i];
			if (d < 0 || d > 1) {
				if (d < 0)
					expectedOutput[i] = 0 + epsilon;
				else
					expectedOutput[i] = 1 - epsilon;
			}
		}

		int i = 0;
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double ak = n.getOutput();
				double ai = con.leftNeuron.getOutput();
				double desiredOutput = expectedOutput[i];

				double partialDerivative = -ak * (1 - ak) * ai
						* (desiredOutput - ak);
				double deltaWeight = -learningRate * partialDerivative;
				double newWeight = con.getWeight() + deltaWeight;
				con.setDeltaWeight(deltaWeight);
				con.setWeight(newWeight + momentum * con.getPrevDeltaWeight());
			}
			i++;
		}

		// update weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double aj = n.getOutput();
				double ai = con.leftNeuron.getOutput();
				double sumKoutputs = 0;
				int j = 0;
				for (Neuron out_neu : outputLayer) {
					double wjk = out_neu.getConnection(n.id).getWeight();
					double desiredOutput = (double) expectedOutput[j];
					double ak = out_neu.getOutput();
					j++;
					sumKoutputs = sumKoutputs
							+ (-(desiredOutput - ak) * ak * (1 - ak) * wjk);
				}

				double partialDerivative = aj * (1 - aj) * ai * sumKoutputs;
				double deltaWeight = -learningRate * partialDerivative;
				double newWeight = con.getWeight() + deltaWeight;
				con.setDeltaWeight(deltaWeight);
				con.setWeight(newWeight + momentum * con.getPrevDeltaWeight());
			}
		}
	}

	void run(int maxSteps, double minError) {
		int i;
		// Train neural network until minError reached or maxSteps exceeded
		double error = 1;
		for (i = 0; i < maxSteps && error > minError; i++) {
			error = 0;
			for (int p = 0; p < inputs.length; p++) {
				setInput(inputs[p]);

				activate();

				output = getOutput();
				resultOutputs[p] = output;

				for (int j = 0; j < expectedOutputs[p].length; j++) {
					double err = Math.pow(output[j] - expectedOutputs[p][j], 2);
					error += err;
				}

				applyBackpropagation(expectedOutputs[p]);
			}
		}

		printResult();
		
		System.out.println("Sum of squared errors = " + error);
		System.out.println("##### EPOCH " + i+"\n");
		if (i == maxSteps) {
			System.out.println("!Error training try again");
		} else {
			printAllWeights();
			printWeightUpdate();
		}
	}
	
	void printResult()
	{
		System.out.println("NN example with xor training");
		for (int p = 0; p < inputs.length; p++) {
			System.out.print("INPUTS: ");
			for (int x = 0; x < layers[0]; x++) {
				System.out.print(inputs[p][x] + " ");
			}

			System.out.print("EXPECTED: ");
			for (int x = 0; x < layers[2]; x++) {
				System.out.print(expectedOutputs[p][x] + " ");
			}

			System.out.print("ACTUAL: ");
			for (int x = 0; x < layers[2]; x++) {
				System.out.print(resultOutputs[p][x] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	String weightKey(int neuronId, int conId) {
		return "N" + neuronId + "_C" + conId;
	}

	/**
	 * Take from hash table and put into all weights
	 */
	public void updateAllWeights() {
		// update weights for the output layer
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				String key = weightKey(n.id, con.id);
				double newWeight = weightUpdate.get(key);
				con.setWeight(newWeight);
			}
		}
		// update weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				String key = weightKey(n.id, con.id);
				double newWeight = weightUpdate.get(key);
				con.setWeight(newWeight);
			}
		}
	}

	// trained data
	void trainedWeights() {
		weightUpdate.clear();
		
		weightUpdate.put(weightKey(3, 0), 1.03);
		weightUpdate.put(weightKey(3, 1), 1.13);
		weightUpdate.put(weightKey(3, 2), -.97);
		weightUpdate.put(weightKey(4, 3), 7.24);
		weightUpdate.put(weightKey(4, 4), -3.71);
		weightUpdate.put(weightKey(4, 5), -.51);
		weightUpdate.put(weightKey(5, 6), -3.28);
		weightUpdate.put(weightKey(5, 7), 7.29);
		weightUpdate.put(weightKey(5, 8), -.05);
		weightUpdate.put(weightKey(6, 9), 5.86);
		weightUpdate.put(weightKey(6, 10), 6.03);
		weightUpdate.put(weightKey(6, 11), .71);
		weightUpdate.put(weightKey(7, 12), 2.19);
		weightUpdate.put(weightKey(7, 13), -8.82);
		weightUpdate.put(weightKey(7, 14), -8.84);
		weightUpdate.put(weightKey(7, 15), 11.81);
		weightUpdate.put(weightKey(7, 16), .44);
	}

	public void printWeightUpdate() {
		System.out.println("printWeightUpdate, put this i trainedWeights() and set isTrained to true");
		// weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				String w = df.format(con.getWeight());
				System.out.println("weightUpdate.put(weightKey(" + n.id + ", "
						+ con.id + "), " + w + ");");
			}
		}
		// weights for the output layer
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				String w = df.format(con.getWeight());
				System.out.println("weightUpdate.put(weightKey(" + n.id + ", "
						+ con.id + "), " + w + ");");
			}
		}
		System.out.println();
	}

	public void printAllWeights() {
		System.out.println("printAllWeights");
		// weights for the hidden layer
		for (Neuron n : hiddenLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = con.getWeight();
				System.out.println("n=" + n.id + " c=" + con.id + " w=" + w);
			}
		}
		// weights for the output layer
		for (Neuron n : outputLayer) {
			ArrayList<Connection> connections = n.getAllInConnections();
			for (Connection con : connections) {
				double w = con.getWeight();
				System.out.println("n=" + n.id + " c=" + con.id + " w=" + w);
			}
		}
		System.out.println();
	}
}

Connection.java

import java.util.*;

public class Neuron {	
	static int counter = 0;
	final public int id;  // auto increment, starts at 0
	Connection biasConnection;
	final double bias = -1;
	double output;
	
	ArrayList<Connection> Inconnections = new ArrayList<Connection>();
	HashMap<Integer,Connection> connectionLookup = new HashMap<Integer,Connection>();
	
	public Neuron(){		
		id = counter;
		counter++;
	}
	
	/**
	 * Compute Sj = Wij*Aij + w0j*bias
	 */
	public void calculateOutput(){
		double s = 0;
		for(Connection con : Inconnections){
			Neuron leftNeuron = con.getFromNeuron();
			double weight = con.getWeight();
			double a = leftNeuron.getOutput(); //output from previous layer
			
			s = s + (weight*a);
		}
		s = s + (biasConnection.getWeight()*bias);
		
		output = g(s);
	}
	
	
	double g(double x) {
		return sigmoid(x);
	}

	double sigmoid(double x) {
		return 1.0 / (1.0 +  (Math.exp(-x)));
	}
	
	public void addInConnectionsS(ArrayList<Neuron> inNeurons){
		for(Neuron n: inNeurons){
			Connection con = new Connection(n,this);
			Inconnections.add(con);
			connectionLookup.put(n.id, con);
		}
	}
	
	public Connection getConnection(int neuronIndex){
		return connectionLookup.get(neuronIndex);
	}

	public void addInConnection(Connection con){
		Inconnections.add(con);
	}
	public void addBiasConnection(Neuron n){
		Connection con = new Connection(n,this);
		biasConnection = con;
		Inconnections.add(con);
	}
	public ArrayList<Connection> getAllInConnections(){
		return Inconnections;
	}
	
	public double getBias() {
		return bias;
	}
	public double getOutput() {
		return output;
	}
	public void setOutput(double o){
		output = o;
	}
}

Neuron.java

public class Connection {
	double weight = 0;
	double prevDeltaWeight = 0; // for momentum
	double deltaWeight = 0;

	final Neuron leftNeuron;
	final Neuron rightNeuron;
	static int counter = 0;
	final public int id; // auto increment, starts at 0

	public Connection(Neuron fromN, Neuron toN) {
		leftNeuron = fromN;
		rightNeuron = toN;
		id = counter;
		counter++;
	}

	public double getWeight() {
		return weight;
	}

	public void setWeight(double w) {
		weight = w;
	}

	public void setDeltaWeight(double w) {
		prevDeltaWeight = deltaWeight;
		deltaWeight = w;
	}

	public double getPrevDeltaWeight() {
		return prevDeltaWeight;
	}

	public Neuron getFromNeuron() {
		return leftNeuron;
	}

	public Neuron getToNeuron() {
		return rightNeuron;
	}
}

Result:

NN example with xor training
INPUTS: 1.0 1.0 EXPECTED: 0.0 ACTUAL: 0.01978605453528619
INPUTS: 1.0 0.0 EXPECTED: 1.0 ACTUAL: 0.9836399078122067
INPUTS: 0.0 1.0 EXPECTED: 1.0 ACTUAL: 0.9831299198563257
INPUTS: 0.0 0.0 EXPECTED: 0.0 ACTUAL: 0.007493158102140806

Sum of squared errors = 9.99887592864088E-4
##### EPOCH 5689

Written by kunuk Nykjaer

October 11, 2010 at 12:23 am

Follow

Get every new post delivered to your Inbox.