Associative Memory - Experiment 1

Introduction

The first thing to do is to make sure that cell assemblies can actually form in the grid. I want my animals and characteristics to form small "islands" of activity in the grid of cells. for this to work, it is important that I establish that islands of activation do form and that they can sustain themselves. That is what this experiment is designed to test. If it fails (i.e. the islands don't form or the activation spreads all over the grid with no appreciable structure), then the idea of using cell assemblies to implement an associative memory will take a severe knock.

Below you will see a grid of 20-by-20 cells, each randomly connected to a certain number of the other cells in the grid (the number is adjustable by the user) with connections whose strengths are initially assigned to a random decimal in the range 0 to 0.4. 5% of the cells are inhibitory, the rest excitatory.

The 100 cells in a 10-by-10 square in the centre of the grid are special. During each time step of training, each of these cells has a certain probability (adjustable via a control at the base of the applet), which starts off at 50%, of having its activation boosted to 1. When you click on the icon on the applet, you will see black spots flickering on this central square as the cells are activated.

When you click on the icon, you find that a stable pattern of cell activations (black circles) appears in the centre of the grid. Having trained the grid, you can then clear all the activations and set a few of the central circles to black by clicking on them. Then, when you click on the icon, you should find that the stable pattern quickly reappears. Activating a few of the circles is enough to get the entire cell assembly going again! This is what we in the scientific world call "a result!"

The Java Applet itself

Click here to download the source code

How to use the program

The most basic way

Just click on the icon at the top. You will see patterns of activation crawl across the grid. When it has finished training, click on to blank the grid out exactly. Then click on a few of the cells with the mouse pointer to set them. You should only need to click on about three of four providing you choose them carefully (try near the middle of the grid). When you have set your test pattern, click on . If the cell assembly has trained correctly, the small amount of activity that you have specified should grow into a self-sustaining pattern, i.e. it will settle down to a pattern.

Try different parameter values

I have set the parameter values to give what I think is pretty much the best performance, but please feel free to alter them. This is done by using icons at the top of the applet and various controls below the grid itself. The following icons at the top of the applet:


You can decide whether the connections are distance biased (i.e. each cell is only connected to those within 5 units of its position) or completely random (any cell has an equal probability of being connected to any other cell on the grid).


You can decide whether cells lose all their activation when they have fired (i.e. they have shot their bolt and then "go back to sleep").

There are several parameter values which can be altered between 0 and 1. They start off with default values as shown. Click on the icon next to each option to increase it by 0.1 and on the icon to increase it by 0.01. Similarly, click on the and icons to decrease the value by 0.1 and 0.01 respectively.

Additionally the program gives you some information about the average connection strengths. If we refer to the central square of cells that receive external activity as the "island" and the surrounding cells as the "sea", then the connections between the cells can be classified as within the island (I to I), within the sea (S to S) or bridging the two (I to S or S to I). The program tells you the total number of such connections (in brackets) and the average strength of each type of connection.

How the program works

The program contains a grid of cells in 20 rows by 20 columns (stored in constants ROWS and COLS in the program). Each cell has an activity level, and connections to other cells. The default number of connections is 10 connections in total to other cells in the grid.

Cells can be either excitatory (i.e. when it passes activation to other cells, it tends to increase their activity levels) or inhibitory (it tends to decrease the destination cells' activity levels). The connection destinations and whether the cell is excitatory/inhibitory are set up randomly when the program runs, although the user can choose to re-randomize them by clicking on the appropriate icon. By default, the cells have a 95% chance of being excitatory.

The cells are what Dr. Huyck terms "leaky integrators". This means that they build up activity, but it gradually leaks away. The activity of each cell is given by the its activity at the previous time step, multiplied by a percentage (which represents the proportion that it retained from the previous step) added to the sum of the incoming activity. If the cell's activity at a given time step t is ht, its activity at the previous time step is ht-1, and d is the decay term, then:

ht = ht-1.d + Σw.i

In this case, Σw.i represents the weighted sum of the inputs to this cell. The default value of d is 0.3, indicating that 30% of the activity of the cell stays put from one time step to the next, while the rest leaks away into thin air. You may see this formula written slightly differently in the scientific literature:

ht = ht-1 / d + Σw.i

i.e. the activity is divided by a constant rather than multiplied by it. It doesn't really make any difference - mathematically, they are equivalent as long as you choose your constants correctly!

You have the choice as to whether the cells fatigue or not. Fatigue is just what the name implies - cells that are active gradually become tired and this increases their tendency to deactivate. Each cell in the grid contains a Fatigue value, and this fatigue value, should you choose to include it, is governed by three constants: the fatigue threshold (default value 0.6), the fatigue rate (default value 0.1) and the recovery rate (default value 0.03).

When the activity of the cell is above the fatigue threshold, then the fatigue value of the cell is subtracted from the cell's activity. Although this starts at 0, the fatigue rate is added to this fatigue value every time step that the cell is activated (i.e. the fatigue increases). This does not prevent the cell from being reactivated on subsequent time steps, but does make it harder. Similarly, when a cell deactivates, the fatigue value is reduced on every subsequent time step by the recovery rate (until the cell reactivates, of course).

Best results are generally obtained by training the network thoroughly (several clicks on the icon) without fatigue, and then turning fatigue on with a threshold of 0.9 and a fatigue rate of 0.05 or less before testing.

The cells themselves are modelled by a class within the Java program (called cell, funnily enough), which controls how the connections are assigned, the propagation of activity through the cell and how the connections are adapted.

The constant MAX_CONN determines the maximum number of connections that lead out of each cell (to others), with a default value of 10. The actual number of connections (the value of the variable conn) can be altered in the program using the Connectivity control on the left of the applet.

By default, the destinations to these connections are set randomly, but with distance biasing, i.e. the destinations of the connections are limited to a maximum distance of 2 cells away from their source. The weights of the connections are set to random numbers in the range 0 to 0.4.

There is only one input "pattern" as such. We are interested in setting up a cell assembly in the middle 10-by-10 square of cells in the grid. Instead of activating all these squares in one go on every step of the training sequence (that would be too easy!) the program activates each cell randomly with a certain probability given by INP_PROB (default value 0.2). This means that the cells in the middle square twinkle on and off like stars during training.

The training uses "LTP with post-not-pre LTD" and a post-Hebbian updating rule. This means that

When the grid is run, only cells whose activations are above the firing threshold pass on their activation to others. The activation of each of the cells is multiplied by the weight of the connection and added to a temporary variable called temp_a maintained for each cell. If the original firing cell is excitatory, then the activation is added to the temp_a value for the destination cell. Otherwise it is subtracted. The firing cell then has its activation reduced to zero (i.e. firing exhausts the cell), although this facility can be turned off by the user. Experience suggests that cells which have fired are usually immediately reactivated by other cells feeding them, so cells tend to stay active for quite a few time steps.

When all the temp_a values of the cells have been updated, the activation can be propagated through the cells. It should be clear, with a bit of thought, why we need to maintain a temp_a value for each cell: If activity were propagated through each cell as soon as it arrived, then cells wouldn't be able to sum the activation for all the inputs to it, and its altered activation would then affect other cells before the system had had time to settle down - it would be an asynchronous free-for-all.

In each cell, the incoming activity is passed through a sigmoid function and then multiplied by a decay rate. This is to account for the fact that activity decays gradually from the cells even when they aren't firing.


Previous file On we go!