<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><!--Generated by Squarespace Site Server v5.11.81 (http://www.squarespace.com/) on Tue, 22 May 2012 11:02:04 GMT--><feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><title type="text">Rinat Abdullin on NeuroEvolution</title><subtitle type="html">Using neural networks and genetic algorithms for complex data analysis and forecasting.</subtitle><id>http://abdullin.com/journal/</id><link rel="alternate" type="application/xhtml+xml" href="http://abdullin.com/journal/" /><updated>2012-05-22T08:37:08Z</updated><generator uri="http://www.squarespace.com/" version="Squarespace Site Server v5.11.81 (http://www.squarespace.com/)">Squarespace</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/neuro-evolution" /><feedburner:info uri="neuro-evolution" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><title>Strategy Pattern in .NET NeuroEvolution Algorithms</title><category term="C#" /><category term="NeuroEvolution" /><category term="Snippets" /><id>http://abdullin.com/journal/2009/1/8/strategy-pattern-in-net-neuroevolution-algorithms.html</id><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/neuro-evolution/~3/FaVhzwYG2FI/strategy-pattern-in-net-neuroevolution-algorithms.html" /><author><name>Rinat Abdullin</name></author><published>2009-01-08T13:32:30Z</published><updated>2009-01-08T13:32:30Z</updated><content type="html" xml:lang="en-US">&lt;p&gt;Getting back to the &lt;a href="http://abdullin.com/neuroevolution/"&gt;NeuroEvolution&lt;/a&gt; research after a couple of years of delay has turned out to be quite rewarding.&lt;/p&gt;

&lt;p&gt;For example, while writing new implementation of the algorithm from scratch I just could not avoid leveraging some principles from the &lt;a href="http://rabdullin.com/shared-libraries/"&gt;Lokad Shared&lt;/a&gt; (apart from using the core library). One of these patterns is about cleanly separating some logic in the delegates, and then combining these delegates to produce the desired effects.&lt;/p&gt;

&lt;p&gt;We had &lt;a href="http://rabdullin.com/journal/2008/12/1/net-exception-handling-action-policies-application-block.html"&gt;Action Policies&lt;/a&gt; and &lt;a href="http://rabdullin.com/journal/2008/11/23/net-application-block-for-validation-and-business-rules.html"&gt;Validation Rules&lt;/a&gt; in .NET enterprise development. In NeuroEvolution algorithms we can also apply these principles to mutation strategies.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By the way, I've created a &lt;a href="http://rabdullin.com/neuroevolution/"&gt;separate page&lt;/a&gt; to serve as an index for these NeuroEvolution series. And there also is a &lt;a href="http://feeds.feedburner.com/neuro-evolution"&gt;NeuroEvolution RSS feed&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;Strategy Pattern&lt;/h1&gt;

&lt;p&gt;Every evolutionary algorithm leverages operations like &lt;em&gt;mutate&lt;/em&gt; or &lt;em&gt;crossover&lt;/em&gt; that have certain probability of occuring. Additionally, NeuroEvolutional algorithms (being more specific) have to operate with the networks that can grow and thus they leverage strategies like &lt;em&gt;AddConnection&lt;/em&gt;, &lt;em&gt;RemoveConnection&lt;/em&gt;, &lt;em&gt;Jiggle&lt;/em&gt; and some others.&lt;/p&gt;

&lt;p&gt;Since such algorithms are being developed within the the research process, soon they turn into a mess of heuristics:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;foreach (var genome in winners)
{
  if (Rand.NextDouble() &amp;lt; mutationChance)
  {
    // do mutation
  }
  if (Rand.NextDouble() &amp;lt; crossOverChance)
  {
    var parent = Rand.NextItem(winner);
    // do crossover    
  }
  if (Rand.NextDouble() &amp;lt; addSynapse)
  {
    // add synapse
  }
  // etc
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's try to make everything slightly more extensible and fit for the research process.&lt;/p&gt;

&lt;p&gt;We'll define our strategy as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public delegate Genome MutationStrategy(Genome source, Genome parent,
  Context context);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where the Genome is just genocode, and Context class contains population-specific properties like PopulationAge or JiggleFactor.&lt;/p&gt;

&lt;p&gt;Given that, we can cleanly define our strategies in C# like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static Genome AddSynapse(Genome source, Genome parent, 
  Context context)
{
  // Rand is a class from Lokad Shared that makes it easier
  // to use various random generators
  var input = Rand.NextItem(source.Neurons).Index;
  var output = Rand.NextItem(source.Neurons).Index;
  var param = Rand.NextDouble();
  var newConnection = new SynapseGene(input, output, param);
  return Genome.AddConnection(source, newConnection);
}

