Our beautiful immune system in action – Modeling an interactive neural network
Complex as it is, our immune system can track menace in different and fascinating ways, using different types of white cells laying each of them on several approaches to do this.
The foundations of my humble simulations are:
- Bacterias run away from white cells
- White cells chase chemical traces left by bacterias
Actually, this is partially true. I didn’t work with chemical traces on the code as it will lead to a major dedication and development, which is not the point of this tutorial. Let’s say then, I only use random movements for bacterias (to start) and then they let them learn from white cells movements knowing that those are the places they don’t want to be or move to.
If you like to know more about neural networks, you can visit this tutorial, it contains full and detailed explanation on how the learning process occur inside a neural network.
For this particular project, I worked with the Architect object. It allows you to create multilayer perceptrons, also known as feed-forward neural networks. They consist of a sequence of layers, each fully connected to the next one.
So, for our case, we are going to need two different neural networks, trained with different data. First, we have a special white cell, the Lymphocyte; and the Bacteria itself. Take a quick look to the code bellow, but don’t worry much about the different values (you can play with them later ;) ).
As you can see, both of them declare a Perceptron with different inputs, hidden and output layer values. Let’s revise them a little bit:
Lymphocyte only defines 3 outputs (also does the Bacteria). Can you imagine why? Let’s try to abstract our development goal by imaging what actually happens on real life. Lymphocytes moves freely and “randomly” on our bodies, and whenever a bacteria disrupts in the environment it gets targeted by the white cell, moving towards to it in order to “eat it”. Ok, so basically it moves, right?.
My intention it’s make this easier and think on movements on a 2D world. In other words, we’ll be working with vectors (oh my!) and coordinate axis composed by x and y values only.
Coming back to the the core of the matter, this number 3 represents the expected values needed to move the Lymphocyte (or Bacteria) towards a particular place which will be, at the end of the training sessions in which our nets are going to “sweat” all the values out, the expected one: the bacteria location for the lymphocytes, and a location away the lymphocytes for the bacteria. Easy peasy!
Now, take a look to our world definitions…
Holds a collection of bacterias and lymphocytes, of course! So, please keep this in mind as is the most important understanding to train our networks properly. Here, I chose to add 10 lymphocytes and 2 bacterias. Thus, for the input to be meaningful and correct to any of our organisms we need to use: their locations (decomposed on x and y values) and their velocity (decomposing the vector on x and y as well) to train our network.
So, for the lymphocyte neural net we’ll have 2 components for the location and 2 for the velocity, giving us a total of 4 values times 2 bacterias equal 8.
Equally it is for the bacterias, 4 values times 10 lymphocytes equal 40.
Besides knowing x and y values, we also need an angle (duh! of course I remember algebra from High School) which determines vector’s direction. What we are trying to to attempt is “learn” from this values, in other words, train our neural network so it can know as accurate as it possible how to reach their target.
A couple of things worth be mentioned here:
- This neural net works in a cohesive way, meaning each group of organisms stick together. Imagine a platoon of soldiers marching to a specific point in which their enemies are barricaded; they have to work in groups, join forces so as for them to be as effective as they can.
a) Bacterias “stick together” in this particular exercise so it can be easier to picture it on the canvas. I encourage you to work in this particular point to make it more interesting :) and try coding a non-dependent group of bacterias.
b) Lymphocytes as well, however thinking in real life examples, they actually follow chemical tracks. We can think of them as being spread randomly in our bodies and when suddenly encounter one of this tracks, they start to follow it immediately. So it could have some sense to make them work together, but again, it’s for practical reasons.
Show me “the sweat”
- Let’s take a closer look to the training process, starting with the lymphocytes.
This piece of code belongs to our world.js file. First, we loop through the lymphocytes collection, and in each cycle we loop through the bacterias collection and store their position and velocity values in an array. Next, we use this array to train each lymphocyte, “feeding” the network to where it should be moving. In addition we define a learning rate, which can be modified to “play” on how fast/easy/slow/wrong the net behaves.
The target variable holds the cohesion I was talking before. Above you can take a quick look on how it works. Behind several functions in charge of defining and calculate positions based on the bacterias belonging to our world (you can take a deeper look to them in the project source code at GitHub) it retrieves the cohesion value that consequently allows to the lymphocyte group stick together and in addition, follow their target, the bacterias.
Finally, the loop process draws our lymphocytes positions in the canvas. This logic it’s also followed by bacterias training process but slightly different when it comes to learning where to move.
2. Bacterias training looks like this (please don’t panic, you’ll see it’s pretty straightforward when read the explanation :) )
If you think about it just for a moment you’ll realize what’s going here. Bacterias don’t want to be close to lymphocytes, right? So their input can not be lymphocytes positions, which lead us to ANY position but lymphocytes ones. Pretty much what’s written on the code: we train our bacterias network with random positions and velocities and then, we remove those belonging to lymphocytes. Because of this, we can ended up with less than 40 inputs (as our bacterias net require to be trained) so we continue generating random ones until reach 40. And then, we feed the net with this values and draw it in our canvas.
AND THAT’S IT! :)
Hope you enjoyed this article as much as I did writing it! There are tons of things to work, change, modify or play with this project. Let me know how that goes! And please, if you really liked it don’t forget to applaud so everybody can enjoy it as well :)