Evolving Simple Organisms

Benjamin
6 min readJul 11, 2018

--

Fish competing for food, one thousand generations into the experiment.

Here I present the results of a small project I have been working on recently. I use a genetic algorithm to evolve organisms (I call them fish) that try to eat food. Nathan Rooy wrote the original ‘evolving simple organisms’ code which I forked and then edited for my own purposes. My code can be found here.

The Organisms

The fish have small brains represented by neural networks. Each fish brain has six inputs, x and y displacement to nearest food, x and y displacement to the nearest fish neighbor and current x and y velocity. They have two outputs, new x and y velocity. They have only one hidden layer with five nodes, making them very simple organisms.

The Algorithm

The fish evolve using a genetic algorithm. In the first generation most of the fish are not very capable because their neural network brains have been initialised with random weights. The best fish in that generation are selected for the next generation, and the rest of the new generation is created by breeding those successful fish. This pattern is repeated for as many generations as we like.

The Fitness

How to decide which fish are selected for the next generation and to become parents? Fitness was determined by how much food a fish was able to eat. Fish that were better at eating food were more likely to be selected. To prevent the fish clumping together, a small cost was incurred by fish that got too close to each other.

The Experiment

The fish of the first generation behave mostly at random, though some fish are slightly better at getting the food than the others.

After only one generation, several of the fish are able to head directly towards food.

After five generations, most of the fish are quite good at moving towards food. After the food is gone, they quickly spread apart because of the selection pressure to not get too close to other fish.

After twenty generations, the fish have developed a swirling strategy that allows them to avoid getting too close to each other while also moving towards their closest food. This strategy also has the benefit that when several fish happen to be moving towards the same closest food, the swirling pushes some fish away from that food, allowing them the possibility of stumbling onto other food with less competitors.

Not much has changed after one hundred generations. A bit of fine tuning of the weights, slightly wider arcs when moving towards food.

Even in the one thousandth generation, not much has changed.

So how do our fish perform over the generations? It’s interesting to see that after about fifty generations, the population average, best and worst performance stabilises. In the early generations, some efficient fish were able to get comparably high scores because of weak competition, but as the generations progressed, the weaker fish were replaced with children of the fitter fish.

Now, here, you see, it takes all the running you can do, to keep in the same place — Lewis Carroll, Alice Through the Looking Glass

Some Thoughts on the Project

There were a few things I had to tweak to get the fish to behave in a way I wanted. First was the rate of convergence of the population. I adjusted this by choosing the number of individuals to select for breeding in the next generation. When I set this to 20% of the population, the population was very quick to converge, setting it to 50% seemed to work better. Increasing the population size also slows down convergence. Another variable I experimented with was the number of food. I noticed that a higher fish to food ratio led the fish to converge more quickly and to move towards food more aggressively.

My first experimental runs did not penalise against organisms getting too close together, and so when the population converged, all the fish had similar brains and would clump together if they were after the same food. This led me to try out reward shaping. To encourage the fish not to clump up, I created a small cost to their fitness if they got too close to each other. The ‘small cost’ I tried first was too big and sent the fish swimming away from each other and off the screen away from the food. Getting the fish to behave how I wanted them to was a matter of testing different cost values.

In generation 100, it looks like a fish that ignored the other fish and went straight for the food might do well. I reasoned that a fish that ignores other fish when all the other fish avoid it might excel. This strategy would not always do well though, because when it’s strategy became the dominant one in the population, the fish would clump together. This type of pressure is called frequency-dependent selection and can sometimes create a cyclic pattern in behaviour. Despite searching, I wasn’t able to observe this in any of the experimental runs.

Lastly, there was a bug in my code. My code still ran and the fish still optimised, it was only after staring at their behaviour for several generations that I realised something must be wrong. Optimising systems with stochastic elements can make discovering bugs difficult. The system will still likely achieve some incremental improvements, and odd behaviour can be attributed to mutations.

Bloopers

Lot’s of things can go wrong when coding up ‘artificial life’. Here are some of the weirder things I came across.

Without the selection pressure to not get too close to each other, the fish clump together. The neural network weights slowly converge as the generations progress. This means that for fish in close proximity, the next move is likely to be the same.
Due to a difficult to discover bug, most of these fish swim off the screen. The fish still learn though, despite the bug
These fish get stuck between two foods
Misshapen rewards made these fish circle around the food instead of eating it
I have no idea about this one
This one isn’t a blooper. When food isn’t scarce, the fish don’t behave so aggressively
Due to a difficult to discover bug, most of these fish lose motivation. Some fish can learn though, despite the bug
This was when I mixed up the neural network outputs
None of these poor fish seem able to get a single food

Thanks for reading. I had a lot of fun evolving these fish and observing their behaviour. I hope you enjoy them too.

--

--

Benjamin

Mathematics, Programming, Data Science, Deep Learning, Evolutionary Algorithms