public static Genome FastestWins(Genome source, Genome parent, 
  Context context)
{
  if (source.Synapses.Length &amp;lt; parent.Synapses.Length)
    return source;
  return parent;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or even reuse one strategy in another:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static Genome RemoveSynapse(Genome source, Genome parent,
  Context context)
{
  var length = source.Synapses.Length;
  if (length &amp;gt; 1)
  {
    var idx = Rand.Next(length);

    return Genome.DropConnection(source, idx);
  }
  return FastestWins(source, parent, context);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously, you could also create parametrized strategies as well.&lt;/p&gt;

&lt;p&gt;Then these strategies could be combined together (with probabilities of happening) like this: &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Tuple is a class from Lokad Shared that makes it more
// simple to bind values together
var chances = new List&amp;lt;Tuple&amp;lt;int, MutationStrategy&amp;gt;&amp;gt;();

chances.Add(5, Strategies.AddSynapse);
chances.Add(10, Strategies.RemoveSynapse);
chances.Add(20, Strategies.DadWins);
chances.Add(10, Strategies.MutateSynapse);
chances.Add(20, Strategies.MutateNeuron);
chances.Add(5, Strategies.AddNeuron);
chances.Add(20, Strategies.Cross);

var strategies = CreateRoulette(chances);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where CreateRulette simply creates array of strategies, where each strategy has N number of entries (thus the probability of being applied is &lt;em&gt;Pi = Ni/Sum(Ni)&lt;/em&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static T[] CreateRoulette&amp;lt;T&amp;gt;(IEnumerable&amp;lt;Tuple&amp;lt;int,T&amp;gt;&amp;gt; source)
{
  return source.SelectMany(tuple =&amp;gt; 
    Enumerable.Repeat(tuple.Item2, tuple.Item1)).ToArray();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With that we can apply random strategy to every item in the population pool like this (random item from the winners collection is being picked as the primary parent):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;population = population.Convert(g =&amp;gt;
  Rand.NextItem(strategies)(Rand.NextItem(winners), g, context));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;New .NET 3.5 features make wonders to these old C# algorithm implementations, do not they?&lt;/p&gt;

&lt;p&gt;As the &lt;a href="http://rabdullin.com/neuroevolution/"&gt;NeuroEvolution series&lt;/a&gt; go on, we'll see if it is possible to make it even more simple to write these machine-learning heuristics that leverage the latest technology.&lt;/p&gt;

&lt;p&gt;PS: .NET F# can make wonders to the performance of these algorithms by making them as fast as pure C. Check out the latest update to the &lt;a href="http://rabdullin.com/journal/2009/1/6/f-has-better-performance-than-c-in-math.html"&gt;previous post&lt;/a&gt; for details.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=YyOXZl2r"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=YyOXZl2r" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=3DaBMfhv"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=3DaBMfhv" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=SNn2v1f6"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=SNn2v1f6" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/neuro-evolution/~4/FaVhzwYG2FI" height="1" width="1"/&gt;</content><feedburner:origLink>http://abdullin.com/journal/2009/1/8/strategy-pattern-in-net-neuroevolution-algorithms.html</feedburner:origLink></entry><entry><title>F# Has Better Performance than C# in Math</title><category term="NeuroEvolution" /><category term="Snippets" /><id>http://abdullin.com/journal/2009/1/6/f-has-better-performance-than-c-in-math.html</id><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/neuro-evolution/~3/Xg_2bbV0z-Q/f-has-better-performance-than-c-in-math.html" /><author><name>Rinat Abdullin</name></author><published>2009-01-06T10:35:38Z</published><updated>2009-01-06T10:35:38Z</updated><content type="html" xml:lang="en-US">&lt;p&gt;As it turns out algorithms coded in F# code might have much better performance, compared to the ones in C# code.&lt;/p&gt;

&lt;p&gt;Below you will find F# version of optimized sigma-comparison algorithm from the &lt;a href="http://rabdullin.com/journal/2009/1/5/caching-activation-function-is-not-worth-it.html"&gt;previous post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Compared to the C#, this .NET code: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;executes sigmoid1 benchmark in &lt;strong&gt;588.8ms instead of 3899,2ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;executes sigmoid2 (LUT) benchmark in &lt;strong&gt;156.6ms instead of 411.4ms&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll see below that this performance of F# is quite close to the performance of the similar implementation written in C.&lt;/p&gt;

&lt;p&gt;Here's the F# code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#light

let Scale = 320.0f;
let Resolution = 2047;

let Min = -single(Resolution)/Scale;
let Max = single(Resolution)/Scale;

let range step a b =
  let count = int((b-a)/step);
  seq { for i in 0 .. count -&amp;gt; single(i)*step + a };

let lut = [| 
  for x in 0 .. Resolution -&amp;gt;
    single(1.0/(1.0 +  exp(-double(x)/double(Scale))))
  |]

let sigmoid1 value = 1.0f/(1.0f + exp(-value));

let sigmoid2 v = 
  if (v &amp;lt;= Min) then 0.0f;
  elif (v&amp;gt;= Max) then 1.0f;
  else
    let f = v * Scale;
    if (v&amp;gt;0.0f) then lut.[int (f + 0.5f)]
    else 1.0f - lut.[int(0.5f - f)];

let getError f = 
  let test = range 0.00001f -10.0f 10.0f;
  let errors = seq { 
    for v in test -&amp;gt; 
      abs(sigmoid1(single(v)) - f(single(v)))
  }
  Seq.max errors;

open System.Diagnostics;

let test f = 
  let sw = Stopwatch.StartNew(); 
  let mutable m = 0.0f;
  let result = 
    for t in 1 .. 10 do
      for x in 1 .. 1000000 do
        m &amp;lt;- f(single(x)/100000.0f-5.0f);
  sw.Elapsed.TotalMilliseconds;

printf "Max deviation is %f\n" (getError sigmoid2)
printf "10^7 iterations using sigmoid1: %f ms\n" (test sigmoid1)
printf "10^7 iterations using sigmoid2: %f ms\n" (test sigmoid2)

let c = System.Console.ReadKey(true);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the output (Release compilation against F# 1.9.6.2 CTP with no debugger):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Max deviation is 0.001664
10^7 iterations using sigmoid1: 588.843700 ms
10^7 iterations using sigmoid2: 156.626700 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Chances are that the performance of sigmoid2 is better than that, but I just can't figure out how to get rid of the mutable state.&lt;/p&gt;

&lt;h1&gt;Running as Mono&lt;/h1&gt;

&lt;p&gt;By the way, that's how similar (although not exact) code works out under Mono (&lt;a href="http://stackoverflow.com/questions/412019/code-optimizations#414152" class="offsite-link-inline"&gt;details&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gmcs test.cs &amp;amp;&amp;amp; mono test.exe
Max detected error using LUT: 0.1568425 %
1000000 iterations using Sigmoid1() took 3591.858 ms
1000000 iterations using Sigmoid2() took 247.561 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Running as C&lt;/h1&gt;

&lt;p&gt;C is supposed to be really close to metal and highly efficient. Let's check out how it works out for this algorithm.&lt;/p&gt;

&lt;p&gt;Running &lt;a href="http://stackoverflow.com/questions/412019/code-optimizations#412176" class="offsite-link-inline"&gt;C implementation&lt;/a&gt; of the code (developed by &lt;a href="http://stackoverflow.com/users/2010/henrik-gustafsson" class="offsite-link-inline"&gt;Henrik Gustafsson&lt;/a&gt;) yields following results:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Max deviation is 0.001664
10^7 iterations using sigmoid1: 628 ms
10^7 iterations using sigmoid2: 157 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Surprisingly enough, the performance is almost the same as F#. So F# must be doing really good job here.&lt;/p&gt;

&lt;p&gt;Caveat: I've been using win32 compiler to get the binaries. 64 bit might improve the performance a bit. I'll update the article if it does.&lt;/p&gt;

&lt;h1&gt;Summary&lt;/h1&gt;

&lt;p&gt;So it turns out that F# compiler creates code that is 2-6 times faster for the math code, compared to C# (while the output is still .NET compatible). And this F# code has performance close to the one of the C code.&lt;/p&gt;

&lt;p&gt;All this makes me wonder, if it is worth switching to F# for the core &lt;a href="http://rabdullin.com/neuroevolution/"&gt;NeuroEvolution&lt;/a&gt; code. Stay &lt;a href="http://feeds.rabdullin.com/RinatAbdullin"&gt;tuned&lt;/a&gt; for the series.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=rvKYKqTA"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=rvKYKqTA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=JPM5Mnov"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=JPM5Mnov" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=BLDqALGG"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=BLDqALGG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/neuro-evolution/~4/Xg_2bbV0z-Q" height="1" width="1"/&gt;</content><feedburner:origLink>http://abdullin.com/journal/2009/1/6/f-has-better-performance-than-c-in-math.html</feedburner:origLink></entry><entry><title>Caching Activation Function Is Not Worth It</title><category term="NeuroEvolution" /><id>http://abdullin.com/journal/2009/1/5/caching-activation-function-is-not-worth-it.html</id><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/neuro-evolution/~3/Gju0dX38Q2w/caching-activation-function-is-not-worth-it.html" /><author><name>Rinat Abdullin</name></author><published>2009-01-05T14:18:01Z</published><updated>2009-01-05T14:18:01Z</updated><content type="html" xml:lang="en-US">&lt;p&gt;Let's continue with our &lt;a href="http://rabdullin.com/journal/category/neuroevolution"&gt;NeuroEvolution series&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil &lt;br /&gt;
  &amp;copy; Donald Knuth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The statement above applies even to seemingly hi-tech areas like forecasting, data mining or neural networks.&lt;/p&gt;

&lt;p&gt;Here's a simple situation. &lt;/p&gt;

&lt;p&gt;The function below is called an activation function and it is the piece of code that eats up the most CPU time in old-fashioned neural networks:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;static double sigmaActivation(double value)
{
  return 1d / (1 + Math.Exp(-value));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One may be &lt;a href="http://stackoverflow.com/questions/412019/code-optimizations"&gt;tempted&lt;/a&gt; to optimize this "bottleneck". Can you?&lt;/p&gt;

&lt;h1&gt;Caching&lt;/h1&gt;

&lt;p&gt;One of the options was to create a complete cache of all the function arguments and outputs to save the cost of the computations. The assumption is that this table will perform better and will have reasonably small footprint.&lt;/p&gt;

&lt;p&gt;Let's prove that 4k is a mild understatement for size of this table.&lt;/p&gt;

&lt;p&gt;We'll use this method to create float values within the range between -10 and +10:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;static float CreateRandomFloat()
{
  return (float)((Rand.NextDouble() - 0.5)*Rand.NextDouble()*20);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note, that we a dropping number of values to be hashed by a couple of orders of magnitude here (normally synapse outputs are double and they can easily get out of the (-10;+10) range.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static void Main()
{
  var hash = new HashSet&amp;lt;float&amp;gt;();

  ThreadStart a = () =&amp;gt; {
    while(true)
    {
      hash.AddRange(Range.Create(100, i =&amp;gt; CreateRandomFloat()));
    }
  };

  var thread = new Thread(a);
  using (new DisposableAction(thread.Abort))
  {
    thread.Start();

    do
    {
      Console.WriteLine("Press Esc to quit or any other key to poll hash");
      var pureSize = hash.Count*sizeof (float)*2;
      Console.WriteLine("Pure table size is {0} Mb", pureSize/1.Mb());

    } while (Console.ReadKey(true).Key != ConsoleKey.Escape);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the code snippet above we simply launch secondary thread to look up for new floats and put them into the HashSet. The HashSet will obviously keep only unique values.&lt;/p&gt;

&lt;p&gt;Then, whenever user presses non-ESC key, we output current raw size of our imaginary look-up table. &lt;/p&gt;

&lt;p&gt;After running this code for 20 seconds I've already hit 250 megabytes, and it kept growing. &lt;/p&gt;

&lt;p&gt;Now, given the size of that thing and the amount of index walking that has to be done, it does not really make a lot of sense to use hashing, does not it?&lt;/p&gt;

&lt;p&gt;And even if it would have a small performance improvement, I'd personally still stay away from this optimization, since the increased code complexity is just not worth it.&lt;/p&gt;

&lt;h1&gt;Lookup Table&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Another possible way&lt;/strong&gt; is to use &lt;a href="http://en.wikipedia.org/wiki/Lookup_table" class="offsite-link-inline"&gt;lookup tables&lt;/a&gt; to break the input into a set of predefined intervals and then output some &lt;strong&gt;rough estimation&lt;/strong&gt; instead. &lt;/p&gt;

&lt;p&gt;Unfortunately, this option does not work for me in some situations (especially when using NEAT algorithm derivatives for complex tasks), since this approach &lt;strong&gt;messes up the search space&lt;/strong&gt; for the training algorithm (by introducing local extrema all over the place)  and makes it even more CPU intensive in the long run (also lowering the probability of success). &lt;/p&gt;

&lt;p&gt;But it might work for your scenario. Here's the snippet posted by &lt;a href="http://stackoverflow.com/questions/412019/code-optimizations#414152" class="offsite-link-inline"&gt;Henrik Gustafsson&lt;/a&gt; (with some performance tweaks). And kudos go to him for setting me straight on the lookup tables.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;const float Scale = 320.0f;
const int Resolution = 2047;
const float Min = -Resolution/Scale;
const float Max = Resolution/Scale;

static readonly float[] _lut = InitLut();

static float[] InitLut()
{
  var lut =  new float[Resolution + 1];
  for (int i = 0; i &amp;lt; Resolution + 1; i++)
  {
    lut[i] = (float) (1.0/(1.0 + Math.Exp(-i/Scale)));
  }
  return lut;
}

static float Sigmoid1(double value)
{
  return (float) (1.0/(1.0 + Math.Exp(-value)));
}

static float Sigmoid2(float value)
{
  if (value &amp;lt;= Min) return 0.0f;
  if (value &amp;gt;= Max) return 1.0f;
  var f = value*Scale;
  if (value &amp;gt;= 0) return _lut[(int) (f + 0.5f)];
  return 1.0f - _lut[(int) (0.5f - f)];
}

static float TestError()
{
  var emax = 0.0f;
  for (var x = -10.0f; x &amp;lt; 10.0f; x += 0.000001f)
  {
    var v0 = Sigmoid1(x);
    var v1 = Sigmoid2(x);

    var e = Math.Abs(v1 - v0);
    if (e &amp;gt; emax) emax = e;
  }
  return emax;
}

static double TestPerformancePlain()
{
  var sw = new Stopwatch();
  sw.Start();
  for (int i = 0; i &amp;lt; 10; i++)
  {
    for (float x = -5.0f; x &amp;lt; 5.0f; x += 0.000001f)
    {
      Sigmoid1(x);
    }
  }

  return sw.Elapsed.TotalMilliseconds;
}

static double TestPerformanceOfLut()
{
  var sw = new Stopwatch();
  sw.Start();
  for (int i = 0; i &amp;lt; 10; i++)
  {
    for (float x = -5.0f; x &amp;lt; 5.0f; x += 0.000001f)
    {
      Sigmoid2(x);
    }
  }
  return sw.Elapsed.TotalMilliseconds;
}

static void Main()
{
  var emax = TestError();
  var t0 = TestPerformancePlain();
  var t1 = TestPerformanceOfLut();

  Console.WriteLine("Max detected deviation using LUT: {0}", emax);
  Console.WriteLine("10^7 iterations using Sigmoid1() took {0} ms", t0);
  Console.WriteLine("10^7 iterations using Sigmoid2() took {0} ms", t1);
  Console.ReadKey(true);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here are the results on my machine (relase mode, no debugger attached):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Max detected deviation using LUT: 0,001663984
10^7 iterations using Sigmoid1() took 3899,1979 ms
10^7 iterations using Sigmoid2() took 411,4441 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Keep in mind, that increasing precision will not necessarily improve the overall performance, since it will result in larger lookup table that has lower chance to fit into the CPU cache. &lt;/p&gt;

&lt;p&gt;By the way, from my experience even switching from &lt;em&gt;double&lt;/em&gt; to &lt;em&gt;float&lt;/em&gt; could be enough to turn training some complex model task from &lt;em&gt;hard&lt;/em&gt; to &lt;em&gt;unfeasible&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That's it for now. The series on NeuroEvolution will definitely continue till they hit Cloud Computing. Stay &lt;a href="http://feeds.rabdullin.com/RinatAbdullin"&gt;tuned&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; next post shows that &lt;a href="http://rabdullin.com/journal/2009/1/6/f-has-better-performance-than-c-in-math.html"&gt;F# version of this algorithm has better performance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PS: &lt;em&gt;Range.Create&lt;/em&gt;, &lt;em&gt;DisposableAction&lt;/em&gt;, &lt;em&gt;1.Mb&lt;/em&gt; and other shortcuts come from the &lt;a href="http://rabdullin.com/shared-libraries/"&gt;Lokad.Shared.dll&lt;/a&gt; helper library that is used in this snippet.&lt;/p&gt;

&lt;p&gt;PPS: you may also want to check &lt;a href="http://rabdullin.com/journal/2008/9/24/some-performance-issues-and-caveats-of-linq.html"&gt;Some performance issues and caveats of using LINQ in math code&lt;/a&gt;. &lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=rgkxQnCA"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=rgkxQnCA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=DaNiKOOz"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=DaNiKOOz" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=d7QK8Ele"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=d7QK8Ele" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/neuro-evolution/~4/Gju0dX38Q2w" height="1" width="1"/&gt;</content><feedburner:origLink>http://abdullin.com/journal/2009/1/5/caching-activation-function-is-not-worth-it.html</feedburner:origLink></entry><entry><title>On AI, Neuro-Evolution and Azure</title><category term="Azure" /><category term="NeuroEvolution" /><id>http://abdullin.com/journal/2008/12/22/on-ai-neuro-evolution-and-azure.html</id><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/neuro-evolution/~3/LPmuuQqq1dI/on-ai-neuro-evolution-and-azure.html" /><author><name>Rinat Abdullin</name></author><published>2008-12-22T03:50:34Z</published><updated>2008-12-22T03:50:34Z</updated><content type="html" xml:lang="en-US">&lt;p&gt;One of the topics that I've never covered in this blog is about developing data-mining and business analytics applications. Especially, the analytics part (which happened to have popularity with terms like &lt;em&gt;Artificial Intelligence&lt;/em&gt; or &lt;em&gt;Neural Networks&lt;/em&gt;) which is one of the most curious implementation fields in the area of software development.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with the subject but are really interested about it, then I recommend you to have a look at the &lt;a href="http://sharpneat.sourceforge.net/" class="offsite-link-inline" rel="external nofollow"&gt;SharpNEAT&lt;/a&gt; implementation. The C# architecture of the solution is far from representing efficient development approach (that's the inseparable feature of scientific projects) but some concepts behind are really nice.&lt;/p&gt;

&lt;p&gt;In short, this project leverages neural networks (these were a hype not that much time ago) with augmenting topologies to solve tasks of forecasting and machine learning. The network "training" is done via the evolutionary (genetics) algorithm.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;augmenting topologies&lt;/em&gt; part is one of the key features of the project. It is about letting the networks to "grow" more complex during the training process. This is much better than simply changing the synapse weights as it allows to adapt the system to the complexity of the solution (just do not forget about the over-training problem).&lt;/p&gt;

&lt;p&gt;Obviously such approach requires the introduction of some new heuristics to the evolutionary algorithm like segmentation of the species into the pools (mixing together networks with different topology will be just a waste of CPU) or introducing the pruning phase to "compact" existing networks that are too large.&lt;/p&gt;

&lt;p&gt;If we compare this approach to the traditional statistical learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it works better, but nobody can really tell how the models work (black-box situation);&lt;/li&gt;
&lt;li&gt;it allows to capture really complex multi-factor dependencies of the nonlinear nature;&lt;/li&gt;
&lt;li&gt;it works with the incomplete or noisy data;&lt;/li&gt;
&lt;li&gt;less human hours are needed to actually create and update analysis and forecasting models;&lt;/li&gt;
&lt;li&gt;it makes development more fun.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the major problems with this neuro-evolutional approach lies within the analogy road. Scientists get way too stuck with this neural-networks concept from the Mother Nature to see the development opportunities of the flexibility and technology. Well at least they like to think they are close to real world because these networks &lt;em&gt;do solve real-world problems&lt;/em&gt; (although they really are just non-deterministic brute-force algorithms with some slight optimization of the search space). &lt;/p&gt;

&lt;p&gt;However, building a full feature set for the proper real-world analogy will require &lt;strong&gt;at least&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;introduction of the proper electro-chemical reactions with the mediators in an asynchronous and continuous manner;&lt;/li&gt;
&lt;li&gt;introduction of the Glia (networks are not just about neurons and synapses, you know);&lt;/li&gt;
&lt;li&gt;delivery of the quantum computers into the mass-production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;span class="thumbnail-image-float-right ssNonEditable"&gt;&lt;span&gt;&lt;a href="javascript:showFullImage('/display/ShowImage?imageUrl=%2Fstorage%2Fuploads%2F2008%2F12%2Fanalysis-network.gif%3F__SQUARESPACE_CACHEVERSION%3D1229922066510',517,705);"&gt;&lt;img style="width: 150px;" src="http://abdullin.com/storage/thumbnails/2929255-2285050-thumbnail.jpg?__SQUARESPACE_CACHEVERSION=1229922100182" alt=""/&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, we do not have to stick to these concepts and can play directly with the development-pure things like mathematical interpretators, model ensembles or evolving functions. New technologies like &lt;a href="http://www.microsoft.com/azure/" class="offsite-link-inline" rel="external nofollow"&gt;Windows Azure&lt;/a&gt; (we are interested in the Cloud Computing part) or Microsoft &lt;a href="http://research.microsoft.com/en-us/projects/Accelerator/" class="offsite-link-inline" rel="external nofollow"&gt;Accelerator&lt;/a&gt; Research Project (.NET library for delegating some computations to your GPU) make it more affordable.&lt;/p&gt;

&lt;p&gt;Side effect is that models are more flexible, leverage CPU more efficiently and are more fun to develop.&lt;/p&gt;

&lt;p&gt;We'll see how this research topic on non-statistical learning will go further. Stay &lt;a href="http://feeds.rabdullin.com/RinatAbdullin"&gt;tuned&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=iAArm3Sp"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=iAArm3Sp" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=rxumG7ch"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=rxumG7ch" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/neuro-evolution?a=CKulC32Z"&gt;&lt;img src="http://feeds.feedburner.com/~f/neuro-evolution?i=CKulC32Z" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/neuro-evolution/~4/LPmuuQqq1dI" height="1" width="1"/&gt;</content><feedburner:origLink>http://abdullin.com/journal/2008/12/22/on-ai-neuro-evolution-and-azure.html</feedburner:origLink></entry></feed>

