Sunday, November 29, 2009

Multiple Calibrations

Came across a very annoying bug. Basically, it's printing the wrong numbers for the fitness of each sweeper on the epoch, depending on the speed of the playback. The strange thing is that changing the speed at which the thread runs the updates shouldn't really have any effect whatsoever, so I'm at a loss for what the problem is.

It doesn't seem to have any effect on the actual running of the program, it just displays the fitnesses wrong. I'll figure it out eventually, but it'll be a lot of trial and error.

UPDATE:
I figured it out faster than I expected. It turns out that I was actually not moving the mines when I turned the graphics off (to speed up the running time), which meant that I was calibrating the sweepers for non-moving mines, and then throwing them into a situation with moving ones.

This actually brings up an interesting process which would be to calibrate the networks for something similar to what you want first in order to give them the right impression. In this case, it was training them not to go with the movement of the mines, because the mines were standing still. Which was the reason they didn't go with the flow as I expected. The moment I fixed the "bug" they went back to following the flow.

I've added in moving mines, as opposed to the generic stationary ones. This is helpful because it eliminates a problem I was having before where the sweepers would just not move at all. It's ironic, because the program was telling the sweepers not to hit the mines, so the best way they evolved to do that was to simply not move at all.

With the addition of moving mines, I no longer have to force them to move, because they are moving the entire time (relative to the mines at least).

With this, my tests for factoring in distance based avoidance is actually starting to work, without the need for a new input. (Which is actually not what I had intended, since I was expecting to be testing how easy I could manipulate the neural network's links without achieving unintended consequences).

Elitism

I've been messing around with some of the starting parameters, namely numElite and numCopiesElite. Basically what they control are the copies of the most fittest genes at the end of the life cycle. When a new generation is about to be created, the program take an amount of the most fittest genes, numElite, and copies them into the new generation with numCopiesElite copies. This controls how much of an effect the previous generation had on the new one. If the numElite is 5 and there are a total of 10 sweepers in the generation, it would take the top five and (assuming numCopiesElite is 1) would copy them into the new generation.

This is necessary for obvious reasons so that the most fit genes actually continue over rather than dying out. It can also be a hazard, if the number is too high. If the previous generation was bad overall, the most fittest genes wouldn't necessarily be accomplishing the task; they would just be not, not accomplishing the task better than the others. By taking too many you lower the remaining spaces for mutated genes, meaning that the new generation wouldn't advance as fast, or might stop advancing all together.

Update

I've began writing a few encapsulation methods for some of the classes in the simulation, so that in the future, I can easily modify the simulation elements and goals. I wrote a BaseObject class that all objects with Neural Networks will extend so that I don't run the risk of messing something up with the network. It houses a method that all extending classes can overwrite to state what kinds of conditions need to be met in order to change the fitness level for that object. Hopefully this will make things easier to work with in the future.

I've decided to work on making the sweepers avoid the mines as well, since it allows for more inputs. I tried a little experimentation, by passing a direct offset value for the x and y coordinates to the closest mine, instead of just giving the network the normalized vector, hoping that this would allow the sweeper to take into account the distance to the mine, as well as the angle. I can't quite tell if it's working or not, because they tend to just sit still, avoiding the mines, but not going anywhere.

Basic Completion

After fixing some minor parameters, the program is basically complete. The neural networks work perfectly as they should given their inputs. Depending on the settings for mutation and elitism, the sweepers will learn to collect the dots in around 5 generations (10 for proficiency) on average. By increasing or decreasing a sweeper's level of fitness depending on it's actions (increasing for hitting a mine) I can change what kind of sweeper will evolve out of the generations. By changing the program so that a sweeper's fitness is decreased when hitting a mine, I can also make them avoid the dots as well. It's amazingly simple to change their behaviors.

The current networks I'm using are incredibly simple, with four inputs, 2 outputs, and a few nodes in between. I'm probably going to do some experimentation on adding different inputs, or changing the game around.

Graphics

I've added in very basic rendering to the program to help with debugging. Nothing pretty, but it should be easy to tell now if anything is wrong. Attached is a screenshot of the current graphics. Boxes are placed on the position of the sweepers and dots are placed for the mines. Each sweeper also has a line drawn from it to show its current movement vector.

So Far #2

So the bug seems to have stemmed from a different bug in the crossover method. While the method would have been correct in all other syntaxes, in Java, setting one object equal to another object does not actually copy the properties into the object, rather it stores a reference. I was taking in a parameter for the child neuron that would be outputted, and setting it equal to the mother neuron (only if the crossover rate didn't fire, which is why it didn't happen every time). The child neuron then only stored a reference to the mother neuron, but the mother was deleted after the epoch (creation of a new generation) ended.

So Far #1

Up until now, I have been working on programming the engine for the Neural Network that I am trying to create in Java. I have been working off the online tutorial, and converting the C++ that the tutorial is written in into Java.

http://www.ai-junkie.com/ann/evolved/nnt1.html

I recently finished basically porting the code available into Java, and am now in the process of debugging the code, such as adding methods that were not shown, or not available in Java.

The end result of this program would be to create a simulation that created small minesweeper robots that would use Neural Networks to control their movement towards dots placed around the screen. I hope to use this example to teach me more about how Neural Networks work in general, and then expand to create my own system that would solve a more realistic problem. (Spam filtering, Virus Blocking, etc...)

At the moment, I am trying to write methods that are built into C++, but not Java, such as RandomClamped and creating iterators from the list of genes so that the program can sort the genomes by the most efficient. It's mostly a matter of putting in the time to just write the methods, as they aren't very difficult. RandomClamped just returns a value -11

Start

I'm just starting this blog as a sort of log for what I'm doing in conjunction with my projects on Neural Networks and AI. What I'm hoping is that someone who's a beginner and interested in the topic will stumble across it and learn something about the process.