September 2015

Volume 30 Number 9

Test Run - Computing with Artificial Spiking Neurons

By James McCaffrey

James McCaffreyA fascinating area of computer science is computing with artificial spiking neurons—small software components that model the behavior of biological neurons. Artificial spiking neurons are related to but quite different from the artificial neurons in a common software neural network.

Let me state right up front that this discussion of artificial spiking neurons is not likely to be immediately useful to you in your normal day-to-day programming tasks. But it will give you insight into what the future of computing might be like, and you just might find artificial spiking neurons interesting in their own right.

The best way to get a feel for what a spiking neuron is and to see where this article is headed is to take a look at the demo program in Figure 1.

Artificial Spiking Neuron Demo
Figure 1 Artificial Spiking Neuron Demo

The demo shows the input and output values for a single spiking neuron. There are three input streams, sometimes called spike trains.

Each of the input spike trains has 16 0 or 1 values. The three input spike trains are:

0 0 1 0 1 0 1 1 1 1 0 0 1 0 1 1
1 0 1 1 0 0 0 1 1 1 0 1 1 0 1 1
1 1 0 1 0 0 0 1 1 0 1 1 1 1 1 1

These 0 or 1 values represent input over time from some other spiking neuron. In other words, at time t = 0, the input value from the first spike train is 0; at time t = 1, the input is 0; at t = 2, the input is 1; and so on through t = 15 when the input value is 1.

At time t = 0, the spiking neuron receives input from all three streams, so at t = 0, the complete input to the neuron is (0, 1, 1); at time t = 1, the input is (0, 0, 1); and so on through t = 15 when the input is (1, 1, 1).

The next part of the demo program displays numeric constants that define the behavior of the neuron. There are three weights with values (4, -2, 3) that correspond to each input train. The meaning of the leak potential (1), the threshold potential (8), the spike potential (4), and the post-spike latency (2) will be explained shortly. In the context of spiking neurons, the term “potential” means (loosely) electrical voltage rather than “possible” or “impending.”

The demo program simulates 16 time ticks. At each tick, the three input 0 or 1 values are displayed along with the state of the neuron (active or inactive), and the current electrical potential (V) of the neuron. Notice that at time t = 6 the neuron reaches a potential of V = 8 and spikes to V = 12. Behind the scenes, as each set of input values is processed, an output value of 0 or 1 is generated and saved in a buffer. After all the input values have been processed, the demo program displays the resulting output spike train:

0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0

At this point, you’re probably not too impressed. A bunch of 0 or 1 values goes in, and a bunch of 0 or 1 values comes out. But bear with me and you’ll see why artificial spiking neurons may help lead to a fundamental change in computers and computing.

This article assumes you have at least beginner programming skills but doesn’t assume you know anything about spiking neurons. I’ve coded the demo program using C#, but you shouldn’t have much difficulty refactoring it to another language, such as Python or JavaScript. The demo code is short and is presented in its entirety in this article. The complete source is also available in the accompanying code download.

Understanding Spiking Neurons

Take a look at the graph in Figure 2. The graph displays the electrical potential value, V, of the demo spiking neuron from time t = 0 to t = 15. There are many different variations of spiking neurons. The demo program is based on a model called the leaky integrate-and-fire spiking neuron.

Leaky Integrate-and-Fire Spiking Neuron Behavior
Figure 2 Leaky Integrate-and-Fire Spiking Neuron Behavior

The electrical potential of the neuron tends to increase over time. When V meets or exceeds the spiking threshold equaling 8, indicated by the dashed line, the V value instantly spikes up by 4 (the spike potential) and then immediately resets to 0. Spiking events occur at time t = 6 and t = 13. If a spiking event occurs, a 1 is emitted to the output spike train, other­wise a 0 is emitted.

So, just how is V calculated for each value of t? At time t = 0, the three input values are (0, 1, 1). Recall the neuron’s three weight values are (4, -2, 3). First, the sum of the products of inputs times weights is computed and added to the current value of V. If V is assumed to be 0 at the start of the demo then:

V = V + sum
   = 0 + (0)(4) + (1)(-2) + (1)(3)
   = 0 + 1
   = 1

This is the integrate step. Next, the leak value is subtracted. For the demo, leak = 1 so:

V = V - leak
   = 1 - 1
   = 0

The new value of V = 0 doesn’t exceed the threshold value of 8 so the neuron doesn’t spike and it emits a 0 to the output spike train. Next, at time t = 1, the input values are (0, 0, 1). Combining the integrate and leak steps gives:

V = V + sum - leak
    = 0 + (0)(4) + (0)(-2) + (1)(3) - 1
    = 0 + 3 - 1
    = 2

Artificial leaky integrate-and-fire spiking neurons are extremely simple. Notice that all values are integers, which, combined with design simplicity, mean that artificial neurons can be efficiently implemented in software or hardware.

