1
0
mirror of https://github.com/fazo96/AIrium.git synced 2025-01-10 09:34:20 +01:00

added some docs, refactored some code

This commit is contained in:
Enrico Fasoli 2015-07-01 20:31:55 +02:00
parent 3181272cae
commit 89edaf5b84
5 changed files with 136 additions and 59 deletions

View File

@ -4,14 +4,7 @@
<auxiliary> <auxiliary>
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group> <group/>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/NeuralConnection.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/com/mygdx/game/Game.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/Neuron.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/Creature.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/Brain.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/World.java</file>
</group>
</open-files> </open-files>
<editor-bookmarks lastBookmarkId="0" xmlns="http://www.netbeans.org/ns/editor-bookmarks/2"/> <editor-bookmarks lastBookmarkId="0" xmlns="http://www.netbeans.org/ns/editor-bookmarks/2"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">

View File

@ -76,7 +76,7 @@ public class World {
//graveyard.sort(creatureComp); //graveyard.sort(creatureComp);
int x = 0; int x = 0;
for (Creature c : graveyard) { for (Creature c : graveyard) {
c.getBrain().mutate(5f); c.getBrain().getMutatedCopy(5f);
if (x < creatPerGen) { if (x < creatPerGen) {
c.setHp(100); c.setHp(100);
creatures.add(c); creatures.add(c);

View File

@ -1,9 +1,9 @@
package logic.neural; package logic.neural;
import com.mygdx.game.Log; import com.mygdx.game.Log;
import java.util.ArrayList;
/** /**
* Represents a virtual brain
* *
* @author fazo * @author fazo
*/ */
@ -12,73 +12,119 @@ public class Brain {
public static final float bias = 0.5f; public static final float bias = 0.5f;
private Neuron[][] neurons; private Neuron[][] neurons;
/**
* Create a new brain with a random map (mind) with given number of neurons
*
* @param nInputs the number of input neurons (at least 1)
* @param nOutputs the number of output neurons (at least 1)
* @param hiddenLayers how many hidden layers of neurons (at least 1)
* @param neuronsPerHiddenLayer how many neurons per hidden layer (at least
* 1)
*/
public Brain(int nInputs, int nOutputs, int hiddenLayers, int neuronsPerHiddenLayer) { public Brain(int nInputs, int nOutputs, int hiddenLayers, int neuronsPerHiddenLayer) {
// Prepare brain map
neurons = new Neuron[hiddenLayers + 2][]; neurons = new Neuron[hiddenLayers + 2][];
populate(nInputs, nOutputs, hiddenLayers, neuronsPerHiddenLayer);
}
private void populate(int nInputs, int nOutputs, int hiddenLayers, int neuronsPerHiddenLayer) {
// Create input neurons
neurons[0] = new Neuron[nInputs]; neurons[0] = new Neuron[nInputs];
for (int i = 0; i < nInputs; i++) { neurons[hiddenLayers + 1] = new Neuron[nOutputs];
neurons[0][i] = new Neuron(0, bias, this);
Log.log(Log.DEBUG, "Adding Input Layer Neuron " + (i + 1));
}
// popiulate hidden layers
for (int i = 0; i < hiddenLayers; i++) { for (int i = 0; i < hiddenLayers; i++) {
neurons[i + 1] = new Neuron[neuronsPerHiddenLayer]; neurons[i + 1] = new Neuron[neuronsPerHiddenLayer];
for (int j = 0; j < neuronsPerHiddenLayer; j++) { }
// Randomize brain
initialize();
}
/**
* Create a new brain using given brain map (mind)
*
* @param brainMap the brain map (mind) to use
*/
public Brain(float[][][] brainMap) {
neurons = new Neuron[brainMap.length][];
for (int i = 0; i < brainMap.length; i++) { // for each layer
neurons[i] = new Neuron[brainMap[i].length];
for (int j = 0; j < brainMap[i].length; j++) { // for each neuron
neurons[i][j] = new Neuron(i, bias, this, brainMap[i][j]);
}
}
}
/**
* Apply a new brain map (mind) to this brain
*
* @param brainMap the new brain map to apply
*/
public void remap(float[][][] brainMap) {
for (int i = 0; i < brainMap.length; i++) { // for each layer
for (int j = 0; j < brainMap[i].length; j++) { // for each neuron
if (neurons[i][j] == null) {
neurons[i][j] = new Neuron(j, bias, this, brainMap[i][j]);
} else {
neurons[i][j].setWeights(brainMap[i][j]);
}
}
}
}
/**
* Populate the brain with brand new random neurons
*/
private void initialize() {
// init hidden layers
for (int i = 0; i < neurons.length; i++) {
for (int j = 0; j < neurons[i].length; j++) {
// create neuron // create neuron
Neuron n = new Neuron(i + 1, bias, this); Neuron n = new Neuron(i, bias, this);
neurons[i + 1][j] = n; neurons[i][j] = n;
Log.log(Log.DEBUG, "Adding Hidden Layer " + (i + 1) + " Neuron " + (j + 1)); Log.log(Log.DEBUG, "Adding Layer " + (i + 1) + " Neuron " + (j + 1));
} }
} }
// populate output layer
neurons[hiddenLayers + 1] = new Neuron[nOutputs];
for (int i = 0; i < nOutputs; i++) {
// add neuron
Neuron n = new Neuron(hiddenLayers + 1, bias, this);
neurons[hiddenLayers + 1][i] = n;
Log.log(Log.DEBUG, "Adding Output Layer Neuron " + (i + 1));
}
}
private float randWeight() {
return (float) Math.random() * 5 - 2.5f;
} }
/**
* Give some input to the brain
*
* @param values the array of input. Its length must match the number of
* input neurons of this brain
*/
public void input(float[] values) { public void input(float[] values) {
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
neurons[0][i].setOutput(values[i]); neurons[0][i].setOutput(values[i]);
} }
clearCache();
} }
/**
* Compute output of the brain starting from given input
*
* @return an array as long as the number of output neurons, containing the
* result
*/
public float[] compute() { public float[] compute() {
clearCache(); //clearCache(); // unnecessary if already called when changing inputs
float[] res = new float[neurons[neurons.length - 1].length]; float[] res = new float[neurons[neurons.length - 1].length];
for (int i = 0; i < neurons[neurons.length - 1].length; i++) { for (int i = 0; i < neurons[neurons.length - 1].length; i++) {
Neuron n = neurons[neurons.length - 1][i]; res[i] = neurons[neurons.length - 1][i].compute();
if (n != null) {
res[i] = n.compute();
}
} }
return res; return res;
} }
public void map(float[][][] map) { /**
// Populate with new neurons * Input some values (see input function) and then compute the results.
for (int j = 0; j < map.length; j++) { *
for (int i = 0; i < map[j].length; i++) { * @param values
if (map[j] == null || map[i] == null) { * @return the results of the neural network
continue; */
} public float[] compute(float[] values) {
neurons[j][i] = new Neuron(j, bias, this); input(values);
neurons[j][i].setWeights(map[j][i]); return compute();
}
}
} }
/**
* Get a brainMap that represents this brain's mind
*
* @return a tridimensional floating point number array representing a full
* mind
*/
public float[][][] getMap() { public float[][][] getMap() {
float[][][] res = new float[neurons.length][neurons[1].length][neurons[1].length]; float[][][] res = new float[neurons.length][neurons[1].length][neurons[1].length];
for (int i = 0; i < neurons.length; i++) // layers for (int i = 0; i < neurons.length; i++) // layers
@ -94,7 +140,13 @@ public class Brain {
return res; return res;
} }
public float[][][] mutate(float mutationFactor) { /**
* Get a map of this brain's mind.. with a mutation
*
* @param mutationFactor the highest this number, the bigger the mutation
* @return a mutated brain map of this brain's mind
*/
public float[][][] getMutatedMap(float mutationFactor) {
float[][][] res = new float[neurons.length][][]; float[][][] res = new float[neurons.length][][];
for (int i = 0; i < neurons.length; i++) // layers for (int i = 0; i < neurons.length; i++) // layers
{ {
@ -107,6 +159,10 @@ public class Brain {
return res; return res;
} }
/**
* Empties the neurons' cache. Needs to be called after changing brain
* inputs or before computing the result.
*/
private void clearCache() { private void clearCache() {
for (int i = 1; i < neurons.length; i++) { for (int i = 1; i < neurons.length; i++) {
for (int j = 0; j < neurons[i].length; j++) { for (int j = 0; j < neurons[i].length; j++) {
@ -115,6 +171,11 @@ public class Brain {
} }
} }
/**
* Returns an array with pointers to all this brain's neurons.
*
* @return bidimensional array with first index representing the layer.
*/
public Neuron[][] getNeurons() { public Neuron[][] getNeurons() {
return neurons; return neurons;
} }

View File

@ -57,8 +57,6 @@ public class Neuron {
} }
float a = bias * -1; // activation float a = bias * -1; // activation
for (int i = 0; i < weights.length; i++) { for (int i = 0; i < weights.length; i++) {
//if(brain == null) System.out.println("BRAINS NULL"); else if(brain.getNeurons() == null) System.out.println("NEURONS NULL");
//System.out.println(Arrays.toString(brain.getNeurons()));
if (cache.has(i)) { if (cache.has(i)) {
try { try {
return cache.get(i); return cache.get(i);
@ -97,7 +95,7 @@ public class Neuron {
this.bias = bias; this.bias = bias;
} }
public boolean isIsInputNeuron() { public boolean isInputNeuron() {
return isInputNeuron; return isInputNeuron;
} }
@ -115,6 +113,8 @@ public class Neuron {
public void setWeights(float[] weights) { public void setWeights(float[] weights) {
this.weights = weights; this.weights = weights;
// Changing the neuron makes the cache invalid
clearCache();
} }
public void clearCache() { public void clearCache() {

View File

@ -1,11 +1,7 @@
/*
* 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 logic.neural; package logic.neural;
/** /**
* Used by neurons to cache inputs for faster NN evaluation performance.
* *
* @author fazo * @author fazo
*/ */
@ -14,17 +10,35 @@ public class NeuronCache {
private float[] cache; private float[] cache;
private boolean[] validity; private boolean[] validity;
/**
* Create a new empty input cache with given size.
*
* @param size how many inputs the requiring neuron has.
*/
public NeuronCache(int size) { public NeuronCache(int size) {
cache = new float[size]; cache = new float[size];
validity = new boolean[size]; validity = new boolean[size];
clear(); clear();
} }
/**
* Put a value in the cache.
*
* @param index the index of the value
* @param value the value itself
*/
public void put(int index, float value) { public void put(int index, float value) {
validity[index] = true; validity[index] = true;
cache[index] = value; cache[index] = value;
} }
/**
* Read a value from the cache.
*
* @param index the index of the value
* @return the value required
* @throws Exception if value not stored or declared invalid
*/
public float get(int index) throws Exception { public float get(int index) throws Exception {
if (validity[index]) { if (validity[index]) {
return cache[index]; return cache[index];
@ -33,10 +47,19 @@ public class NeuronCache {
} }
} }
/**
* Returns true if required value is present and valid in the cache.
*
* @param index which value to check
* @return true if has given value
*/
public boolean has(int index) { public boolean has(int index) {
return validity[index]; return validity[index];
} }
/**
* Clears cache.
*/
public void clear() { public void clear() {
for (int i = 0; i < cache.length; i++) { for (int i = 0; i < cache.length; i++) {
validity[i] = false; validity[i] = false;