- Home /
Multiple array variable
Hello! I am trying to make my own Artificial Neural Network like this guy did here: Youtube Video It is in Finnish, so no need to watch.
So, his "brain" code was almost 1000 lines long, and it was pretty hard to add more layers and neurons. So I wanted to make more expandable one.
This is a part of original one
// Inputs / Inputit
private float I1, I2, I3;
// Outputs / Outputit
private float Sum_01, Sum_02;
// Mutation rate / Mutaation määrä
public int mutationRate = 5;
//weights ----------------------------------------------------------------------------
//Input1
float W_I1_L1N1;
float W_I1_L1N2;
float W_I1_L1N3;
float W_I1_L1N4;
float W_I1_L1N5;
And this is mine in works.
// Inputs / Inputit
float[] I = new float[3];
// Outputs / Outputit
float[] Sum_ = new float[2];
// Layer amount / Layereiden määrä
[SerializeField]
private int LayerAmount = 2;
// Neuron count for each layer / Neuroni määrä jokaiselle layerille
[SerializeField]
private int NeuronAmountForEachLayer = 5;
// Mutation rate / Mutaation määrä
[SerializeField]
private int mutationRate = 5;
Now the problem is things like these
void Start(){
// Start generation and mutation / Alkugenerointi ja mutaatio
//Mutaatio Input1
if (Random.Range (0, mutationRate) == 1 || simulationStart == true) {
W_I1_L1N1 = Random.Range (-1.0f, 1.0f);
}
}
And I'd like to use it like this (if it even works as intended)
void Start(){
// Start generation and mutation / Alkugenerointi ja mutaatio
//Mutaatio Input1
if (Random.Range (0, mutationRate) == 1 || simulationStart == true) {
foreach (float i in I) {
foreach(int l in LayerAmount){
foreach(int n in NeuronAmountForEachLayer){
W_I[i]_L[l]N[n] = Random.Range (-1.0f, 1.0f);
}
}
}
}
}
( W_I1_L1N1 means Weight of Input 1 to Layer 1's Neuron 1 )
I basically want to use better way of setting these, than doing it for every single one.
It's hard to explain ANN.
I'm currently working on it, but I'm not sure about the structure. Do neurons have inputs and outputs? And you call these weights?
Never$$anonymous$$d, I was thinking too much about it.
Answer by Bunny83 · Jun 21, 2016 at 03:11 PM
This approach for a neuronal network is not very flexible. I just wrote a simple NeuronalNetwork framework which is fully scalable. You can create a neuronal network with as many hidden layers you like in any configuration with a single line of code. The only thing that's fixed is that each node of one layer is connected to each node of the next layer.
NeuronalNetwork network = new NeuronalNetwork(inputCount, outputCount, hiddenLayer1, hiddenLayer2, ...);
Some examples:
// 2 inputs, 1 outputs, 3 neurons in the first hidden layer, 5 in the second hidden layer and 2 in the third.
network = new NeuronalNetwork(2, 1, 3, 5, 2);
// 4 inputs, 2 outputs, 5 neurons in the hidden layer
network = new NeuronalNetwork(4, 2, 5);
You can set the inputs with SetInput and read the outputs with GetOutput. Alternatively you can access the input and output layers directly. You have to call "Calculate()" after you set the inputs in order to calculate the output values.
You can easily clone a NeuronalNetwork with the copy constructor:
NeuronalNetwork clone = new NeuronalNetwork( source );
This will duplicate the whole network and copy the weights and settings over. You can call the Mutate method in order to randomly mutate the network. I implemented this the same way as in the source code you've linked.
Note: When Mutate is called with a MutationRate of "-1" it will randomize all stats. This is automatically called for new networks.
At the moment it doesn't have any kind of backpropagation or weight adjustments since the original code only depends on random evolution.
edit
I just implemented two ways of serializing a "NeuronalNetwork":
XML
Binary
To serialize a network as an XML string you would do this:
XML
NeuronalNetwork network;
var doc = new System.Xml.XmlDocument(); // new XML document
var nets = doc.AppendChild(doc.CreateElement("Networks")); // add root node
network.Serialize(nets); // serialize the network into the root node
// the following is just converting the XML document into a string
var sb = new System.Text.StringBuilder();
using (var writer = new System.IO.StringWriter(sb))
doc.Save(writer);
string XMLtext = sb.ToString();
To deserialize you would do:
var doc = new System.Xml.XmlDocument();
doc.LoadXml(text);
var nets = doc["Networks"]; // root node
var node = nets.ChildNodes.Item(0); // get the actual network node
NeuronalNetwork network = new NeuronalNetwork(node);
To serialize it as a byte array you would do:
Binary
NeuronalNetwork network;
byte[] data;
using (var stream = new System.IO.MemoryStream())
using (var writer = new System.IO.BinaryWriter(stream))
{
network.Serialize(writer);
data = stream.ToArray();
}
To deserialize:
NeuronalNetwork network;
byte[] data;
using (var stream = new System.IO.MemoryStream(data))
using (var reader = new System.IO.BinaryReader(stream))
{
network = new NeuronalNetwork(reader);
}
Of course instead of a MemoryStream you could directly use a file stream if you want to read / write to a file.
Likewise the XmlDocument has a Load and Save method which also works with IO streams.
I should add that i wrote this from scratch without testing it. It's even hard to test a neural network. I just had some spare time.
First i thought to implement a seperate input neuron, as inputs don't do any calculations themselfs and don't have any input neurons, but it was easier to just ignore them on input neurons. In addition output neurons don't have an activation function. Their value is always just the weighted sum of all inputs (inputs for the output neurons is the last hidden layer). Their type is defined by the "type" variable of each layer / neuron.
Also note the NeuronalNetwork class as well as the NeuronLayer class are just management classes. The actual network only consists of Neurons. They directly link each other. Those two classes just simplify the creation, linking and usage of the network.
Woah, this was unexcepted and amazing. I am currently testing it, and its working perfectly (Except there is "RandomRangeInt is not allowed to be called from $$anonymous$$onoBehaviour constructor" error, does not prevent Play mode). It's able to sense food distance and react to it (It only keeps the food in its sight however, not moving close to eat it).
I unaccepted the $$anonymous$$avina's answer, ins$$anonymous$$d I upped both answers from Bunny and $$anonymous$$avina, since they are both good.
Well, you should initialize your neuronal network inside Awake or Start. Well, i could make the class independent from Unity's Random class and simply use System.Random ins$$anonymous$$d, then this wouldn't be a problem.
However it could cause other problems when you initialize many instances at the same time there would be a change that they all get the same values since the random generator would be initialized by the current date / time. A seperate random singleton class could be a solution, but it must be thread safe.
A class like this could be used ins$$anonymous$$d of Unity's Random class:
public static class $$anonymous$$yRandom
{
private static System.Random rnd = new System.Random();
public static int Range(int a$$anonymous$$in, int a$$anonymous$$ax)
{
lock(rnd) return rnd.Next(a$$anonymous$$in, a$$anonymous$$ax);
}
public static float Range(float a$$anonymous$$in, float a$$anonymous$$ax)
{
return Value * (a$$anonymous$$ax-a$$anonymous$$in) + a$$anonymous$$in;
}
public static float Value
{
get { lock(rnd) return (float)rnd.NextDouble(); }
}
}
It creates exactly one instance of the System.Random class which is shared by everyone. Note it should not be used in situations where you need a lot random numbers (1000+) very frequently as the locking has some overhead. It's best to avoid multithread access and just use Unity's Random class
Yes, I am mutating with same rate. It's just that they spin in circle, so they cannot get food and children (Children are spawned when score is greater than 30, single ball of food gives 10 score). The ones that don't spin just freeze in their place when they see food (Not completely frozen, twitching).
I know how to connections go, the original code has different connections between Layer 1 and 2.
I just found a small error in my code ^^. The $$anonymous$$utate function of the NeuronalNetwork doesn't mutate the output layer. Adding this line:
output.$$anonymous$$utate(a$$anonymous$$utationRate);
at the end of the $$anonymous$$utate function should solve the problem.
I don't seen why the original code would have different connections between Layer 1 and 2... The original code also links all neurons from Layer1 to all neurons of Layer2.
I modified the example project from that video link and seperated the input (raycast) and the output (translate / rotate) as well as the whole score logic into a seperate class. That way i can simply exchange the "brain" class with my own. I initialize the whole scene procedurally and spawn 64 of each type and about 1000 food initially. I also increased the scoring so they live a bit longer than 10 sec. This is the result after about 800 sec (~13 $$anonymous$$). I added some stats on the left.
Yep, that fixed the error I had when spawning children.
Answer by mwnDK1402 · Jun 19, 2016 at 10:23 PM
Not sure if this is what you're looking for:
// Create the jagged array
float[][] input = new float[LayerAmount][];
for (int i = 0; i < LayerAmount; i++)
{
input[i] = new float[NeuronAmountForEachLayer];
}
// Randomize the values
for (int i = 0; i < LayerAmount; i++)
{
for (int j = 0; j < NeuronAmountForEachLayer; j++)
{
input[i][j] = Random.Range(-1f, 1f);
}
}
They're called jagged arrays: https://msdn.microsoft.com/da-dk/library/2s05feca.aspx
Not quite, maybe if you know ANN structure? ANN Wikipedia The picture there shows what it is like, lines are weights.
In the original code, every weight had own randomisation ( 3rd code block in my question )
The layers where neurons are, are called hidden layers. I want to add more layers, with each having same amount of neurons, given by NeuronAmountForEachLayer.
I want this, since having more layers (and neurons) makes the ANN able to learn much more complicated things, but slower.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Loading spawned prefabs upon connecting to server? 1 Answer
Re-hosting a Match in unity creates a bunch of random errors 1 Answer
ClientRPC not getting sent. 0 Answers
Distribute terrain in zones 3 Answers