In Figure 2, you can see that a spike event occurs at time t = 6. At t = 5, V = 5 so the integrate-and-leak calculation for t = 6 is:

V = V + sum - leak
    = 5 + (1)(4) + (0)(-2) + (0)(3) - 1
    = 5 + 4 - 1
    = 8

At this point, V meets the threshold value of 8, so the value of V spikes to 8 + 4 = 12, an output value of 1 is emitted, and then V is immediately reset to 0. After a spike event, the simulated neuron enters a state of inactivity where input values are ignored. The demo sets this latency period to 2, so at times t = 7 and t = 8, V remains at 0 regardless of the values of the inputs. At time t = 9, the neuron becomes active and resumes normal behavior.

Implementing the Demo Program

The code for the demo program, with a few minor edits to save space, is presented in Figure 3. To create the demo program, I launched Visual Studio and created a new C# console application project named SpikingNeuron. The demo program has no significant Microsoft .NET Framework dependencies so any relatively recent version of Visual Studio will work.

Figure 3 Spiking Neuron Program

using System;
namespace SpikingNeuron
{
  class SpikingNeuronProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Begin spiking neuron demo");
      int[][] inputs = new int[3][];
      inputs[0] = new int[] { 0, 0, 1, 0, 1, 0, 1, 1,
        1, 1, 0, 0, 1, 0, 1, 1 };
      inputs[1] = new int[] { 1, 0, 1, 1, 0, 0, 0, 1,
        1, 1, 0, 1, 1, 0, 1, 1 };
      inputs[2] = new int[] { 1, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 1, 1, 1, 1, 1, 1 };
      Console.WriteLine("The inputs are: ");
      for (int i = 0; i < inputs.Length; ++i)
        ShowVector(inputs[i], false);
      Console.WriteLine("");
      int[] output = new int[16];
      int[] wts = new int[] { 4, -2, 3 };
      Console.Write("The weights are: ");
      ShowVector(wts, true);
      Console.WriteLine("");
      int leak = 1;
      Console.WriteLine("Leak potential is: " + leak);
      int v = 0; // electrical potential (voltage)
      int thresh = 8; // Threshold
      int spike = 4;  // Increase in v at spike
      int tNext = 0; // Time when neuron is active
      int latency = 2; // Inactive after spike
      Console.WriteLine("Threshold is: " + thresh);
      Console.WriteLine("Spike is: " + spike);
      Console.WriteLine("Latency time is: " + latency);
      Console.WriteLine("Starting processing\");
      for (int t = 0; t < 16; ++t)
      {
        Console.WriteLine("----------------------");
        Console.Write(" ");
        Console.Write("t = ");
        if (t <= 9) Console.Write(" ");
        Console.Write(t + ". ");
        Console.Write("Inputs = " + inputs[0][t] +
          " " + inputs[1][t] +
          " " + inputs[2][t]);
        if (t != tNext) // Neuron not active
        {
          Console.Write(". Neuron is inactive. ");
          Console.WriteLine("V = " + v);
          output[t] = 0;
        }
        else // Neuron is active
        {
          Console.Write(". Neuron is   active. ");
          int sum = 0;
          for (int j = 0; j < inputs.Length; ++j)
            sum += inputs[j][t] * wts[j];
          v = v + sum;
          v = v - leak;
          if (v < 0)
            v = 0;
          Console.WriteLine("V = " + v);
          if (v >= thresh) // Spike and reset
          {
            v = v + spike;
            Console.WriteLine(" Spiking, V = " + v);
            output[t] = 1;
            v = 0;
            tNext = t + 1 + latency;
          }
          else
          {
            output[t] = 0;
            tNext = t + 1;
          }
        } // Active
      } // t
      Console.WriteLine("----------------------");
      Console.WriteLine("Output spike train = ");
      ShowVector(output, false);
      Console.WriteLine("End spiking neuron demo");
      Console.ReadLine();
    } // Main
    static void ShowVector(int[] vector, bool plus)
    {
      for (int i = 0; i < vector.Length; ++i)
      {
        if (plus == true && vector[i] >= 0)
          Console.Write("+");
        Console.Write(vector[i] + " ");
      }
      Console.WriteLine("");
    }
  } // Program
} // ns

After the template code loaded into the text editor, in the Solution Explorer window I renamed file Program.cs to SpikingNeuronProgram.cs and allowed Visual Studio to rename class Program for me. At the top of the source code I removed all unneeded using statements, leaving just the reference to the top-level System namespace.

The code in the Main method begins by setting up the input data and a storage buffer for the output values:

int[][] inputs = new int[3][];
inputs[0] = new int[] { 0, 0, 1, 0, 1, 0, 1, 1,
  1, 1, 0, 0, 1, 0, 1, 1 };
...
int[] output = new int[16];

Here there are three input streams. Artificial spiking neurons can accommodate any number of streams. Each steam has 16 0 or 1 values. The input length is arbitrary, but from a programmer’s point of view, you can think of each demo input stream as a 16-bit unsigned value.

Next, the demo sets values that define the neuron’s behavior:

int[] wts = new int[] { 4, -2, 3 };
int leak = 1;
int v = 0; // Electrical potential (voltage)
int thresh = 8; // Needed to fire an output spike
int spike = 4;  // Increase in v at spike event
int tNext = 0; // Next time when neuron is active
int latency = 2; // Number t inactive after spike

Notice that the weights for input streams 0 and 2 are positive and therefore act to increase the electrical potential of the neuron, but the weight for input stream 1 is negative, so it decreases the potential. Sometimes these are distinguished as excitatory (increase) and inhibitory (decrease) inputs.

Here the leak value is set to 1. An alternative to consider is to make the leakage stochastic; that is, randomly vary the leak value between, say, 0 and 3 at each time tick. Or you could vary the leak value to be proportional to the current potential. You can also consider making the spike reset latency time period a random value.

All the processing is controlled by a time-driven loop:

for (int t = 0; t < 16; ++t)
{
  // Compute new V
  // Spike if V >= threshold
  // Emit a 0 or 1
}

Inside the time loop, the demo first checks to see if the neuron is inactive:

if (t != tNext) // Neuron is not active
{
  Console.Write(". Neuron is inactive. ");
  Console.WriteLine("V = " + v);
  output[t] = 0;
}
else
{
  // Active
}

Variable tNext is the next time value when the neuron will be active. In most cases, tNext will be t+1. An inactive neuron is essentially asleep, so there’s no change to the electrical potential and no spike can occur. Inside the active-neuron branch, the electrical potential V is calculated:

int sum = 0;
for (int j = 0; j < inputs.Length; ++j)
  sum += inputs[j][t] * wts[j];
v = v + sum;
v = v - leak;
if (v < 0) v = 0;

Here j is the index of the input stream (0, 1, 2) and t is the time index. For example, inputs[1][8] is the 0-or-1 value for input stream 1 at time t = 8. After the leak is subtracted from V, the resulting value is checked to make sure V doesn’t go negative. However, in real neurons, electrical potentials can in fact be negative, so an option to consider is to allow V to go negative.

After V is calculated, its value is checked to see if a spike event should occur, as shown in Figure 4.

Figure 4 Checking If a Spike Event Should Occur

if (v >= thresh) // Spike and reset
{
  v = v + spike;
  Console.WriteLine(" Spiking, V = " + v);
  output[t] = 1;  // Fire
  v = 0;
  tNext = t + 1 + latency;
}
else // No spike
{
  output[t] = 0;
  tNext = t + 1;
}

When a spike event occurs, the current value of V is incremented (by 4 in the demo) and then immediately reset to 0. In other words, the temporary spiked value of V is not used at all. An alternative for you to consider is to not automatically reset to V = 0. Instead, you can reset by subtracting some amount from the spiked V value. For example, at time t = 6 in the demo, V temporarily spikes from 8 to 12. If you used a spike reset value of 10, then instead of resetting from 12 to 0, the neuron would reset from 12 to 2.

What’s the Point?

Artificial spiking neurons are studied by different groups of people for different purposes. Neurobiologists attempt to create software models that exactly replicate the behavior of real neurons in order to gain insights into biological processes. It turns out that the leaky integrate-and-spike neuron model is too simple to completely replicate the behavior of real neurons, so more complex models are usually used.

Artificial spiking neurons also serve as the basis for machine learning classification systems. Although artificial neural networks that use real-valued simulated neurons have been studied for decades, networks of artificial spiking neurons haven’t been explored much. In my opinion, research results in this area are inconclusive and it’s not clear whether networks of artificial spiking neurons provide any advantage over classical real-valued artificial neurons. There are still many open research questions.

Finally, artificial spiking neurons are being used in an effort to create a fundamentally new approach to computers and programming. The U.S. Defense Advanced Research Projects Agency (DARPA) Systems of Neuromorphic Adaptive Plastic Scalable Electronics (SyNAPSE) project aims to create computers that can scale to biological levels. Instead of using traditional hardware architecture, some initial promising designs have used billions of inter-connected artificial leaky integrate-and-fire spiking neurons. If these efforts prove successful, it may be possible to create computers that are almost inconceivably more powerful than current systems.


Dr. James McCaffrey works for Microsoft Research in Redmond, Wash. He has worked on several Microsoft products including Internet Explorer and Bing. Dr. McCaffrey can be reached at jammc@microsoft.com.

Thanks to the following Microsoft technical experts for reviewing this article: Todd Bello and Dan Liebling