<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>fxai</title>
 <link href="http://floybix.github.io/" rel="self"/>
 <link href="http://floybix.github.io"/>
 <updated>2016-09-24T08:58:45+00:00</updated>
 <id>http://floybix.github.io</id>
 <author>
   <name>Felix Andrews</name>
   <email>felix@nfrac.org</email>
 </author>

 
 <entry>
   <title>Attempting the Numenta Anomaly Benchmark</title>
   <link href="http://floybix.github.io/2016/07/01/attempting-nab"/>
   <updated>2016-07-01T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2016/07/01/attempting-nab</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;Being an objective test problem, NAB allows us to tease apart the
contribution of various aspects of HTM models. It turns out the
current best result on NAB can be achieved with only first-order
transition memory. It seems the regular sampling rate of most time
series data does not produce a directly meaningful sequence of
transitions. If we take effective time steps only when sufficient
changes occur this indeed gives some improved performance, but still
sees no benefit to higher-order transitions. Ultimately, like most
things in HTM, I think human-level anomaly detection will require
robust temporal pooling.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The most frustrating thing about working on
&lt;a href=&quot;http://numenta.org/&quot;&gt;Hierarchical Temporal Memory&lt;/a&gt; has been the lack
of any standard test problems. I’ve spent ages thinking and reading
papers, trying to decide what kind of problems are suitable. Visual
object recognition – or does that depend on understanding attention?
Game playing – or does that require complex behaviour generation?
Natural language processing – or does that need working memory? What
even should an HTM system be trying to do and how can we measure it?&lt;/p&gt;

&lt;p&gt;To its credit, Numenta has recently established one such standardised
test problem: &lt;a href=&quot;http://numenta.org/nab/&quot;&gt;Numenta Anomaly Benchmark&lt;/a&gt;
(NAB). The task is anomaly detection in a stream of numeric values. It
includes a corpus of artificial data, events with known causes,
and other real world data annotated with anomalies, each over a window
of time. Currently there are 58 time series with a total of about
366,000 records and 116 anomaly windows.&lt;/p&gt;

&lt;p&gt;Initial results have an HTM model coming out on top compared with
several other methods. This is exciting because it is the first
example I have seen of HTM doing something useful, and doing it better
than the alternatives.&lt;/p&gt;

&lt;p&gt;The HTM model listed on the
&lt;a href=&quot;https://github.com/numenta/NAB&quot;&gt;NAB leaderboard&lt;/a&gt; was run in
&lt;a href=&quot;https://github.com/numenta/nupic&quot;&gt;NuPIC&lt;/a&gt; with
&lt;a href=&quot;https://github.com/numenta/nupic/blob/039c9292f806a4db5d72e291dc7ed56b1a390a2c/src/nupic/frameworks/opf/common_models/anomaly_params_random_encoder/best_single_metric_anomaly_params_tm_cpp.json&quot;&gt;these parameter values&lt;/a&gt;.
I set out to find out which aspects of the model were really important,
by exploring the parameter space and algorithm variations. Also, since
at last we have a standard test problem, this was an opportunity to
verify my implementation of HTM,
&lt;a href=&quot;https://github.com/htm-community/comportex&quot;&gt;Comportex&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;headline-result&quot;&gt;Headline result&lt;/h2&gt;

&lt;p&gt;I have not produced a much better score than the original Numenta
model. Rather, my main result was to show that that score can be
equalled with a much simpler model. This tells us something useful
about the contribution of different aspects of these HTM models. I’ll
discuss some below.&lt;/p&gt;

&lt;p&gt;The headline result here comes from Comportex with mostly the same
parameters as the Numenta model, but with the following differences:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;first-order transition memory (1 cell per column, down from 32);&lt;/li&gt;
  &lt;li&gt;a potential receptive field sample of 16% (down from 80%);&lt;/li&gt;
  &lt;li&gt;only 16 segments per cell (down from 128);&lt;/li&gt;
  &lt;li&gt;sampled linear encoders;&lt;/li&gt;
  &lt;li&gt;timestamp given as distal input (not proximal / driving input);&lt;/li&gt;
  &lt;li&gt;a distal stimulus threshold of 18 (not 20).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve been following the HTM community you’ll recognise that this
approach is based directly on
&lt;a href=&quot;http://mrcslws.com/gorilla/?path=hotgym.clj&quot;&gt;the successful work of Marcus Lewis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, some post-processing was applied:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Instead of the raw bursting rate, a &lt;strong&gt;delta anomaly&lt;/strong&gt; score was
calculated: it considers only newly active columns (ignoring any
remaining active from the previous timestep). The bursting rate is
calculated only within these new columns. To handle small changes,
the number of columns considered – i.e. divided by – is kept from
falling below 20% of the total number of active columns (20% of 40 =
8).&lt;/li&gt;
  &lt;li&gt;If an anomaly is detected (above some specified threshold), &lt;strong&gt;no
further detections&lt;/strong&gt; are reported for 40 time steps. This stops false
positives from going crazy.&lt;/li&gt;
  &lt;li&gt;Note that Numenta’s Anomaly Likelihood filtering was &lt;strong&gt;not applied&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anyway, here is the final result as scored by NAB:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;model&lt;/th&gt;
      &lt;th&gt;standard&lt;/th&gt;
      &lt;th&gt;low FP rate&lt;/th&gt;
      &lt;th&gt;low FN rate&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;original NuPIC model + anomaly likelihood&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;65.3&lt;/td&gt;
      &lt;td&gt;58.6&lt;/td&gt;
      &lt;td&gt;69.4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;original NuPIC model, raw bursting score&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;52.5&lt;/td&gt;
      &lt;td&gt;41.1&lt;/td&gt;
      &lt;td&gt;58.3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;selected Comportex model, delta anomaly score&lt;/td&gt;
      &lt;td&gt;64.6&lt;/td&gt;
      &lt;td&gt;58.8&lt;/td&gt;
      &lt;td&gt;69.6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;selected Comportex model, raw bursting score&lt;/td&gt;
      &lt;td&gt;59.5&lt;/td&gt;
      &lt;td&gt;53.4&lt;/td&gt;
      &lt;td&gt;63.8&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;A model variant that achieves a notably better &lt;strong&gt;low FP rate&lt;/strong&gt; score of
59.8 is also described below under &lt;strong&gt;Effective time steps&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;discussion&quot;&gt;Discussion&lt;/h2&gt;

&lt;p&gt;This is a good result and confirms that Comportex is a competitive
implementation of HTM. But the most interesting part is how this
allows us to run experiments to tease apart the contribution of
different aspects of the models. Let look at the most important ones:&lt;/p&gt;

&lt;h4 id=&quot;first-order&quot;&gt;First-order&lt;/h4&gt;

&lt;p&gt;The result shows that the reported performance of HTM on NAB can be
explained with only first-order transition memory. That is surprising,
given that NAB consists of many complex time series, and some were
even deliberately constructed as artificial higher-order sequence
problems. However, the result follows similar findings for prediction
&lt;a href=&quot;http://mrcslws.com/gorilla/?path=hotgym.clj&quot;&gt;on the HotGym data&lt;/a&gt; (by
Marcus Lewis), and
&lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2015-December/003441.html&quot;&gt;on the New York Taxi data&lt;/a&gt;
(by me).&lt;/p&gt;

&lt;p&gt;Of course I did run experiments with 32 cells per column, the NuPIC
standard. The result was a large decrease in score – around the same
amount as when leaving out the timestamp input, or when leaving out
the delta anomaly score. (see Appendix)&lt;/p&gt;

&lt;p&gt;That a first-order model gives an improved result suggests that the
current design of HTM transition memory is incomplete. While it is
possible that my own implementation has subtle problems, the fact
remains that HTM’s higher order transition memory has not been
demonstrated to have a benefit on any real problem, as far as I know.
My feeling is that transition memory will work better when constrained
by higher-level contexts, i.e. with temporal pooling.&lt;/p&gt;

&lt;h4 id=&quot;delta-anomaly-score&quot;&gt;Delta anomaly score&lt;/h4&gt;

&lt;p&gt;The delta anomaly score is defined as:&lt;/p&gt;

&lt;pre&gt;
(number-of-newly-active-columns-that-are-bursting) /
max(0.2 * number-of-active-columns, number-of-newly-active-columns)
&lt;/pre&gt;

&lt;p&gt;Note that this will not pick up cases when columns stay on
unexpectedly, like a flat-line scenario. To catch this I also tried a
variant with instead the &lt;code class=&quot;highlighter-rouge&quot;&gt;number-of-newly-bursting-columns&lt;/code&gt; –
i.e. counting the columns that changed into a bursting state, even if
they were previously active. However, that gave worse results.&lt;/p&gt;

&lt;p&gt;Here’s an example of an obvious anomaly in the
&lt;code class=&quot;highlighter-rouge&quot;&gt;realKnownCause/machine_temperature_system_failure&lt;/code&gt; series, around
time step 4000:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2016-07-01/temp1-anomaly-delta-scores.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Section of the &lt;code class=&quot;highlighter-rouge&quot;&gt;machine_temperature_system_failure&lt;/code&gt; data. Anomaly
 windows are outlined in red. The middle plot is delta anomaly scores
 and the bottom plot is raw bursting scores, from a baseline HTM
 model.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Looking at the HTM columns with
&lt;a href=&quot;https://github.com/htm-community/sanity&quot;&gt;Sanity&lt;/a&gt;, we can see that the
anomaly rolls in over several time steps, hiding the overall magnitude
of the anomaly:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2016-07-01/temp1-t3982.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;HTM columns over time (time steps go left to right) on the &lt;code class=&quot;highlighter-rouge&quot;&gt;machine_temperature_system_failure&lt;/code&gt; data, highlighting time step 3982. Red columns are bursting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is why delta anomaly calculation helps. I like that this simple
approach achieves good results without the need for a separate
“anomaly likelihood” Gaussian estimation process.&lt;/p&gt;

&lt;h4 id=&quot;limited-potential-receptive-field&quot;&gt;Limited potential receptive field&lt;/h4&gt;

&lt;p&gt;It is curious that there is such a strong benefit in limiting the set
of inputs that each column can connect to. I think this reflects that
the learning process in HTM is too greedy, so it loses the ability to
discriminate between values. A “boosting” mechanism is supposed to
correct for this, but in practice does more harm than good. There is
more to say on this but I’ll leave that for another time and a simpler
test problem.&lt;/p&gt;

&lt;p&gt;Compared to the roughly 5% increase in score going from 80% to 16%
global connectivity, we get about two thirds of that benefit if the
16% connectivity is restricted to a local area of the input bits (80%
connectivity within 20% area = 16%). Probably in the local case, while
its scope is limited, greediness still applies within a local range of
values.&lt;/p&gt;

&lt;h4 id=&quot;sampled-linear-encoders&quot;&gt;Sampled linear encoders&lt;/h4&gt;

&lt;p&gt;The original Numenta model used a Random Distributed Scalar Encoder
for the time series value, and a periodic scalar encoder for the
hour. Instead I used Marcus Lewis’ sampled linear encoders for both -
mainly for aesthetic reasons. Also I didn’t have an implementation of
RDSE. So I didn’t test the impact of this decision. But just look at
the beautiful encoding they produce - how can this not be good?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2016-07-01/value-encoder.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Value encoder. x-axis is numeric range in 5% steps. Active bits vertically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2016-07-01/hour-encoder.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hour-of-day encoder. x-axis is hour. Active bits vertically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2 id=&quot;effective-time-steps&quot;&gt;Effective time steps&lt;/h2&gt;

&lt;p&gt;The time series data in NAB are sampled at different time scales and
also change at very different rates. Some are smooth and wavelike and
others are super spiky. As I mentioned in the context of the delta
anomaly score, sometimes an apparently sharp peak would in fact roll in
over many time steps. Because there is only an incremental change on
each time step, the magnitude of the anomaly can be underestimated.&lt;/p&gt;

&lt;p&gt;The sampling rate at which data happens to be available may not be the
best rate for learning meaningful transitions.&lt;/p&gt;

&lt;p&gt;One idea is to delay taking an effective time step in HTM until a
sufficient change occurs to be registered. That is, wait until the set
of active columns are, say, 20% different from the last effective time
step. At that point, learn the transitions from the last effective
time step.&lt;/p&gt;

&lt;p&gt;Interestingly, this gives an improved result on the &lt;strong&gt;low FP rate&lt;/strong&gt;
profile:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;model&lt;/th&gt;
      &lt;th&gt;standard&lt;/th&gt;
      &lt;th&gt;low FP rate&lt;/th&gt;
      &lt;th&gt;low FN rate&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;original NuPIC model + anomaly likelihood&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;65.3&lt;/td&gt;
      &lt;td&gt;58.6&lt;/td&gt;
      &lt;td&gt;69.4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;original NuPIC model&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;52.5&lt;/td&gt;
      &lt;td&gt;41.1&lt;/td&gt;
      &lt;td&gt;58.3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;selected Comportex model (above)&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;64.6&lt;/td&gt;
      &lt;td&gt;58.8&lt;/td&gt;
      &lt;td&gt;69.6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;effective time steps when 20% columns change&lt;/td&gt;
      &lt;td&gt;64.7&lt;/td&gt;
      &lt;td&gt;59.8&lt;/td&gt;
      &lt;td&gt;69.5&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Incidentally, I think the &lt;strong&gt;low FP rate&lt;/strong&gt; profile is the most
reasonable. It balances one correctly detected anomaly to about 10
false positives; whereas the &lt;strong&gt;standard&lt;/strong&gt; profile balances one to about
20 false positives, which seems excessive. And &lt;strong&gt;low FN rate&lt;/strong&gt; is more
like one to 30.&lt;/p&gt;

&lt;h4 id=&quot;limitations&quot;&gt;Limitations&lt;/h4&gt;

&lt;p&gt;Anyway, this effective time steps approach is interesting but
obviously not a final solution. It has no way to detect when an
expected event does &lt;em&gt;not&lt;/em&gt; occur, since there is no change of value
involved.&lt;/p&gt;

&lt;p&gt;Ideally I think the system would be entrained to a rhythm according to
regular patterns in the data, and that would define effective time steps.&lt;/p&gt;

&lt;h2 id=&quot;further-work&quot;&gt;Further work&lt;/h2&gt;

&lt;p&gt;I’m keen to break down the effects of parameters and algorithm
variations by file. Which files change their score order under in each
experiment? That could help to investigate what’s going wrong, in detail.&lt;/p&gt;

&lt;p&gt;Looking forward to hearing your thoughts directly or on the
&lt;a href=&quot;http://discourse.numenta.org/&quot;&gt;HTM Forum&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;

&lt;p&gt;The results here were produced with
&lt;a href=&quot;https://github.com/floybix/nab-comportex/&quot;&gt;nab-comportex&lt;/a&gt; 0.1.0 using &lt;a href=&quot;https://github.com/htm-community/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.14.&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2 id=&quot;appendix-specific-experiments&quot;&gt;Appendix: Specific experiments&lt;/h2&gt;

&lt;p&gt;Results here are expressed as a change in score relative to a starting
point “baseline” model. The baseline model is the same as headline
model except:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;distal stimulus threshold 20&lt;/li&gt;
  &lt;li&gt;local receptive field 20% diameter and 80% fraction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; The scoring here is not from official NAB, it is from my own
implementation of the NAB scoring rules. And my scores are not quite
the same as the official NAB scores, although they are usually closely
correlated. I have not tracked down the cause of the inconsistency.&lt;/p&gt;

&lt;p&gt;Scores shown as differences from baseline:&lt;/p&gt;

&lt;pre&gt;
|   | settings                                      | standard | low FP rate | low FN rate |
|------------------------------------------------------------------------------------------|
| * | baseline                                      | =0.0     | =0.0        | =0.0        |
|   | without delta anomaly; raw bursting score     | -4.8     | -2.7        | -3.4        |
|   | global receptive field, 80% fraction          | -1.1     | -1.2        | -1.6        |
|   | global receptive field, 16% fraction          | +0.4     | +1.7        | +0.5        |
|   | no timestamp input                            | -3.8     | -3.5        | -3.0        |
|   | depth 32 cells per column                     | -2.6     | -4.6        | -2.3        |
|   | depth 32 cells per column, newly bursting     | -3.2     | -5.9        | -2.3        |
|   | depth 32 cells per column, raw bursting       | -5.5     | -5.8        | -5.7        |
|   | distal stimulus threshold 19                  | +0.3     | +1.0        | +0.8        |
|   | distal stimulus threshold 18                  | +1.1     | +1.5        | +1.9        |
|   | distal stimulus threshold 17                  | -0.1     | +0.9        | +2.0        |
| $ | global receptive field, 16% fraction, stim 18 | +1.3     | +2.5        | +1.4        |
|   | effective time steps when 20% columns change  | -0.8     | +0.5        | -1.3        |
|   | effective time steps when 25% columns change  | -1.9     | +0.1        | -2.4        |
|   | effective time steps when 15% columns change  | -1.3     | -0.7        | -1.5        |
|   | effective time steps, distal stimulus 18      | -0.7     | +1.1        | -0.9        |
| ! | effective time steps, 16% fraction, stim 18   | +1.8     | +3.1        | +2.0        |
|   | depth 32, effective time steps &amp;amp; stimulus 18  | -2.6     | -1.0        | -2.1        |
&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;*  baseline model&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;$  headline model&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;!  headline effective time steps model&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Where baseline model scores are (different from official NAB scoring):&lt;/p&gt;

&lt;pre&gt;
|   | settings                                      | standard | low FP rate | low FN rate |
|------------------------------------------------------------------------------------------|
| * | baseline                                      | 66.1     | 60.5        | 70.5        |
&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>Sequence replay in HTM</title>
   <link href="http://floybix.github.io/2015/12/01/sequence-replay-in-HTM"/>
   <updated>2015-12-01T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2015/12/01/sequence-replay-in-HTM</id>
   <content type="html">
&lt;p&gt;If you are not redirected automatically, follow the &lt;a href=&quot;http://viewer.gorilla-repl.org/view.html?source=github&amp;amp;user=htm-community&amp;amp;repo=sanity&amp;amp;path=examples/worksheets/seq-replay.clj&quot;&gt;link to this post&lt;/a&gt;.
&lt;/p&gt;

&lt;script&gt;
  window.location.href = &quot;http://viewer.gorilla-repl.org/view.html?source=github&amp;user=htm-community&amp;repo=sanity&amp;path=examples/worksheets/seq-replay.clj&quot;
&lt;/script&gt;

</content>
 </entry>
 
 <entry>
   <title>The taming of the SDR</title>
   <link href="http://floybix.github.io/2015/09/15/the-taming-of-the-sdr"/>
   <updated>2015-09-15T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2015/09/15/the-taming-of-the-sdr</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;In which I come to a way of visually understanding the activity of
cells in &lt;a href=&quot;http://numenta.org/#theory&quot;&gt;HTM&lt;/a&gt;, which have Sparse
Distributed Representations (SDRs). This new way is like a state
transition diagram, but with fuzzy, evolving states. Several problems
in my existing demos become immediately obvious.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;sparse-distributed-representations&quot;&gt;Sparse Distributed Representations&lt;/h2&gt;

&lt;p&gt;Does the brain work like a computer program? No, and perhaps the
deepest explanation of the difference is in their representation of
information. Computers store data and instructions in a precise
structure using every bit; in a digital memory address, one bad bit
makes the whole thing useless.  Brains use a sparse, distributed
representation where vastly more bits (cells) are needed, but in its
own form captures meaning, in terms of a “halo” of related
concepts. &lt;a href=&quot;http://numenta.com/learn/&quot;&gt;Read more.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of representing a particular person. A computer program might
use their name or email address. But that in itself doesn’t tell you
anything about the person, and if any bit was wrong it would fail. In
contrast, a sparse distributed representation might include where they
live, their friends, occupation, etc. If bits of that were missing,
one would still have a general idea who it might be or could fall back
to someone “similar”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt; with using SDRs is that they are hard to pin down. How
do you work with something that is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;fuzzy&lt;/em&gt; – it can be active to varying degrees, mixed with noise or other SDRs;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;evolving&lt;/em&gt; – it can change over time as it is learned from experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;a-sketch-of-a-diagram&quot;&gt;A sketch of a diagram&lt;/h2&gt;

&lt;p&gt;Earlier this year,
&lt;a href=&quot;https://plus.google.com/u/0/+RobertJohnFreeman&quot;&gt;Rob Freeman&lt;/a&gt; and I
were exchanging emails on some HTM-related ideas. At one point he said,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want to experiment with allowing distal excitation to spread over
region-1 independently of time steps (or before each time step?)&lt;/p&gt;

  &lt;p&gt;For instance, if you take my earlier example &lt;code class=&quot;highlighter-rouge&quot;&gt;abcabcabcxyzabc&lt;/code&gt; and plot
all the subnetworks in a pooled representation […] it should look
like (if my ascii art works out):&lt;/p&gt;

  &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     abc
   /     \
abc   -   abc
   \     /
     xyz
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;

&lt;/blockquote&gt;

&lt;p&gt;Well, I may have missed the main point Rob was making at the time, but
that little ascii-art diagram got me thinking. Why &lt;em&gt;can’t&lt;/em&gt; we distil
the activity in a HTM region down into a state transition diagram?&lt;/p&gt;

&lt;p&gt;I spent the next couple of months, on and off, building and refining
such a plot. In retrospect it seems like an obvious visualisation, and
I’ve come to rely on it as an essential tool for understanding HTM
activity.&lt;/p&gt;

&lt;h2 id=&quot;the-method&quot;&gt;The method&lt;/h2&gt;

&lt;p&gt;I’m going to talk about SDRs of cell activity in a single layer of a
HTM network. Note, &lt;strong&gt;cell&lt;/strong&gt; activity, not column activity, which means
that these representations are context-specific. And because my main
display in
&lt;a href=&quot;https://github.com/nupic-community/comportexviz&quot;&gt;ComportexViz&lt;/a&gt; shows
column activity, it doesn’t help much with seeing these
context-specific cell SDRs.&lt;/p&gt;

&lt;p&gt;This is as much an algorithm as it is a plot.&lt;/p&gt;

&lt;p&gt;The main idea is to tame SDRs by recording them with a unique name
when they appear in distinguishable form. Then we can recognise them
when they appear again, even partially, and we can decide how to
evolve their form.&lt;/p&gt;

&lt;p&gt;Let’s call a named SDR a &lt;em&gt;state&lt;/em&gt; (since it will play a role on
something like a state transition diagram). A state keeps track of
which cells have been active on its watch, and how often.&lt;/p&gt;

&lt;p&gt;Every time step we check the set of &lt;em&gt;active learning cells&lt;/em&gt;. If they
overlap a known state sufficiently well, meeting a threshold
parameter, that known state is said to &lt;em&gt;match&lt;/em&gt;. It’s even possible
that multiple states could match. Otherwise, the active learning cells
define a new state. In any case, all these cells are counted towards
the matching state (or states).&lt;/p&gt;

&lt;p&gt;It’s not quite that simple because states are fuzzy. Some cells are
more essential to a state than others. That’s why we keep running
counts: the influence of a cell is weighted by its &lt;em&gt;specificity&lt;/em&gt; to a
state. So if a cell participates in states &lt;em&gt;A&lt;/em&gt; and &lt;em&gt;B&lt;/em&gt; an equal number
of times, it will count only half as much to &lt;em&gt;A&lt;/em&gt; as a cell fully
specific to
&lt;em&gt;A&lt;/em&gt;. &lt;a href=&quot;https://github.com/nupic-community/comportexviz/blob/5b0592ee76c0222320c06468e505a00f9bba1b8e/src/comportexviz/plots.cljs#L583&quot;&gt;Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here we see there is a tension at the heart of the idea. When a state
evolves and expands, as it appears mixed in various different
contexts, is it still reasonable to think of it as a single coherent
thing? Well, perhaps not, and it will often make sense to reset,
building states anew after some time. But abstraction of concepts from
fuzzy, messy reality is how we understand the world.&lt;/p&gt;

&lt;p&gt;Labels from the input data are also counted on matching states, but
this is only for display, it is not used to define states in any way.&lt;/p&gt;

&lt;p&gt;So that’s basically it for taming SDRs. Now for the display, at one
point in time. We can draw the states, but what about the transitions
between them? Those we can derive from distal synapse
connections. Easy: get all connections between cells, then map both
the source and target cells into states, weighted by specificity. You
end up with the connections between states, each with a score, being
the weighted number of connected synapses between
them. &lt;a href=&quot;https://github.com/nupic-community/comportexviz/blob/5b0592ee76c0222320c06468e505a00f9bba1b8e/src/comportexviz/server/data.cljc#L508&quot;&gt;Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As well as drawing the matching states, it’s useful to show any
partial matches of states by currently active or predicted cells.&lt;/p&gt;

&lt;h2 id=&quot;reading-the-diagram&quot;&gt;Reading the diagram&lt;/h2&gt;

&lt;p&gt;Here’s an example where the inputs are single letters. This display
shows the activity in a layer of cells after seeing the sequence&lt;a href=&quot;#note1&quot;&gt;*&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;o n e o n e o n e t w o t w o t w o t h r e e
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2015-09-15/cell-sdrs-plot.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What does it tell us? Firstly, each of the letters of “one” and “two”
generated distinct states when they were first seen, were re-activated
on repetition, and the transitions between them were learned (blue
lines). The start of “three”, “thr” also generated new states, but the
“e” matched the previous “e” state from “one” instead of generating a
new state. Incidentally, this is undesirable and indicates some bad
parameters in this particular example. The current state, at the time
this plot was drawn, was matching that “e” state (outlined black), and
also extending it with other current cells that were not already in
the state (the green part). Lastly, the initial “o” state is being
predicted for the next time step (it is shaded blue).&lt;/p&gt;

&lt;p&gt;More precisely, here are the rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;States are drawn in order of appearance, by default.&lt;/li&gt;
  &lt;li&gt;If any of a state’s cells are currently active that fraction will be
shaded red (whether active due to bursting or not).&lt;/li&gt;
  &lt;li&gt;Similarly, any predictive cells (predicting activation for the
&lt;strong&gt;next&lt;/strong&gt; time step) will be shaded blue.&lt;/li&gt;
  &lt;li&gt;If any of a state’s cells are the current &lt;em&gt;learning cells&lt;/em&gt; that
fraction will be outlined in black.&lt;/li&gt;
  &lt;li&gt;When a matching state will be extended to include new cells, those
are shown in green.&lt;/li&gt;
  &lt;li&gt;Transitions are drawn as blue curves. Thickness corresponds to the
number of connected synapses, weighted by specificity of both the
source and target cells.&lt;/li&gt;
  &lt;li&gt;The height of a state corresponds to the (weighted) number of cells
it represents.&lt;/li&gt;
  &lt;li&gt;The width of a state corresponds to the number of times it has
matched.&lt;/li&gt;
  &lt;li&gt;Labels are drawn with horizonal spacing by frequency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;putting-it-to-work&quot;&gt;Putting it to work&lt;/h2&gt;

&lt;p&gt;Let’s see if the display is useful. Continuing the example from
&lt;a href=&quot;/2014/10/15/learning-simple-sentences.html&quot;&gt;a previous post&lt;/a&gt; we’ll
use the following sequence of words as input (with each sentence
repeated).&lt;/p&gt;

&lt;pre&gt;
Jane has eyes .
Jane has a head .
Jane has a mouth .
Jane has a brain .
Jane has a book .
Jane has no friend .
Chifung has eyes .
Chifung has a head .
Chifung has a mouth .
Chifung has a brain .
Chifung has no book .
Chifung has a friend .
&lt;/pre&gt;

&lt;p&gt;Here we go.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2015-09-15/sentences-boosting-problem.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Erm… ok. That’s not good. Every word seen comes up as a completely
new state, even when repeated. The problem here was the “boosting”
mechanism which is supposed to encourage fair, efficient use of
columns by biasing activation towards neglected columns. It does
settle down after a while but clearly this is pretty crazy. Let’s turn
off boosting.&lt;/p&gt;

&lt;p&gt;Running it again, repeated states are now re-activated, but we have a
new problem. Here are two consecutive time steps (&lt;code class=&quot;highlighter-rouge&quot;&gt;has&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2015-09-15/sentences-confusion-problem.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The sequence &lt;code class=&quot;highlighter-rouge&quot;&gt;Jane has eyes&lt;/code&gt; had already been learned, so “&lt;code class=&quot;highlighter-rouge&quot;&gt;eyes&lt;/code&gt;” was
predicted. When the actual input “&lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt;” appeared, it somehow ended up
matching the state that was previously active for “&lt;code class=&quot;highlighter-rouge&quot;&gt;eyes&lt;/code&gt;”. How?&lt;/p&gt;

&lt;p&gt;The answer is that the predicted cells, with their distal excitation,
were biased to become active, so the prediction became part of the
actual representation. This is a non-standard part of the algorithm,
sometimes called
&lt;a href=&quot;http://inbits.com/2015/01/self-stabilisation-in-hierarchical-temporal-memory/&quot;&gt;prediction-assisted recognition&lt;/a&gt;.
However in this case the effect is clearly too strong. We can confirm
the cause by looking at the sources of excitation on activated cells:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2015-09-15/sentences-confusion-sources.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So indeed there were 7 cells which became active on the strength of
their predictive (distal) excitation without having much direct
(proximal) excitation.&lt;/p&gt;

&lt;p&gt;When we revise the parameter &lt;code class=&quot;highlighter-rouge&quot;&gt;:distal-vs-proxmal-weight&lt;/code&gt; down from 1.0
to 0.2, the confusion we observed is resolved:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2015-09-15/sentences-confusion-resolved.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Moving on… when we let it run through, something odd happens in the
second section:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2015-09-15/sentences-many-chifungs.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The word “&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung&lt;/code&gt;” ends up as a different state within each
sentence. This happens because, the whole input being an unbroken
sequence, “&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung&lt;/code&gt;” appears after sequences that were recognised
from previous learning:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;has no friend . Chifung&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;has eyes . Chifung&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;has a head . Chifung&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;has a brain . Chifung&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Coming up in these different learned contexts leads to distinct
context-dependent representations. That feels frustrating, because it
is obvious to us that those are not meaningful contexts, and do not
alter the meaning of “&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung&lt;/code&gt;”.&lt;/p&gt;

&lt;p&gt;A better way to read sentences may be using multiple layers. A lower
layer learns sequences of words in a sentence, but starts anew rather
than continuing sequences across sentence boundaries. A higher layer
could track transitions across sentences, which of course involves
Temporal Pooling, a topic I won’t discuss here. This approach can be
seen in the &lt;em&gt;second-level motor&lt;/em&gt; online demo.&lt;/p&gt;

&lt;p&gt;There are several online demos at
&lt;a href=&quot;http://nupic-community.github.io/comportexviz/&quot;&gt;http://nupic-community.github.io/comportexviz/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking forward to hearing your thoughts directly or on the
&lt;a href=&quot;http://numenta.org/lists/&quot;&gt;NuPIC-theory mailing list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;UPDATE 2015-09-18:&lt;/strong&gt; Chetan,
&lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2015-September/003188.html&quot;&gt;replying on NuPIC-theory&lt;/a&gt;,
suggested running a higher-order sequence like&lt;/p&gt;

  &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;6874230
1874235
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;

  &lt;p&gt;This is “higher-order” because it’s not enough to learn the
transitions in isolation. The context of the first letter must be
carried through the following 5 steps in order to unambiguously
predict the final letter.&lt;/p&gt;

  &lt;p&gt;I ran it through my &lt;em&gt;second-level motor&lt;/em&gt; demo, where each word is
repeated until it is learned before moving on, and the sequence
learning is reset when starting each new word. Learning follows a
pattern where on each repetition the new pattern becomes
progressively more distinct from the old pattern, until after about
6 repetitions there is a fully distinct representation of the new
pattern.&lt;/p&gt;

  &lt;p&gt;You can
&lt;a href=&quot;http://nupic-community.github.io/comportexviz/&quot;&gt;run this yourself online&lt;/a&gt;,
but I also &lt;a href=&quot;https://youtu.be/CQG6zfMR2Us&quot;&gt;recorded it as a video&lt;/a&gt;,
in case that is easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;

&lt;p&gt;The results here were produced with
&lt;a href=&quot;https://github.com/nupic-community/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.10 with
&lt;a href=&quot;https://github.com/nupic-community/comportexviz/&quot;&gt;ComportexViz&lt;/a&gt; 0.0.10.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;note1&quot;&gt;*&lt;/a&gt;&lt;span style=&quot;font-size: 80%&quot;&gt; &lt;em&gt;The first example
comes from the second-level motor demo, so the input is not actually
a simple sequence.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Local inhibition algorithm</title>
   <link href="http://floybix.github.io/2014/11/13/local-inhibition"/>
   <updated>2014-11-13T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/11/13/local-inhibition</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;In which I propose and demonstrate a new local inhibition algorithm
for HTM that seems more natural than existing methods. I attempt to
model the waves of inhibition around firing neurons. A target level of
sparsity is maintained by an adaptive control on the stimulus
threshold parameter. One could imagine other formulations and I look
forward to hearing other ideas.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A crucial step in HTM is the selection of neural columns to become
active, given their feed-forward inputs. Essentially, only those with
most excitation will be activated, forming a sparse representation.
But the details could be important. Real neural columns, &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-September/001304.html&quot;&gt;I am
told&lt;/a&gt;,
on firing trigger a wave of inhibition in the surrounding area.&lt;/p&gt;

&lt;h2 id=&quot;inhibition-algorithms-in-nupic&quot;&gt;Inhibition algorithms in NuPIC&lt;/h2&gt;

&lt;p&gt;In NuPIC the seemingly universal choice is &lt;a href=&quot;https://github.com/numenta/nupic/blob/df37f7853775efd771d2822a671bafc2c18286b8/nupic/research/spatial_pooler.py#L1352&quot;&gt;global
inhibition&lt;/a&gt;
of columns. The top few columns with highest excitation are selected
to become active, ignoring any spatial relationships between them. The
justification for this is computational performance; a comment in the
code warns of a 60x performance difference between the global vs local
algorithms.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/numenta/nupic/blob/df37f7853775efd771d2822a671bafc2c18286b8/nupic/research/spatial_pooler.py#L1378&quot;&gt;local inhibition algorithm in
NuPIC&lt;/a&gt;
works as follows. Taking the target activation density—typically 2%
(as with the global algorithm)—it keeps just that number of the
most active columns in each sliding window over the column space. So
inhibition is applied in local spatial areas, but within each area the
spatial relationships between columns are still ignored.&lt;/p&gt;

&lt;p&gt;The local window size is not a parameter but is
&lt;a href=&quot;https://github.com/numenta/nupic/blob/df37f7853775efd771d2822a671bafc2c18286b8/nupic/research/spatial_pooler.py#L831&quot;&gt;calculated&lt;/a&gt;
as the average receptive field size, mapped back from the input space
to the column space.&lt;/p&gt;

&lt;h2 id=&quot;proposed-algorithm&quot;&gt;Proposed algorithm&lt;/h2&gt;

&lt;p&gt;I have tried to model the inhibitory waves around active columns, and
their relative timing to some extent. Keep in mind that my
neuroscience knowledge is poor.&lt;/p&gt;

&lt;p&gt;In a nutshell, starting with the most excited columns and working
down, each becomes active and inhibits all neighbours within a &lt;em&gt;base
distance&lt;/em&gt;; it may also inhibit further neighbours within an outer
&lt;em&gt;radius&lt;/em&gt; if their excitation is sufficiently low. Specifically, if the
neighbour’s excitation level is below a linear ramp from the original
column’s level down to zero at the outer radius. That radius is
defined by the average receptive field size. As soon as any column is
inhibited in this process it is removed from consideration.&lt;/p&gt;

&lt;p&gt;That is the inhibition algorithm itself, but notice that it does not
enforce any particular activation density. Also it may be overly
sensitive to noise in areas lacking any real signal (a criticism that
probably applies to any local algorithm). So, in addition, I have made
the &lt;em&gt;stimulus threshold&lt;/em&gt; an adaptive parameter, changing slightly each
time step according to the actual vs target activation density.
Columns with excitation below the stimulus threshold can not become
active. This is a global mechanism, but operates at a longer time
scale; perhaps there is some neurochemical process like this?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;UPDATE 2014-11-25:&lt;/strong&gt; There is a problem with the adaptive stimulus
threshold. After training on familiar input for a while, it becomes
well recognised with many connected synapses so the stimulus
threshold rises. When new input comes in, it has fewer connected
synapses, i.e. a lower stimulus value. This gives rises to too
few—even zero—active columns. Bad! Anyway, we can simply take
the top N most excited columns after accounting for local
inhibition. That is the same as having the threshold adapt
immediately within one time step.&lt;/p&gt;

  &lt;p&gt;This algorithm is a “local algorithm” in the sense that it considers
local spatial interactions in its processing. But it is not a “local
algorithm” in the sense that its computation is distributed. Of
course one could split up the column space and run inhibition on
each chunk, but that is not my focus here. Rather I am interested in
whether accounting for local interactions could have some effect on
information processing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;interactive-demonstration&quot;&gt;Interactive demonstration&lt;/h2&gt;

&lt;p&gt;The plot below shows 200 columns along the x axis with some generated
excitation levels on the y axis. Red columns are active. Hit the
&lt;strong&gt;Step&lt;/strong&gt; button a few times to see the actual activation level
converge on the target activation level, and to contrast this kind of
local inhibition with global inhibition (mirrored below the axis):&lt;/p&gt;

&lt;iframe src=&quot;/assets/2014-11-13/local_inhibition/inhibition_viz.html&quot; width=&quot;620&quot; height=&quot;500&quot;&gt;
Your browser does not support iframes.
&lt;/iframe&gt;

&lt;p&gt;And a similar demonstration in 2D:&lt;/p&gt;

&lt;iframe src=&quot;/assets/2014-11-13/local_inhibition/inhibition_2d_viz.html&quot; width=&quot;620&quot; height=&quot;550&quot;&gt;
Your browser does not support iframes.
&lt;/iframe&gt;

&lt;p&gt;Finally here is a basic example of the algorithm running in HTM:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2014-11-13/demos/isolated_2d.html&quot;&gt;Isolated fixed sequences 2D&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Google Chrome browser recommended.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;perf&quot;&gt;Perf&lt;/h2&gt;

&lt;p&gt;Of course local inhibition is slower to compute than the simple global
approach, which scales approximately linearly by the number of
columns. But it is not as bad as &lt;em&gt;(number of columns) X (inhibition
radius)&lt;/em&gt;, because as columns are inhibited they are removed and
ignored. The performance depends on distributional properties of the
input. In one (fairly arbitrary) test I ran on Comportex, the local
algorithm was about 25X slower than a simple sort. However, usually
the inhibition step is not the slowest part of a time step in
Comportex; rather, learning on proximal synapses takes longer.&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;The demonstrations here were compiled from ComportexViz 0.0.6
(&lt;a href=&quot;https://github.com/nupic-community/comportexviz/blob/master/examples/local_inhibition/comportexviz/local-inhibition-1d.cljs&quot;&gt;local-inhibition-1d.cljs&lt;/a&gt;,
&lt;a href=&quot;https://github.com/nupic-community/comportexviz/blob/master/examples/local_inhibition/comportexviz/local-inhibition-2d.cljs&quot;&gt;local-inhibition-2d.cljs&lt;/a&gt;).
with Comportex 0.0.6
(inhibition code is in
&lt;a href=&quot;https://github.com/nupic-community/comportex/blob/9af5dd11ad1b9971eaee81e2190288c1576d7878/src/cljx/org/nfrac/comportex/inhibition.cljx#L64&quot;&gt;inhibition.cljx&lt;/a&gt;
and tuning the stimulus threshold is in
&lt;a href=&quot;https://github.com/nupic-community/comportex/blob/9af5dd11ad1b9971eaee81e2190288c1576d7878/src/cljx/org/nfrac/comportex/cells.cljx#L494&quot;&gt;cells.cljx&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;UPDATE 2014-11-25:&lt;/strong&gt; fixed version is Comportex 0.0.7 and
ComportexViz 0.0.7. Inhibition code is in
&lt;a href=&quot;https://github.com/nupic-community/comportex/blob/cdb4fa597699548dc9ca5a17cbc35b279e241e18/src/cljx/org/nfrac/comportex/inhibition.cljx#L102&quot;&gt;inhibition.cljx&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As always, I value your advice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>HTM protocols</title>
   <link href="http://floybix.github.io/2014/11/05/htm-protocols"/>
   <updated>2014-11-05T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/11/05/htm-protocols</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;In which I explain two of the central abstractions in Comportex (my
HTM project). Firstly the decomposition of a time step into
activation, learning, and depolarisation phases across an HTM network.
Secondly the interface for working with synapse connection graphs. I
need to know if my abstractions have problems, before I go further
down the road of building on them. Also, they may help others to think
about HTM in software.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Clojure, &lt;a href=&quot;http://clojure.org/protocols&quot;&gt;protocols&lt;/a&gt; make
abstractions. They are minimalist. Elegant weapons, for a more…
civilized age &lt;sup&gt;&lt;a href=&quot;http://xkcd.com/297/&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. Defining a
protocol simply creates the named functions, but leaves their
implementations to be supplied separately as needed.&lt;/p&gt;

&lt;p&gt;Comportex’s protocols cover networks, regions, layers, synapses,
sensory inputs, encoders and topologies in about 150 lines (er, thanks
in part to the paucity of documentation), and can be read in full at
&lt;a href=&quot;https://github.com/nupic-community/comportex/blob/master/src/org/nfrac/comportex/protocols.cljc&quot;&gt;protocols.cljc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I would like to focus on two protocols.&lt;/p&gt;

&lt;h2 id=&quot;activate-learn-depolarise&quot;&gt;Activate, Learn, Depolarise&lt;/h2&gt;

&lt;p&gt;I try to follow &lt;a href=&quot;http://thechangelog.com/rich-hickeys-greatest-hits/&quot;&gt;Rich Hickey’s design
philosophy&lt;/a&gt;:
design is about “taking things apart so you can put them back
together”. He talks about making sure each component is just doing one
thing, “decomplecting” concerns to make something simple.&lt;/p&gt;

&lt;p&gt;In my early work on Comportex I had a &lt;code class=&quot;highlighter-rouge&quot;&gt;step&lt;/code&gt; function for regions
which activated cells, performed learning by updating synapses, and
calculated depolarised cells. These concerns were complected.&lt;/p&gt;

&lt;p&gt;Eventually I started thinking about networks of regions, where there
are feed-forward inputs to regions from below, but also feedback
connections from above, motor signal connections from below and maybe
other connections. As I imagine it the feed-forward inputs should
propagate through the whole network first, then feedback, motor, and
other signals to distal synapses propagate afterwards. So the feedback
passed down would reflect the state of higher regions &lt;em&gt;after&lt;/em&gt; they
received feed-forward input from the same time step.&lt;/p&gt;

&lt;p&gt;This idea is behind the &lt;code class=&quot;highlighter-rouge&quot;&gt;PHTM&lt;/code&gt; protocol (the prefix &lt;code class=&quot;highlighter-rouge&quot;&gt;P&lt;/code&gt; is
conventional). To satisfy the protocol, an object must implement its
functions: &lt;code class=&quot;highlighter-rouge&quot;&gt;htm-sense&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;htm-activate&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;htm-learn&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;htm-depolarise&lt;/code&gt;.
Such an implementation is given in
&lt;a href=&quot;https://github.com/nupic-community/comportex/blob/master/src/org/nfrac/comportex/core.cljc&quot;&gt;core.cljc&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;UPDATE 2014-11-25:&lt;/strong&gt; Originally I had sensory input on each time
step arriving via input sources/channels embedded in an HTM model.
&lt;a href=&quot;https://twitter.com/mrcslws&quot;&gt;Marcus Lewis&lt;/a&gt; helped me to realise the
path of functional purity (and clojurescript compatibility) lies in
passing the input value as an argument to the step function. Exactly
the kind of feedback I needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;UPDATE 2015-08-28:&lt;/strong&gt; The activation step has been further
decomposed into &lt;code class=&quot;highlighter-rouge&quot;&gt;htm-sense&lt;/code&gt; to encode input senses and
&lt;code class=&quot;highlighter-rouge&quot;&gt;htm-activate&lt;/code&gt; to do the feed-forward pass through the network,
activating cells and columns. See
&lt;a href=&quot;https://github.com/nupic-community/comportex/issues/19#issuecomment-133713863&quot;&gt;issue #19&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defprotocol&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PHTM&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A network of regions, forming Hierarchical Temporal Memory.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-sense&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in-value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-activate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-learn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-depolarise&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;htm-step&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in-value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-sense&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in-value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-activate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-learn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;htm-depolarise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I define a function here too, &lt;code class=&quot;highlighter-rouge&quot;&gt;htm-step&lt;/code&gt;, which takes an object
satisfying the &lt;code class=&quot;highlighter-rouge&quot;&gt;PHTM&lt;/code&gt; protocol and applies to it the functions in
canonical order. This function returns the HTM network advanced one
time step and is the centrepiece of the API.&lt;/p&gt;

&lt;p&gt;Depolarisation comes after activation because we often want to use
depolarised cells to make predictions of the next time step. One
consequence of this design is that motor signals, which act to
depolarise cells, should appear the timestep &lt;em&gt;before&lt;/em&gt; a corresponding
sensory (feed-forward) signal in order to be useful. I think that is
reasonable.&lt;/p&gt;

&lt;p&gt;Learning comes before depolarisation because it needs to know the
previously depolarised cells (when “punishing” unfulfilled
predictions); if learning was the last phase we would need to store
the values for an extra step—not a big deal but slightly less
elegant.&lt;/p&gt;

&lt;p&gt;Of course for all this to work it needs to call corresponding
functions on individual regions, and within regions on layers of
cells.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defprotocol&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PRegion&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Cortical regions need to extend this together with PTopological,
   PFeedForward, PTemporal, PParameterised.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;region-activate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ff-bits&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stable-ff-bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;region-learn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ff-bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;region-depolarise&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distal-ff-bits&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distal-fb-bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here the &lt;code class=&quot;highlighter-rouge&quot;&gt;ff-bits&lt;/code&gt; argument is the set of active bits coming in
through a feed-forward pathway, and &lt;code class=&quot;highlighter-rouge&quot;&gt;fb-bits&lt;/code&gt; is the set of bits
coming in through a feed-back pathway. In the depolarise function
there is the odd “&lt;code class=&quot;highlighter-rouge&quot;&gt;distal-ff-bits&lt;/code&gt;” argument: this will be motor
commands from below and maybe sensory too. I separate ff from fb in
the depolarise function because we might want to selectively enable or
disable feedback.&lt;/p&gt;

&lt;p&gt;And similarly within a region there are &lt;code class=&quot;highlighter-rouge&quot;&gt;layer-activate&lt;/code&gt;,
&lt;code class=&quot;highlighter-rouge&quot;&gt;layer-learn&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;layer-depolarise&lt;/code&gt; functions.&lt;/p&gt;

&lt;h2 id=&quot;synapse-graphs&quot;&gt;Synapse Graphs&lt;/h2&gt;

&lt;p&gt;The information content and computational load of HTMs is in the
synapse connections. Usually, proximal synapses are represented and
used very differently to distal synapses (e.g. in Numenta’s CLA White
Paper). Potential proximal synapses are represented as a fixed
explicit list, whereas distal synapses start empty and grow and die
over time. I wanted to try the latter implicit approach for proximal
synapses too. This led to a protocol encompassing both cases.&lt;/p&gt;

&lt;p&gt;Synapse graphs as presented here represent the connections from a set
of sources to a set of targets. In the case of proximal synapses the
sources will be input bits and the targets will be columns. In the
case of distal synapses the sources will be cells (typically in the
same layer but not necessarily) and the targets will be distal
dendrite segments.&lt;/p&gt;

&lt;p&gt;The choice of how to represent the set of potential synapses,
explicitly or implicitly, can be made separately.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;UPDATE 2015-08-28:&lt;/strong&gt; Originally I had defined functions here that
operated on a single synaptic target at a time, reinforcing its
synapses or adding or removing synapses. So the learning algorithms
involved looping over a lot of targets to update each
one. Essentially, procedural programming.&lt;/p&gt;

  &lt;p&gt;I realised a better way is to build a list representing the updates,
before applying those updates in one go: &lt;code class=&quot;highlighter-rouge&quot;&gt;bulk-learn&lt;/code&gt;. Like the way
Datomic works, you build up transaction data structures before
submitting them. This is faster because it allows transient mutation
to be used (we don’t need intermediate states); allows the updates
to be inspected easily; and is just cleaner.&lt;/p&gt;

  &lt;p&gt;Also, I moved &lt;code class=&quot;highlighter-rouge&quot;&gt;excitations&lt;/code&gt;, the function calculating activity in a
whole layer of cells given its input bits, into the protocol. As
with &lt;code class=&quot;highlighter-rouge&quot;&gt;bulk-learn&lt;/code&gt;, abstracting the process improved performance by
allowing internal use of transients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defprotocol&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PSynapseGraph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;The synaptic connections from a set of sources to a set of targets.
   Synapses have an associated permanence value between 0 and 1; above
   some permanence level they are defined to be connected.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;in-synapses&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target-id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;All synapses to the target. A map from source ids to permanences.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sources-connected-to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target-id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;The collection of source ids actually connected to target id.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;targets-connected-from&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source-id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;The collection of target ids actually connected from source id.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;excitations&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;active-sources&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stimulus-threshold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Computes a map of target ids to their degree of excitation -- the
    number of sources in `active-sources` they are connected to -- excluding
    any below `stimulus-threshold`.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bulk-learn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seg-updates&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;active-sources&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Applies learning updates to a batch of targets. `seg-updates` is
    a sequence of SegUpdate records, one for each target dendrite
    segment.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A question arises of how to look up the target dendrite segments by
cell in this model (since target ids refer to segments, not cells).
This can be solved with another protocol which is extended only to
distal synapse graphs:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defprotocol&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PSegments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cell-segments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cell-id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A vector of segments on the cell, each being a synapse map.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;alternative-backends&quot;&gt;Alternative backends&lt;/h2&gt;

&lt;p&gt;Protocols leave their implementation open, so as long as we program to
protocols we can write and use alternative backends. This will be
important. The demos I run in Comportex today are at a tiny toy scale.
But Fergal Byrne has been designing a scalable architecture for
running HTMs in Clojure, in
&lt;a href=&quot;https://github.com/nupic-community/clortex&quot;&gt;Clortex&lt;/a&gt;. I hope that
with the right protocols our efforts can be made to work together.&lt;/p&gt;

&lt;p&gt;As always, I value your thoughts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Hackathon demo: cortical.io encoder</title>
   <link href="http://floybix.github.io/2014/10/27/hackathon_demo"/>
   <updated>2014-10-27T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/10/27/hackathon_demo</id>
   <content type="html">
&lt;p&gt;Last weekend I joined &lt;a href=&quot;http://www.meetup.com/numenta/events/202402962/&quot;&gt;Numenta’s Fall 2014
Hackathon&lt;/a&gt;. A
fantastic event. It underscores Numenta’s approach of being totally
open with their work and supportive of the community.&lt;/p&gt;

&lt;p&gt;It feels like we are at the cusp of a revolution, where a few more
good ideas will really make this thing fly. So it was inspiring to
hear from Jeff Hawkins about the current challenges, and to see
Chetan and Yuwei’s &lt;a href=&quot;http://www.youtube.com/watch?v=-aCYujW7QSc&quot;&gt;brilliant demonstration of temporal pooling in
action&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was particularly glad to meet fellow functional programmers
including &lt;em&gt;system designer and Clojurist&lt;/em&gt; Fergal Byrne, &lt;em&gt;Clojurist /
Clojurescripter&lt;/em&gt; Marcus Lewis, &lt;em&gt;Racketeer&lt;/em&gt; Rian Shams and &lt;em&gt;Lisper&lt;/em&gt;
Eric McCarthy.&lt;/p&gt;

&lt;p&gt;My hack was a &lt;a href=&quot;http://cortical.io&quot;&gt;cortical.io&lt;/a&gt; encoder, for semantic
representation of words as input to HTM. In Comportex. The approach
was to make requests to the &lt;a href=&quot;http://www.cortical.io/developers_apidocumentation.html&quot;&gt;cortical.io REST
API&lt;/a&gt; and
store the results in a cache used by the encoder itself. I did this in
both Clojure (JVM) and Clojurescript (Javascript) implementations.
Since &lt;code class=&quot;highlighter-rouge&quot;&gt;cortical.io&lt;/code&gt; produces two dimensional bit arrays, I also
implemented two dimensional field visualisations in ComportexViz.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here it is:&lt;/strong&gt; &lt;a href=&quot;/assets/2014-10-27/cortical_io.html&quot;&gt;interactive demo of cortical.io
encoder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: may take up to a minute to initialise. Maximise browser
window before loading page. Google Chrome browser recommended.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Er, there is also &lt;a href=&quot;http://www.youtube.com/watch?v=hE6alw_HHrk&quot;&gt;a video&lt;/a&gt;
of me presenting this… but I didn’t present it well. I was so
focused on getting something working that I put zero minutes of
preparation into the talk. I did not even try to address &lt;em&gt;why&lt;/em&gt; I use
Clojure. But Rian Shams did give &lt;a href=&quot;http://www.youtube.com/watch?v=Zz5fFAEYKHc&quot;&gt;a nice introduction to the joys of
functional programming&lt;/a&gt;.
Good on him.&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;The demo here was compiled from
&lt;a href=&quot;https://github.com/nupic-community/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.5 with
&lt;a href=&quot;https://github.com/nupic-community/comportexviz/&quot;&gt;ComportexViz&lt;/a&gt; 0.0.5.&lt;/p&gt;

&lt;p&gt;The Clojure version of the encoder is just this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.nfrac.comportex.cortical-io&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.nfrac.comportex.protocols&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.nfrac.comportex.topology&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;topology&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.nfrac.comportex.util&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clojure.string&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clj-http.client&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base-uri&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://api.cortical.io/rest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retina-size&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:retina_name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en_associative&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get-fingerprint&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;http/post&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base-uri&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/expressions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:query-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:content-type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:form-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:term&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:with-credentials?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:throw-exceptions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:headers&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;api-key&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get-similar-terms&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max-n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;http/post&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base-uri&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/expressions/similar_terms&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:query-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;assoc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:get_fingerprint&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:max_results&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max-n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:content-type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:form-params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:positions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:with-credentials?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:throw-exceptions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:headers&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;api-key&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apply-offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;into&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random-sdr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retina-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;repeatedly&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.02&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;util/rand-int&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;look-up-fingerprint&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Returns a fingerprint for the term, being a set of active indices.
   If the term is not found in the cache, makes a synchronous call to
   cortical.io REST API and stores the result in the cache (an atom).
   If the request to cortical.io fails, the term is assigned a new
   random SDR.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str/lower-case&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;swap!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;assoc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-fingerprint&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;http/success?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cortical.io lookup of term failed:&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;random-sdr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cortical-io-encoder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min-votes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;topo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;topology/make-topology&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retina-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reify&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p/PTopological&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;topology&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;topo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p/PEncodable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cond-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;look-up-fingerprint&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zero?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;apply-offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bit-votes&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;votes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;votes&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min-votes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                         &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bit-votes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-similar-terms&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;http/success?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)})))))))))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If used directly, the encoder above makes synchronous calls to the
REST API, which will slow things down. A better way is to run a
separate thread to do the API calls while the main thread takes care
of the HTM algorithm. Code for that is given in
&lt;a href=&quot;https://github.com/nupic-community/comportex/blob/master/src/cljx/org/nfrac/comportex/demos/cortical_io_channel.clj#L65&quot;&gt;cortical_io_channel.clj&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results?&lt;/h2&gt;

&lt;p&gt;Not really.&lt;/p&gt;

&lt;p&gt;Just as the hackathon was wrapping up I fed in some of &lt;a href=&quot;https://github.com/numenta/nupic.nlp-examples/tree/master/resources/text&quot;&gt;these
children’s
stories&lt;/a&gt;
repeated a couple of times. I ended up just feeding them in as a
continuous stream of words without sentence breaks. Then I fed in the
start of a sentence and looked up the top prediction of the next word.
I fed that in as actual input, then asked for the next word, etc. I
call this a stream of associations. It was not scientific at all but
here are a couple of the more interesting samples:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the poor little&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stream-of-associations&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;riding&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hood&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;said&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;little&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hoops&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arranged&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gone&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left-handed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;what a good&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stream-of-associations&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mother&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;duck&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;said&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;he&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sure&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;issues&quot;&gt;Issues&lt;/h2&gt;

&lt;p&gt;As Jeff mentioned during Francisco Webber’s talk at the hackathon, the
spatial clustering in cortical.io fingerprints may actually be
undesirable for use in HTM. Because there is local inhibition of
column activation, if there are only a few small clusters of input
bits, this may produce a too-sparse activation pattern, losing
information.&lt;/p&gt;

&lt;p&gt;Also, the lookup of similar terms usually seems to produce unlikely
suggestions. This may be resolved by refining the proximal synapse
fields after long training. But for quick usage it seems we get more
reasonable results by comparing the predicted bits directly against
the words we have seen before.&lt;/p&gt;

&lt;p&gt;And of course performance. In particular, my Clojurescript
implementation is very very slow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Learning Simple Sentences</title>
   <link href="http://floybix.github.io/2014/10/15/learning-simple-sentences"/>
   <updated>2014-10-15T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/10/15/learning-simple-sentences</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;In which I make an interactive demo of word sequence learning with
HTM, with an eye to how generalisation might happen. I find some
generalisation through word representations mixing their feed-forward
receptive fields. This occurs because I bias column activations to
depolarised cells. Of course this is only a superficial start at
looking at generalisation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-October/001403.html&quot;&gt;Rob Freeman’s
insistence&lt;/a&gt;
I’ve made up a demo of word sequence learning in HTM. I was resistant
because I thought generalisation in language was inextricably tied up
with the semantic content of the concepts involved. Rob suggested just
“babbling” with some arbitrary words and looking at how generalisation
might happen nonetheless. I am still not entirely convinced, but it is
intriguing.&lt;/p&gt;

&lt;p&gt;So I made up some simple sentences which share context. Each sentence
is presented as a sequence of words, where each word is given a unique
representation completely unrelated to the other words. This is in
contrast to the approach of &lt;a href=&quot;http://cortical.io/&quot;&gt;cortical.io&lt;/a&gt;, which
represents semantic overlap between words in their encoding for input
to HTM (not that I know anything much about it).&lt;/p&gt;

&lt;pre&gt;
&amp;gt; Jane has eyes .
&amp;gt; Jane has a head .
&amp;gt; Jane has a mouth .
&amp;gt; Jane has a brain .
&amp;gt; Jane has a book .
&amp;gt; Jane has no friend .
&amp;gt; Chifung has eyes .
&amp;gt; Chifung has a head .
&amp;gt; Chifung has a mouth .
&amp;gt; Chifung has a brain .
&amp;gt; Chifung has no book .
&amp;gt; Chifung has a friend .
&lt;/pre&gt;

&lt;p&gt;Although these sentences sound as if they come from a logic system,
remember that HTM is seeing just a sequence of meaningless tokens. The
words are to help us think about what kinds of generalisation might be
reasonable. As an input stream, the above is exactly equivalent to:&lt;/p&gt;

&lt;pre&gt;
V X Y Z O
V X Y A B O
V X Y A C O
V X Y A D O
V X Y A E O
V X Y F G O
V H Y Z O
V H Y A B O
V H Y A C O
V H Y A D O
V H Y F E O
V H Y A G O
&lt;/pre&gt;

&lt;p&gt;To me it seems reasonable to generalise on these sequences such that
when it gets to “&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung has a&lt;/code&gt;”, before &lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt;, then &lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;book&lt;/code&gt; could be predicted as possible options (along with &lt;code class=&quot;highlighter-rouge&quot;&gt;head&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;mouth&lt;/code&gt;). This is generalisation because it would never have seen the
exact sequence “&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung has a brain&lt;/code&gt;” before.&lt;/p&gt;

&lt;p&gt;Some technical details with the input. I present each sentence 3 times
so that synapses can learn enough to become connected. I start by
presenting the words “Jane” and “Chifung” on their own to stabilise
their feed-forward receptive fields. Sentences are separated by a gap
(a time step with no input at all), which allows the next sequence to
start fresh, without continuous context. It is useful to include a
start token (“&amp;gt;”) and end token (“.”) on each, so that words can have
a specific representation for starting a sentence, and so the end of a
sentence can be predicted.&lt;/p&gt;

&lt;h3 id=&quot;predictions-and-votes&quot;&gt;Predictions and votes&lt;/h3&gt;

&lt;p&gt;How can we extract predictions from HTM in terms of the source input
words? Start with the set of cells in the predictive state. Through
their columns, trace back their proximal synapses connected to the
encoded input bit array. This gives a number of &lt;strong&gt;votes&lt;/strong&gt; (number of
connected synapses) for each input bit. Going over each possible word,
work out the percentage of votes falling in that word’s bit-set, and
the average number of votes over the word’s complete bit-set. (These
would only give different orderings if the inputs were of different
sizes).&lt;/p&gt;

&lt;h2 id=&quot;play-with-it&quot;&gt;Play with it&lt;/h2&gt;

&lt;p&gt;Here’s the interactive demo. You also have the option to enter your
own input!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2014-10-15/simple_sentences.html&quot;&gt;Simple sentences demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Maximise browser window before loading page. Google Chrome
browser recommended.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;Here are some highlights of the above demo using my default parameter
values.&lt;/p&gt;

&lt;p&gt;First, a very basic sort of generalisation can be seen as a
consequence of &lt;em&gt;bursting&lt;/em&gt;. Columns burst when they are activated by
input they didn’t predict. In that case all cells in the columns
become active, and consequently, predictions are made from that input
in &lt;em&gt;any&lt;/em&gt; previous context. For example, when first presented with
“&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung has&lt;/code&gt;”, that “&lt;code class=&quot;highlighter-rouge&quot;&gt;has&lt;/code&gt;” is bursting and so opens up the
previously-learned associations (see &lt;strong&gt;Predictions&lt;/strong&gt; at the bottom
left):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-10-15/generalisation_bursting.png&quot; alt=&quot;Bursting,
 predictions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;However, that generalisation is short-lived, since as soon as the
transition “&lt;code class=&quot;highlighter-rouge&quot;&gt;Chifung has&lt;/code&gt;” is learned, it gets its own representation
and is no longer bursting (note no predictions this time):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-10-15/generalisation_specialisation.png&quot; alt=&quot;Not bursting, lack of
 predictions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A curious thing happens a little later on. Some generalisation appears
to happen, specifically &lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;book&lt;/code&gt; come up as predictions when
they haven’t been seen in the context before:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-10-15/generalisation_wtf.png&quot; alt=&quot;Lightly predicted from 'has' out of
 context&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that the predictions are fairly light, at only 1 to 2 votes per
bit, so not enough to stop the transition from bursting on first
exposure to an actual input of “&lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt;”.&lt;/p&gt;

&lt;p&gt;These predictions are a result of the columns representing “&lt;code class=&quot;highlighter-rouge&quot;&gt;mouth&lt;/code&gt;”
overlapping—and thus sharing feed-forward synapses with—those
representing “&lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt;”, “&lt;code class=&quot;highlighter-rouge&quot;&gt;head&lt;/code&gt;” and “&lt;code class=&quot;highlighter-rouge&quot;&gt;book&lt;/code&gt;”:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-10-15/ff_synapses_mouth.png&quot; alt=&quot;Feed-forward synapses for 'mouth' overlapping with 'brain', 'head'
 and 'book'&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So, how did that arise? Well, a recently added feature in my code is
to bias columns containing predicted (depolarised) cells to become
active; an idea I got from &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-August/001165.html&quot;&gt;Fergal
Byrne&lt;/a&gt;.
When the representation of “&lt;code class=&quot;highlighter-rouge&quot;&gt;mouth&lt;/code&gt;” was first formed in “&lt;code class=&quot;highlighter-rouge&quot;&gt;Jane has a
mouth&lt;/code&gt;”, the columns/cells for “&lt;code class=&quot;highlighter-rouge&quot;&gt;head&lt;/code&gt;” were being predicted, and
consequently some became active. Since active columns adapt their
input fields to the current input, this led to the overlap in
representations. Similarly the later inputs “&lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt;” and “&lt;code class=&quot;highlighter-rouge&quot;&gt;book&lt;/code&gt;”
appeared when &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;mouth&quot;&lt;/code&gt; was predicted and so ended up overlapping with
it.&lt;/p&gt;

&lt;p&gt;I tested this by turning off the biasing behaviour
(&lt;code class=&quot;highlighter-rouge&quot;&gt;proximal-vs-distal-weight=10000&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;global-inhibition=true&lt;/code&gt;), and
sure enough the phenomenon did not occur.&lt;/p&gt;

&lt;p&gt;Here is another example of this phenomenon, this time generalising the
prediction of “&lt;code class=&quot;highlighter-rouge&quot;&gt;book&lt;/code&gt;” to “&lt;code class=&quot;highlighter-rouge&quot;&gt;mouth&lt;/code&gt;” and “&lt;code class=&quot;highlighter-rouge&quot;&gt;brain&lt;/code&gt;”:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-10-15/generalisation_wtf2.png&quot; alt=&quot;Generalising a prediction of 'book' to 'mouth' and
 'brain'&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;parameters&quot;&gt;Parameters&lt;/h2&gt;

&lt;p&gt;While all parameters are listed in the code, I’ve reproduced the
descriptions of the relevant ones here, together with their default
values in the demo.&lt;/p&gt;

&lt;p&gt;You can change them in the interactive demo and of course I encourage
you to do so.&lt;/p&gt;

&lt;h3 id=&quot;proximal-synapses-and-columns&quot;&gt;Proximal synapses and columns&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;column-dimensions = [1000]&lt;/code&gt; - size of column field as a vector, one
dimensional &lt;code class=&quot;highlighter-rouge&quot;&gt;[size]&lt;/code&gt; or two dimensional &lt;code class=&quot;highlighter-rouge&quot;&gt;[width height]&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ff-potential-radius = 1.0&lt;/code&gt; - range of potential feed-forward synapse
connections, as a fraction of the longest single dimension in the
input space.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ff-potential-frac = 0.3&lt;/code&gt; - fraction of inputs within range that will be
part of the potentially connected set.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ff-perm-inc = 0.05&lt;/code&gt; - amount to increase a synapse’s permanence value
by when it is reinforced.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ff-perm-dec = 0.01&lt;/code&gt; - amount to decrease a synapse’s permanence value
by when it is not reinforced.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ff-perm-connected = 0.20&lt;/code&gt; - permanence value at which a synapse is
functionally connected. Permanence values are defined to be
between 0 and 1.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ff-stimulus-threshold = 3&lt;/code&gt; - minimum number of active input connections
for a column to be &lt;em&gt;overlapping&lt;/em&gt; the input (i.e. active prior to
inhibition).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;distal-synapses-and-sequence-memory&quot;&gt;Distal synapses and sequence memory&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;depth = 8&lt;/code&gt; - number of cells per column.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;max-segments = 5&lt;/code&gt; - maximum number of segments per cell.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;seg-max-synapse-count = 18&lt;/code&gt; - maximum number of synapses per segment.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;seg-new-synapse-count = 12&lt;/code&gt; - number of synapses on a new dendrite
segment.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;seg-stimulus-threshold = 9&lt;/code&gt; - number of active synapses on a
dendrite segment required for it to become active.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;seg-learn-threshold = 7&lt;/code&gt; - number of active synapses on a dendrite
segment required for it to be reinforced and extended on a
bursting column.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;distal-perm-inc = 0.05&lt;/code&gt; - amount by which to increase synapse
permanence when reinforcing dendrite segments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;distal-perm-dec = 0.01&lt;/code&gt; - amount by which to decrease synapse permanence
when reinforcing dendrite segments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;distal-perm-connected = 0.20&lt;/code&gt; - permanence value at which a synapse is
functionally connected. Permanence values are defined to be
between 0 and 1.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;distal-perm-init = 0.16&lt;/code&gt; - permanence value for new synapses on
dendrite segments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;distal-punish? = false&lt;/code&gt; - whether to negatively reinforce synapses on
segments incorrectly predicting activation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;global-inhibition = false&lt;/code&gt; - whether to use the faster global algorithm
for column inhibition (just keep those with highest overlap
scores), or to apply inhibition only within a column’s
neighbours.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;inhibition-base-distance = 4&lt;/code&gt; - the distance in columns within which
a cell inhibits all neighbouring cells with lower excitation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;inhibition-speed = 2&lt;/code&gt; - controls effective inhibition distance. For
every multiple of this distance away a cell is, its excitation
must be exceeded by one extra active synapse for it to be
inhibited. E.g. if this is &lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt;, a cell X, 6 columns away from Y,
will be inhibited by Y if &lt;code class=&quot;highlighter-rouge&quot;&gt;exc(Y) &amp;gt; exc(X) + 3&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;activation-level = 0.03&lt;/code&gt; - fraction of columns that can be
active (either locally or globally); inhibition kicks in to
reduce it to this level.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;proximal-vs-distal-weight = 2&lt;/code&gt; - scaling to apply to the number of
active proximal synapses before adding to the number of active
distal synapses (on the winning segment), when selecting active
cells.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;spontaneous-activation? = false&lt;/code&gt; - if true, cells may become active with
sufficient distal synapse excitation, even in the absence of any
proximal synapse excitation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;alternative-learning? = false&lt;/code&gt; - if true, an extra learning step
happens. Alternative predictions (i.e. depolarised cells) are
carried forward an extra time step (as if the predicted cells
were active); these forward-predicted cells learn on distal
segments in the current context (as if they were active).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anyway, I’m not sure how generally desirable the behaviour I described
above is. I am sure that this is only a very superficial start at
looking at generalisation.&lt;/p&gt;

&lt;p&gt;As always, I value your advice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;The demo here was compiled from
&lt;a href=&quot;https://github.com/floybix/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.4 with
&lt;a href=&quot;https://github.com/floybix/comportexviz/&quot;&gt;ComportexViz&lt;/a&gt; 0.0.4&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Temporal Pooling of Isolated Sequences</title>
   <link href="http://floybix.github.io/2014/09/29/temporal-pooling-of-isolated-sequences"/>
   <updated>2014-09-29T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/09/29/temporal-pooling-of-isolated-sequences</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;In which I fall back to testing temporal pooling on the simplest
possible problem, that of fixed sequences presented in isolation from
each other. I find that simple sequences do get a temporal pooling
representation that is both sensitive and specific. Longer sequences
are not fully covered due to the decay rate in temporal pooling
scores; this needs rethinking. Sequences which start the same and
later diverge give rise to pooled representations over them both
together, as well as each unique sub-sequence.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my recent post I tested a temporal pooling algorithm on an input
stream consisting of fixed sequences randomly mixed together, with
poor results. On &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-September/001377.html&quot;&gt;Rob Freeman’s
suggestion&lt;/a&gt;
I went on to test it with the simpler problem of fixed sequences in
isolation. I should have done that first, of course…&lt;/p&gt;

&lt;h2 id=&quot;see-it-run&quot;&gt;See it run&lt;/h2&gt;

&lt;p&gt;The problem uses the same fixed sequences as last time but presented
randomly in series, separated by a small gap. As before this problem
comes with an interactive demo.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2014-09-29/isolated_1d.html&quot;&gt;Sequences in isolation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;_Note: Maximise browser window before loading page. Google Chrome
browser recommended.&lt;/p&gt;

&lt;p&gt;The sequence are well predicted after a few hundred time steps, and
consequently temporal pooling emerges in the higher-level region.&lt;/p&gt;

&lt;p&gt;As before, let’s try to measure this.&lt;/p&gt;

&lt;h2 id=&quot;measurement&quot;&gt;Measurement&lt;/h2&gt;

&lt;p&gt;So I “warmed up” the system for 4000 time steps, keeping the following
2000 time steps. I filtered them down to where the given pattern
occurs (excluding the first step it appears on, which is
unpredictable), and selected the top 3 most frequently active temporal
pooling cells. These are my candidates.&lt;/p&gt;

&lt;p&gt;It is then a simple matter to compute sensitivity, specificity and
precision for each candidate cell. The results are shown in the
following table.&lt;/p&gt;

&lt;style&gt;
td, th { white-space: nowrap; }
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;pattern&lt;/th&gt;
      &lt;th&gt;candidate&lt;/th&gt;
      &lt;th&gt;in-steps&lt;/th&gt;
      &lt;th&gt;out-steps&lt;/th&gt;
      &lt;th&gt;active-in&lt;/th&gt;
      &lt;th&gt;active-out&lt;/th&gt;
      &lt;th&gt;sensitivity&lt;/th&gt;
      &lt;th&gt;specificity&lt;/th&gt;
      &lt;th&gt;precision&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;run-0-5&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;154&lt;/td&gt;
      &lt;td&gt;925&lt;/td&gt;
      &lt;td&gt;154&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-0-5&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;154&lt;/td&gt;
      &lt;td&gt;925&lt;/td&gt;
      &lt;td&gt;154&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-0-5&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;154&lt;/td&gt;
      &lt;td&gt;925&lt;/td&gt;
      &lt;td&gt;154&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rev-5-1&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;96&lt;/td&gt;
      &lt;td&gt;990&lt;/td&gt;
      &lt;td&gt;96&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rev-5-1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;96&lt;/td&gt;
      &lt;td&gt;990&lt;/td&gt;
      &lt;td&gt;96&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rev-5-1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;96&lt;/td&gt;
      &lt;td&gt;990&lt;/td&gt;
      &lt;td&gt;96&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;104&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.89&lt;/td&gt;
      &lt;td&gt;0.56&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.88&lt;/td&gt;
      &lt;td&gt;0.53&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.88&lt;/td&gt;
      &lt;td&gt;0.53&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;0.47&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;0.47&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;128&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.87&lt;/td&gt;
      &lt;td&gt;0.48&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;twos&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;231&lt;/td&gt;
      &lt;td&gt;846&lt;/td&gt;
      &lt;td&gt;198&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;twos&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;231&lt;/td&gt;
      &lt;td&gt;846&lt;/td&gt;
      &lt;td&gt;198&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;twos&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;231&lt;/td&gt;
      &lt;td&gt;846&lt;/td&gt;
      &lt;td&gt;198&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;saw-10-15&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;203&lt;/td&gt;
      &lt;td&gt;879&lt;/td&gt;
      &lt;td&gt;203&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;saw-10-15&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;203&lt;/td&gt;
      &lt;td&gt;879&lt;/td&gt;
      &lt;td&gt;174&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;saw-10-15&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;203&lt;/td&gt;
      &lt;td&gt;879&lt;/td&gt;
      &lt;td&gt;174&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The results are encouraging. The first two patterns are pooled over
perfectly by several candidate cells. The next two—&lt;code class=&quot;highlighter-rouge&quot;&gt;run-6-10&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;jump-6-12&lt;/code&gt;—show good sensitivity but lower specificity (precision
only 50%). The last two patterns—&lt;code class=&quot;highlighter-rouge&quot;&gt;twos&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;saw-10-15&lt;/code&gt;—show good
specificity but reduced sensitivity at 86% (although one cell managed
to cover &lt;code class=&quot;highlighter-rouge&quot;&gt;saw-10-15&lt;/code&gt; completely).&lt;/p&gt;

&lt;h2 id=&quot;ad-lib-hypotheses&quot;&gt;ad-lib hypotheses&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Patterns &lt;code class=&quot;highlighter-rouge&quot;&gt;run-6-10&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;jump-6-12&lt;/code&gt; share their first few elements
so are probably pooled over by the same cells (thus 50%-50%
precision). I hope there will be other cells which distinguish them by
pooling over the parts which make them unique.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The last two patterns are the longest sequences. The temporal
pooling scores decay over time and so towards the end of the sequence
they may start to be dominated by current feed-forward activation,
even in the absence of bursting.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sensitivity-over-long-sequences&quot;&gt;Sensitivity over long sequences&lt;/h2&gt;

&lt;p&gt;Let’s look over the same plot as last time, showing candidate cell
activations over each pattern instance. This display helps to diagnose
problems with sensitivity (coverage of the target sequence) so it only
makes sense to look at those with imperfect sensitivity, &lt;code class=&quot;highlighter-rouge&quot;&gt;twos&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;saw-10-15&lt;/code&gt;. Here we show cells in red for active and in black for
inactive.&lt;/p&gt;

&lt;script src=&quot;http://variancecharts.com/cdn/variance-noncommercial-standalone-6d26aa2.min.js&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt;

&lt;style&gt;
#runs-plot {
  width: 800px;
  height: 300px;
  margin-left: -60px;
  padding: 40px 20px 40px 60px;
  color: #444444;
  font-family: Helvetica, Arial, sans-serif;
  font-weight: bold;
  font-size: 14px;
}
#runs-plot chart {
  width: 100%;
  height: 45%;
  margin-bottom: 40px;
  background-color: rgba(0,0,0,0.05);
}
#runs-plot .legend-y {
  position: absolute;
  left: -80px;
  top: 50%;
  transform: rotate(-90deg);
}
#runs-plot .legend-x {
  position: absolute;
  width: 100%;
  text-align: center;
  bottom: -30px;
}
#runs-plot .chart-title {
  position: absolute;
  width: 100%;
  text-align: left;
  top: -20px;
}
#runs-plot point {
  width: 6px;
  height: 6px;
  margin-left: -3px;
  margin-top: -3px;
}
#runs-plot .active1 point {
  background-color: rgba(255,0,0,0.5);
}
#runs-plot .active0 point {
  background-color: rgba(0,0,0,0.5);
}
#runs-plot range {
  background-color: rgba(0,0,0,0.10);
  border: 1px solid rgba(0,0,0,0.15);
  border-width: 0px 1px;
}
&lt;/style&gt;

&lt;div id=&quot;runs-plot&quot;&gt;

  &lt;link id=&quot;twos-consistency&quot; rel=&quot;variance-data&quot; href=&quot;/assets/2014-09-29/isolated-twos-consistency.csv&quot; /&gt;
  &lt;chart data=&quot;#twos-consistency&quot; map-xy=&quot;x candidate&quot; scale-x-linear=&quot;0 11&quot; scale-y-linear=&quot;14.5 -0.5&quot;&gt;
    &lt;span class=&quot;chart-title&quot;&gt;Pattern &quot;&lt;tt&gt;twos&lt;/tt&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;legend-y&quot;&gt;15 candidate cells&lt;/span&gt;
    &lt;groups by=&quot;active&quot;&gt;
    &lt;div class=&quot;active{{active}}&quot;&gt;
      &lt;points&gt;&lt;/points&gt;
    &lt;/div&gt;
    &lt;/groups&gt;
&lt;div class=&quot;ranges&quot;&gt;
&lt;range literal-x-extent=&quot;0 1&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;2 3&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;4 5&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;6 7&quot;&gt;&lt;/range&gt;
&lt;/div&gt;
  &lt;/chart&gt;

  &lt;link id=&quot;saw-10-15-consistency&quot; rel=&quot;variance-data&quot; href=&quot;/assets/2014-09-29/isolated-saw-10-15-consistency.csv&quot; /&gt;
  &lt;chart data=&quot;#saw-10-15-consistency&quot; map-xy=&quot;x candidate&quot; scale-x-linear=&quot;0 11&quot; scale-y-linear=&quot;14.5 -0.5&quot;&gt;
    &lt;span class=&quot;chart-title&quot;&gt;Pattern &quot;&lt;tt&gt;saw-10-15&lt;/tt&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;legend-y&quot;&gt;15 candidate cells&lt;/span&gt;
    &lt;span class=&quot;legend-x&quot;&gt;Pattern instance&lt;/span&gt;
    &lt;groups by=&quot;active&quot;&gt;
    &lt;div class=&quot;active{{active}}&quot;&gt;
      &lt;points&gt;&lt;/points&gt;
    &lt;/div&gt;
    &lt;/groups&gt;
&lt;div class=&quot;ranges&quot;&gt;
&lt;range literal-x-extent=&quot;0 1&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;2 3&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;4 5&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;6 7&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;8 9&quot;&gt;&lt;/range&gt;
&lt;/div&gt;
  &lt;/chart&gt;
&lt;/div&gt;

&lt;p&gt;The plot shows that indeed that some cells falter at the end of the
sequence, while others start later, missing the first part but
reaching to the end. The logical OR of these cells would be enough to
fully cover the sequence.&lt;/p&gt;

&lt;p&gt;I ran a simulation with another even higher-level region, and the
statistics are essentially the same. The decay rate of temporal
pooling scores is the same in the higher region so the same thing is
happening. I think the mechanism needs reworking here.&lt;/p&gt;

&lt;h2 id=&quot;specificity-to-distinct-subsequences&quot;&gt;Specificity to distinct subsequences&lt;/h2&gt;

&lt;p&gt;Two patterns had problems with specificity, &lt;code class=&quot;highlighter-rouge&quot;&gt;run-6-10&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;jump-6-12&lt;/code&gt;. Their values are as follows&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;run-6-10&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[6 7 8 9 10]             &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;jump-6-12&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[6 7 8 11 12]            &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Since the first step of all sequences is unpredictable it is ignored
for pooling. The remainder consists of 2 shared values and 2 unique
values each. If we look down the list of candidate cells there are in
fact some cells which cover 50% (2 steps) of each pattern with 100%
specificity:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;pattern&lt;/th&gt;
      &lt;th&gt;candidate&lt;/th&gt;
      &lt;th&gt;in-steps&lt;/th&gt;
      &lt;th&gt;out-steps&lt;/th&gt;
      &lt;th&gt;active-in&lt;/th&gt;
      &lt;th&gt;active-out&lt;/th&gt;
      &lt;th&gt;sensitivity&lt;/th&gt;
      &lt;th&gt;specificity&lt;/th&gt;
      &lt;th&gt;precision&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;104&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.89&lt;/td&gt;
      &lt;td&gt;0.56&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.88&lt;/td&gt;
      &lt;td&gt;0.53&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;66&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0.50&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;945&lt;/td&gt;
      &lt;td&gt;66&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.50&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;0.47&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;132&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.86&lt;/td&gt;
      &lt;td&gt;0.47&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
      &lt;td&gt;…&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;16&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;58&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0.50&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;965&lt;/td&gt;
      &lt;td&gt;58&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.50&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;So that’s good—we have some cells representing “something starting
with &lt;code class=&quot;highlighter-rouge&quot;&gt;[6 7 8]&lt;/code&gt;” and other cells specific to each which appear at their
point of divergence.&lt;/p&gt;

&lt;h2 id=&quot;thoughts&quot;&gt;Thoughts&lt;/h2&gt;

&lt;p&gt;The mechanism I am using (which, by the way, was first &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-August/001112.html&quot;&gt;articulated by
Jake
Bruce&lt;/a&gt;)
produces a stream of temporal pooling cells over the life of a
sequence. That has some nice-seeming properties and some potential
problems.&lt;/p&gt;

&lt;p&gt;If we see a sequence starting from the second element, it will
activate some of these pooling cells but not the ones which are
normally activated on the first element. It seems to me that these
original pooling cells should be reactivated somehow from observing
later parts of the sequence. &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-August/001138.html&quot;&gt;I have raised this question
before&lt;/a&gt;.
One way this could work is by lateral activation between temporal
pooling cells; as they stay active they continue to learn lateral
connections to each other. Then any subset of them could complete the
missing ones &lt;em&gt;if enough lateral activation were enough to activate
cells even without feed-forward input&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As always, I value your advice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;The demo here was compiled from
&lt;a href=&quot;https://github.com/floybix/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.3-SNAPSHOT with
&lt;a href=&quot;https://github.com/floybix/comportexviz/&quot;&gt;ComportexViz&lt;/a&gt; 0.0.3-SNAPSHOT.&lt;/p&gt;

&lt;p&gt;The extra analysis code is here:
&lt;a href=&quot;/assets/2014-09-26/temporal_pooling_experiments.clj&quot;&gt;temporal_pooling_experiments.clj&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Temporal Pooling Mechanism</title>
   <link href="http://floybix.github.io/2014/09/26/temporal-pooling-mechanism"/>
   <updated>2014-09-26T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/09/26/temporal-pooling-mechanism</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;In which I implement a temporal pooling mechanism and test it with
fancy statistics, only to realise a more fundamental problem: my
sequence memory algorithm isn’t predicting mixed sequences well enough
(which is a prerequisite to temporal pooling over them).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A central idea in Hierarchical Temporal Memory is that activity in the
cortex becomes more stable as one looks further up in the hierarchy of
cortical regions. Taking vision as an example, the first regions
respond to small parts of the retina and change rapidly. Higher
regions will have stable representations of, say, an elephant as we
look at it from any angle. This process of abstracting up the
hierarchy is referred to as &lt;em&gt;temporal pooling&lt;/em&gt;. You can read Jeff
Hawkins’ &lt;a href=&quot;https://github.com/numenta/nupic/wiki/New-Ideas-About-Temporal-Pooling&quot;&gt;new ideas about temporal
pooling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There should be specific cells which become active in response to,
say, an elephant and not for anything else. We can measure this on
labelled input data with standard classification metrics. Given a
candidate cell:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Sensitivity&lt;/strong&gt; is the fraction of elephant observations on which
the cell was (correctly) active.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Specificity&lt;/strong&gt; is the fraction of non-elephant observations on
which the cell was (correctly) inactive.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Precision&lt;/strong&gt; is the fraction of the cell’s activations on which an
elephant was in fact being observed.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have attempted to implement a mechanism for temporal pooling. For
now, the implementation does not cover the full sensori-motor scheme
(only Layer 3 not Layer 4), so the experiments I describe here use
only sensory inputs.&lt;/p&gt;

&lt;h2 id=&quot;mechanism&quot;&gt;Mechanism&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;EDIT: this idea was first &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-August/001112.html&quot;&gt;articulated by Jake
Bruce&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My mechanism extends the standard &lt;em&gt;spatial pooling&lt;/em&gt; (also known as
&lt;em&gt;pattern memory&lt;/em&gt;), selecting which columns in a region become active.
The input data are the active cells from the region below, as well as
the subset of those correctly predicted by the region below, which I
call signal cells. My mechanism sets up persistent &lt;em&gt;temporal pooling
scores&lt;/em&gt; which are used like column overlap scores (i.e. to select
active columns). Temporal pooling scores are generated for a column
when it overlaps with signal cell inputs; they decay over time; they
are interrupted when dominated by other columns’ overlap scores, or
when bursting (non-signal) input comes in to the column itself.&lt;/p&gt;

&lt;p&gt;Notice that I do not explicitly turn off pooling when bursting inputs
appear nearby. Rather I assume that bursting inputs will generate
dominant overlap scores because bursting column activation is dense
compared to the sparse (one cell per column) activation from predicted
columns. Whether that is a reasonable assumption in general remains to
be seen. Further insights from the biology may help to clarify it.
Anyway, the mechanism step-by-step:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The overlap score of each column with the input is computed as
usual, but any existing temporal pooling scores (see step 5) replace
the current overlap scores.
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/pooling.cljx#L533&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The set of active columns is derived from overlap scores as usual
by lateral inhibition. Any columns which did not become active lose
their temporal pooling status.
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/pooling.cljx#L534&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If any column has a current overlap score above its previous
temporal pooling score, the previous temporal pooling score is
deleted. However, the column may remain in a temporal pooling state if
the new overlap comes from signal cells (step 5).
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/pooling.cljx#L498&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Temporal pooling scores on continuing active columns are reduced by
a decay factor.
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/pooling.cljx#L505&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If any active columns overlap with signal-cell inputs this overlap
is multiplied by a signal boosting factor and becomes the column’s new
temporal pooling score.
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/pooling.cljx#L494&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;(Sequence Memory / Temporal Memory):&lt;/em&gt; In continuing temporal
pooling columns, the previously active cell remains active.
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/sequence_memory.cljx#L278&quot;&gt;code&lt;/a&gt;
In newly active temporal pooling columns, a cell is chosen to become
the active temporal pooling cell in the usual way (depending on
whether the column itself is bursting or predicted).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The temporal pooling cell is active and thus learns by growing
lateral synapses.
&lt;a href=&quot;https://github.com/floybix/comportex/blob/779374d276ae15174d16c5ff5deab501f1f699e4/src/cljx/org/nfrac/comportex/sequence_memory.cljx#L422&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;see-it-run&quot;&gt;See it run&lt;/h2&gt;

&lt;p&gt;To test my mechanism, I made an input stream consisting of six fixed
one-dimensional sequences, each repeating at random intervals, mixed
together. See section &lt;strong&gt;The data&lt;/strong&gt; below. You can run it online and
observe temporal pooling in the higher region after about 300 time
steps:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/2014-09-26/mixed_gaps_1d.html&quot;&gt;Sequences mixed with variable gaps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Maximise browser window before loading page. Google Chrome
browser recommended.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the visualisation, columns are coloured as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;red&lt;/strong&gt; columns are bursting (active without being predicted);&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;blue&lt;/strong&gt; columns had predicted cells but did not become active;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;purple&lt;/strong&gt; columns were simultaneously active and predicted;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;green&lt;/strong&gt; columns are in a temporal pooling state and thus are
remaining active over multiple time steps. (May be green or brown
according to whether the column is itself predicted or bursting).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This screenshot gives an example of temporal pooling:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-09-26/tp_example.png&quot; alt=&quot;Temporal pooling screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The block on the left shows the input bits, arranged in time steps
from left to right. The middle block shows columns of the first
region, in corresponding time steps from left to right. &lt;em&gt;Yes it
is confusing that the “columns” (neural minicolumns) of a region are
themselves arranged in a column (tabular column) for this
visualisation.&lt;/em&gt; The next block shows columns of the second region,
which receives as input the active cells from the first region. One
time step is highlighted across all panels, and one column is selected
in the highest region, showing its constituent cells and their distal
dendrite segments.&lt;/p&gt;

&lt;p&gt;The input shows a simple repeated pattern over 6 time steps. The first
time step was not predicted since it occurs randomly, but the
following 5 time steps were predicted, as indicated by the purple
columns in the first region in those time steps. (Later steps of the
sequence occur further down in the input field, activating columns
further down in the region, so they are not visible here). Predictive
columns are also mapped back onto the input bits so we can see which
part of the input field was predicted.&lt;/p&gt;

&lt;p&gt;The correctly predicted columns in the first region generate temporal
pooling scores in the next region, visible as green and brown columns.
While the input sequence is correctly predicted, some of these
temporal pooling cells remain active.&lt;/p&gt;

&lt;p&gt;But let’s try to measure this.&lt;/p&gt;

&lt;h2 id=&quot;measurement&quot;&gt;Measurement&lt;/h2&gt;

&lt;p&gt;To measure the sensitivity, specificity and precision of temporal
pooling over a given input pattern, we need to come up with some
candidate cells. I did this by “warming up” the system for 5000 time
steps, then keeping the following 2000 time steps. I filtered them
down to where the given pattern occurs (excluding the first step it
appears on, which is unpredictable), and selected the top 3 most
frequently active temporal pooling cells. These are my candidates.&lt;/p&gt;

&lt;p&gt;It is then a simple matter to compute sensitivity, specificity and
precision for each candidate cell. The results are shown in the
following table and plot.&lt;/p&gt;

&lt;style&gt;
td, th { white-space: nowrap; }
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;pattern&lt;/th&gt;
      &lt;th&gt;candidate&lt;/th&gt;
      &lt;th&gt;in-steps&lt;/th&gt;
      &lt;th&gt;out-steps&lt;/th&gt;
      &lt;th&gt;active-in&lt;/th&gt;
      &lt;th&gt;active-out&lt;/th&gt;
      &lt;th&gt;sensitivity&lt;/th&gt;
      &lt;th&gt;specificity&lt;/th&gt;
      &lt;th&gt;precision&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;run-0-5&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;230&lt;/td&gt;
      &lt;td&gt;1724&lt;/td&gt;
      &lt;td&gt;112&lt;/td&gt;
      &lt;td&gt;27&lt;/td&gt;
      &lt;td&gt;0.49&lt;/td&gt;
      &lt;td&gt;0.98&lt;/td&gt;
      &lt;td&gt;0.81&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-0-5&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;230&lt;/td&gt;
      &lt;td&gt;1724&lt;/td&gt;
      &lt;td&gt;123&lt;/td&gt;
      &lt;td&gt;46&lt;/td&gt;
      &lt;td&gt;0.53&lt;/td&gt;
      &lt;td&gt;0.97&lt;/td&gt;
      &lt;td&gt;0.73&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-0-5&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;230&lt;/td&gt;
      &lt;td&gt;1724&lt;/td&gt;
      &lt;td&gt;108&lt;/td&gt;
      &lt;td&gt;21&lt;/td&gt;
      &lt;td&gt;0.47&lt;/td&gt;
      &lt;td&gt;0.99&lt;/td&gt;
      &lt;td&gt;0.84&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rev-5-1&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;192&lt;/td&gt;
      &lt;td&gt;1760&lt;/td&gt;
      &lt;td&gt;109&lt;/td&gt;
      &lt;td&gt;76&lt;/td&gt;
      &lt;td&gt;0.57&lt;/td&gt;
      &lt;td&gt;0.96&lt;/td&gt;
      &lt;td&gt;0.59&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rev-5-1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;192&lt;/td&gt;
      &lt;td&gt;1760&lt;/td&gt;
      &lt;td&gt;99&lt;/td&gt;
      &lt;td&gt;50&lt;/td&gt;
      &lt;td&gt;0.52&lt;/td&gt;
      &lt;td&gt;0.97&lt;/td&gt;
      &lt;td&gt;0.66&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rev-5-1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;192&lt;/td&gt;
      &lt;td&gt;1760&lt;/td&gt;
      &lt;td&gt;91&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;0.47&lt;/td&gt;
      &lt;td&gt;0.99&lt;/td&gt;
      &lt;td&gt;0.84&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;204&lt;/td&gt;
      &lt;td&gt;1745&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;151&lt;/td&gt;
      &lt;td&gt;0.57&lt;/td&gt;
      &lt;td&gt;0.91&lt;/td&gt;
      &lt;td&gt;0.43&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;204&lt;/td&gt;
      &lt;td&gt;1745&lt;/td&gt;
      &lt;td&gt;114&lt;/td&gt;
      &lt;td&gt;115&lt;/td&gt;
      &lt;td&gt;0.56&lt;/td&gt;
      &lt;td&gt;0.93&lt;/td&gt;
      &lt;td&gt;0.50&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;run-6-10&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;204&lt;/td&gt;
      &lt;td&gt;1745&lt;/td&gt;
      &lt;td&gt;111&lt;/td&gt;
      &lt;td&gt;133&lt;/td&gt;
      &lt;td&gt;0.54&lt;/td&gt;
      &lt;td&gt;0.92&lt;/td&gt;
      &lt;td&gt;0.45&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;204&lt;/td&gt;
      &lt;td&gt;1745&lt;/td&gt;
      &lt;td&gt;117&lt;/td&gt;
      &lt;td&gt;128&lt;/td&gt;
      &lt;td&gt;0.57&lt;/td&gt;
      &lt;td&gt;0.93&lt;/td&gt;
      &lt;td&gt;0.48&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;204&lt;/td&gt;
      &lt;td&gt;1745&lt;/td&gt;
      &lt;td&gt;120&lt;/td&gt;
      &lt;td&gt;149&lt;/td&gt;
      &lt;td&gt;0.59&lt;/td&gt;
      &lt;td&gt;0.91&lt;/td&gt;
      &lt;td&gt;0.45&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;jump-6-12&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;204&lt;/td&gt;
      &lt;td&gt;1745&lt;/td&gt;
      &lt;td&gt;113&lt;/td&gt;
      &lt;td&gt;151&lt;/td&gt;
      &lt;td&gt;0.55&lt;/td&gt;
      &lt;td&gt;0.91&lt;/td&gt;
      &lt;td&gt;0.43&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;twos&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;280&lt;/td&gt;
      &lt;td&gt;1680&lt;/td&gt;
      &lt;td&gt;101&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;0.36&lt;/td&gt;
      &lt;td&gt;0.99&lt;/td&gt;
      &lt;td&gt;0.90&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;twos&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;280&lt;/td&gt;
      &lt;td&gt;1680&lt;/td&gt;
      &lt;td&gt;89&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;0.32&lt;/td&gt;
      &lt;td&gt;1.00&lt;/td&gt;
      &lt;td&gt;0.96&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;twos&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;280&lt;/td&gt;
      &lt;td&gt;1680&lt;/td&gt;
      &lt;td&gt;101&lt;/td&gt;
      &lt;td&gt;44&lt;/td&gt;
      &lt;td&gt;0.36&lt;/td&gt;
      &lt;td&gt;0.97&lt;/td&gt;
      &lt;td&gt;0.70&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;saw-10-15&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;268&lt;/td&gt;
      &lt;td&gt;1694&lt;/td&gt;
      &lt;td&gt;157&lt;/td&gt;
      &lt;td&gt;112&lt;/td&gt;
      &lt;td&gt;0.59&lt;/td&gt;
      &lt;td&gt;0.93&lt;/td&gt;
      &lt;td&gt;0.58&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;saw-10-15&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;268&lt;/td&gt;
      &lt;td&gt;1694&lt;/td&gt;
      &lt;td&gt;148&lt;/td&gt;
      &lt;td&gt;88&lt;/td&gt;
      &lt;td&gt;0.55&lt;/td&gt;
      &lt;td&gt;0.95&lt;/td&gt;
      &lt;td&gt;0.63&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;saw-10-15&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;268&lt;/td&gt;
      &lt;td&gt;1694&lt;/td&gt;
      &lt;td&gt;138&lt;/td&gt;
      &lt;td&gt;76&lt;/td&gt;
      &lt;td&gt;0.51&lt;/td&gt;
      &lt;td&gt;0.96&lt;/td&gt;
      &lt;td&gt;0.64&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;script src=&quot;http://variancecharts.com/cdn/variance-noncommercial-standalone-6d26aa2.min.js&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt;

&lt;csv id=&quot;tp-baseline-data&quot;&gt;
pattern,candidate,in-steps,out-steps,active-in,active-out,sensitivity,specificity,precision
run-0-5,0,230,1724,112,27,0.49,0.98,0.81
run-0-5,1,230,1724,123,46,0.53,0.97,0.73
run-0-5,2,230,1724,108,21,0.47,0.99,0.84
rev-5-1,0,192,1760,109,76,0.57,0.96,0.59
rev-5-1,1,192,1760,99,50,0.52,0.97,0.66
rev-5-1,2,192,1760,91,17,0.47,0.99,0.84
run-6-10,0,204,1745,116,151,0.57,0.91,0.43
run-6-10,1,204,1745,114,115,0.56,0.93,0.5
run-6-10,2,204,1745,111,133,0.54,0.92,0.45
jump-6-12,0,204,1745,117,128,0.57,0.93,0.48
jump-6-12,1,204,1745,120,149,0.59,0.91,0.45
jump-6-12,2,204,1745,113,151,0.55,0.91,0.43
twos,0,280,1680,101,11,0.36,0.99,0.9
twos,1,280,1680,89,4,0.32,1.0,0.96
twos,2,280,1680,101,44,0.36,0.97,0.7
saw-10-15,0,268,1694,157,112,0.59,0.93,0.58
saw-10-15,1,268,1694,148,88,0.55,0.95,0.63
saw-10-15,2,268,1694,138,76,0.51,0.96,0.64
&lt;/csv&gt;
&lt;style&gt;
#stat-plot {
  width: 480px;
  height: 280px;
  padding: 80px 120px 30px 30px;
  color: #444444;
  font-family: Helvetica, Arial, sans-serif;
  font-weight: bold;
  font-size: 14px;
}
#stat-plot chart {
  width: 100%;
  height: 100%;
}
#stat-plot .legend-y {
  position: absolute;
  right: -120px;
  top: 50%;
  transform: rotate(90deg);
}
#stat-plot .legend-x {
  position: absolute;
  width: 100%;
  text-align: center;
  top: -60px;
}
#stat-plot chart annotation {
  white-space: nowrap;
  display: none;
}
#stat-plot chart datum:first-child annotation {
  display: block;
}
.run-0-5   { background-color: red; }
.rev-5-1   { background-color: orange; }
.run-6-10  { background-color: yellowgreen; }
.jump-6-12 { background-color: green; }
.twos      { background-color: blue; }
.saw-10-15 { background-color: purple; }
&lt;/style&gt;

&lt;div id=&quot;stat-plot&quot;&gt;
  &lt;chart data=&quot;#tp-baseline-data&quot; map-xy=&quot;sensitivity specificity&quot; scale-x-linear=&quot;0.30 1.00&quot; scale-y-linear=&quot;0.90 1.00&quot;&gt;
    &lt;guide-x class=&quot;top&quot;&gt;&lt;/guide-x&gt;
    &lt;guide-y class=&quot;right&quot;&gt;&lt;/guide-y&gt;
    &lt;span class=&quot;legend-y&quot;&gt;Specificity&lt;/span&gt;
    &lt;span class=&quot;legend-x&quot;&gt;Sensitivity&lt;/span&gt;
    &lt;groups by=&quot;pattern&quot;&gt;
    &lt;repeat&gt;
      &lt;point class=&quot;{{pattern}}&quot;&gt;&lt;/point&gt;
      &lt;annotation&gt;
        &lt;span class=&quot;pattern-label&quot;&gt;{{pattern}}&lt;/span&gt;
      &lt;/annotation&gt;
    &lt;/repeat&gt;
    &lt;/groups&gt;
  &lt;/chart&gt;
&lt;/div&gt;

&lt;p&gt;The results are disappointing. While the specificity is reasonably
high, sensitivity is low—under 60%—meaning that none of the
candidate cells can reliably indicate the presence of its pattern on
its own.&lt;/p&gt;

&lt;h2 id=&quot;ad-lib-hypotheses&quot;&gt;ad-lib hypotheses&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The visual display suggested that cells were indeed staying active
over any one pattern instance, but not necessarily the same cells for
different instances. So the selection of active columns in the higher
region may not be consistent across instances of the pattern.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Perhaps this is all we should expect from one region and we should
look at an even higher region for more complete temporal pooling.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Perhaps the feed-forward synapses are continuing to learn and
change and this is causing the inconsistency in column activation.
Specifically it may be the learning on temporal pooling columns that
is weakening their receptive field.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Perhaps feed-forward synapses should be reinforced more strongly
when they carry input from signal cells, to make it more likely for
those columns to become active again. (I got this idea from
&lt;a href=&quot;https://github.com/numenta/nupic.research/blob/ea7ce86805594dcaaa8a1663d5d441fac5823c40/sensorimotor/sensorimotor/temporal_pooler.py#L97&quot;&gt;nupic.research&lt;/a&gt;.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Perhaps column activation should be biased by predicted
(depolarised) cells in the column. (I got this idea from &lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-August/001165.html&quot;&gt;Fergal
Byrne&lt;/a&gt;.)
This seems to promise more consistent column activations, rather than
the current approach of randomly choosing between any columns with
equal receptive field overlaps.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;consistency-between-pattern-instances&quot;&gt;Consistency between pattern instances&lt;/h2&gt;

&lt;p&gt;Is the problem just randomness in the choice of active colums when
each pattern instance appears? If so then I would expect if we looked
over a few candidate cells then collectively they would cover all
instances of the pattern.&lt;/p&gt;

&lt;p&gt;Since I am concerned with the sensitivity measure, I filtered the time
steps down to just those where the pattern is occuring, grouped into
each instance of its occurence. Below is a plot of activations over
time of 25 candidate cells, being the top ones by overall sensitivity.
I did this for three different patterns.&lt;/p&gt;

&lt;style&gt;
#runs-plot {
  width: 800px;
  height: 900px;
  margin-left: -60px;
  padding: 40px 20px 40px 60px;
  color: #444444;
  font-family: Helvetica, Arial, sans-serif;
  font-weight: bold;
  font-size: 14px;
}
#runs-plot chart {
  width: 100%;
  height: 30%;
  margin-bottom: 40px;
  background-color: rgba(0,0,0,0.05);
}
#runs-plot .legend-y {
  position: absolute;
  left: -80px;
  top: 50%;
  transform: rotate(-90deg);
}
#runs-plot .legend-x {
  position: absolute;
  width: 100%;
  text-align: center;
  bottom: -30px;
}
#runs-plot .chart-title {
  position: absolute;
  width: 100%;
  text-align: left;
  top: -20px;
}
#runs-plot point {
  width: 6px;
  height: 6px;
  margin-left: -3px;
  margin-top: -3px;
  background-color: #888;
}
#runs-plot range {
  background-color: rgba(0,0,0,0.10);
  border: 1px solid rgba(0,0,0,0.15);
  border-width: 0px 1px;
}
&lt;/style&gt;

&lt;div id=&quot;runs-plot&quot;&gt;
&lt;link id=&quot;rev-5-1-consistency&quot; rel=&quot;variance-data&quot; href=&quot;/assets/2014-09-26/rev-5-1-consistency.csv&quot; /&gt;
  &lt;chart data=&quot;#rev-5-1-consistency&quot; map-xy=&quot;x candidate&quot; scale-x-linear=&quot;0 45&quot; scale-y-linear=&quot;24.5 -0.5&quot;&gt;
    &lt;span class=&quot;legend-y&quot;&gt;25 candidate cells&lt;/span&gt;
    &lt;span class=&quot;chart-title&quot;&gt;Pattern &quot;&lt;tt&gt;rev-5-1&lt;/tt&gt;&quot;&lt;/span&gt;
    &lt;points&gt;&lt;/points&gt;
&lt;div class=&quot;ranges&quot;&gt;
&lt;range literal-x-extent=&quot;0 1&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;2 3&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;4 5&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;6 7&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;8 9&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;10 11&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;12 13&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;14 15&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;16 17&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;18 19&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;20 21&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;22 23&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;24 25&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;26 27&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;28 29&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;30 31&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;32 33&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;34 35&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;36 37&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;38 39&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;40 41&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;42 43&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;44 45&quot;&gt;&lt;/range&gt;
&lt;/div&gt;
  &lt;/chart&gt;

&lt;link id=&quot;run-6-10-consistency&quot; rel=&quot;variance-data&quot; href=&quot;/assets/2014-09-26/run-6-10-consistency.csv&quot; /&gt;
  &lt;chart data=&quot;#run-6-10-consistency&quot; map-xy=&quot;x candidate&quot; scale-x-linear=&quot;0 49&quot; scale-y-linear=&quot;24.5 -0.5&quot;&gt;
    &lt;span class=&quot;chart-title&quot;&gt;Pattern &quot;&lt;tt&gt;run-6-10&lt;/tt&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;legend-y&quot;&gt;25 candidate cells&lt;/span&gt;
    &lt;points&gt;&lt;/points&gt;
&lt;div class=&quot;ranges&quot;&gt;
&lt;range literal-x-extent=&quot;0 1&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;2 3&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;4 5&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;6 7&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;8 9&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;10 11&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;12 13&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;14 15&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;16 17&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;18 19&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;20 21&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;22 23&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;24 25&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;26 27&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;28 29&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;30 31&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;32 33&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;34 35&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;36 37&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;38 39&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;40 41&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;42 43&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;44 45&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;46 47&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;48 49&quot;&gt;&lt;/range&gt;
&lt;/div&gt;
  &lt;/chart&gt;

&lt;link id=&quot;twos-consistency&quot; rel=&quot;variance-data&quot; href=&quot;/assets/2014-09-26/twos-consistency.csv&quot; /&gt;
  &lt;chart data=&quot;#twos-consistency&quot; map-xy=&quot;x candidate&quot; scale-x-linear=&quot;0 45&quot; scale-y-linear=&quot;24.5 -0.5&quot;&gt;
    &lt;span class=&quot;chart-title&quot;&gt;Pattern &quot;&lt;tt&gt;twos&lt;/tt&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;legend-y&quot;&gt;25 candidate cells&lt;/span&gt;
    &lt;span class=&quot;legend-x&quot;&gt;Pattern instance&lt;/span&gt;
    &lt;points&gt;&lt;/points&gt;
&lt;div class=&quot;ranges&quot;&gt;
&lt;range literal-x-extent=&quot;0 1&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;2 3&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;4 5&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;6 7&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;8 9&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;10 11&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;12 13&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;14 15&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;16 17&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;18 19&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;20 21&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;22 23&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;24 25&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;26 27&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;28 29&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;30 31&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;32 33&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;34 35&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;36 37&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;38 39&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;40 41&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;42 43&quot;&gt;&lt;/range&gt;
&lt;range literal-x-extent=&quot;44 45&quot;&gt;&lt;/range&gt;
&lt;/div&gt;
  &lt;/chart&gt;
&lt;/div&gt;

&lt;p&gt;The picture is not what I expected. Different
candidate cells do not seem to be complementary in their activations,
they seem remarkably similar. Some pattern instances see widespread
pooling while others do not see pooling at all (i.e. if you look down
one bar in the plot, there are no horizontal lines indicating
pooling). This suggests that the problem is not spatial pooling
(selection of columns) but rather sequence memory (prediction of
sequences).&lt;/p&gt;

&lt;p&gt;I’d better check this out…&lt;/p&gt;

&lt;h2 id=&quot;observing-carefully&quot;&gt;Observing carefully&lt;/h2&gt;

&lt;p&gt;Hi again. I’ve just been watching the simulation more carefully. Well,
now I feel foolish—I see what is going wrong and it is more
fundamental than any of the hypotheses I threw up above. The first
region is just not predicting the input sequences well in many
instances, so of course they are not being pooled over.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Example of interference between patterns&quot; src=&quot;/assets/2014-09-26/pattern_interference_example.png&quot; style=&quot;float:left; margin-right: 1ex;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While pattern instances that appear in isolation are generally fully
predicted, when two patterns occur together the predictions seem to
fail.&lt;/p&gt;

&lt;p&gt;Take this example, after a generous training period of 4000 time
steps. Four pattern instances are visible (&lt;code class=&quot;highlighter-rouge&quot;&gt;rev-5-1&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;run-0-5&lt;/code&gt;,
&lt;code class=&quot;highlighter-rouge&quot;&gt;jump-6-12&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;run-6-10&lt;/code&gt;), and all but the third have interference
problems.&lt;/p&gt;

&lt;p&gt;The clearest case is the last pattern: its initial time step is
predicted based on the final step of the previous pattern; but this is
a spurious prediction since its occurence is random. So, only one cell
per column is active instead of the usual full bursting, and it is
evidently not the one that usually predicts the next step of the
pattern. The next step appears unexpectedly and bursts the columns.
After that the sequence prediction recovers. &lt;strong&gt;This suggests that
failing predictions should be more harshly punished?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first pattern is missed on its final timestep, probably due to the
mixed input on the second-last time step activating different columns
from the ones which usually predict the final time step. &lt;strong&gt;This
suggests that columns should be preferentially activated if they
contain predictive cells?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A different kind of prediction failure is shown in the screenshot
below. The pattern sequence prediction breaks down after correctly
predicting the first 4 time steps. Inspecting the dendrite segments
shown we can see there is one that has fallen just below the
activation threshold (it has an activation level of 8 and the
threshold is 9). This would have been caused by prior incorrect
predictions being punished, i.e. the segment synapses being weakened.
&lt;strong&gt;This suggests that failing predictions should be less harshly
punished??&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2014-09-26/pattern_prediction_decay.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-curse-of-parametricality&quot;&gt;The curse of parametricality&lt;/h2&gt;

&lt;p&gt;I’ll need to go back to the basic algorithm and confront the many
implementation details and parameter values I have chosen. For
reference here are the parameter values I used in the simulations
described above. You can also view and modify them in the online
simulation.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:ncol&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:potential-radius-frac&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:activation-level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.02&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:global-inhibition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:stimulus-threshold&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:sp-perm-inc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:sp-perm-dec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:sp-perm-signal-inc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:sp-perm-connected&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.20&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:duty-cycle-period&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:max-boost&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; sequence memory:
&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:depth&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:max-segments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:max-synapse-count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:new-synapse-count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:activation-threshold&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:min-threshold&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:connected-perm&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.20&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:initial-perm&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.16&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:permanence-inc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:permanence-dec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;The demo here was compiled from
&lt;a href=&quot;https://github.com/floybix/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.2 with
&lt;a href=&quot;https://github.com/floybix/comportexviz/&quot;&gt;ComportexViz&lt;/a&gt; 0.0.2.&lt;/p&gt;

&lt;p&gt;The extra analysis code is here:
&lt;a href=&quot;/assets/2014-09-26/temporal_pooling_experiments.clj&quot;&gt;temporal_pooling_experiments.clj&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-data&quot;&gt;The data&lt;/h2&gt;

&lt;p&gt;The (toy) problem domain I have constructed here is an attempt to test
temporal pooling and sequence memory in a simple but meaningful way. I
would like others to try simulating the same problem domain, or to
suggest any other that can serve as a kind of benchmark or shared
example.&lt;/p&gt;

&lt;p&gt;The input is made up from 6 different fixed patterns, named as
follows:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;run-0-5&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[0 1 2 3 4 5]            &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;rev-5-1&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[5 4 3 2 1]              &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;run-6-10&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[6 7 8 9 10]             &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;jump-6-12&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[6 7 8 11 12]            &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;twos&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[0 2 4 6 8 10 12 14]     &lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;saw-10-15&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[10 12 11 13 12 14 13 15]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;These patterns are fed into the input stream, each instance separated
from its next repeat by a gap with random duration of between 1 and 75
time steps. As such, the input on each timestep is a set of (up to 6)
integers in the range [0 15]. These are encoded by simply dividing up
the input array (of 400 bits) into 16 non-overlapping blocks and
activating the block corresponding to the integer. The encoded bits
from each integer are ORed together. The code is
&lt;a href=&quot;https://github.com/floybix/comportex/blob/master/src/cljx/org/nfrac/comportex/demos/mixed_gaps_1d.cljx&quot;&gt;mixed_gaps_1d.cljx&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I have generated a CSV data file containing 10,000 time steps of the
input stream:
&lt;a href=&quot;/assets/2014-09-26/mixed_fixed_1d_10k.csv&quot;&gt;mixed_fixed_1d_10k.csv&lt;/a&gt;
(70kb).&lt;/p&gt;

  &lt;p&gt;The file has 6 columns containing either integers or blanks. The set
of integers from each row should be encoded with a scalar encoder of
range [0 15], bit width 400, and 25 active bits. The final input set
is the union of the active bits from each encoded integer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for reading this. I would appreciate your advice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. I’m loving charting with &lt;a href=&quot;http://variancecharts.com/&quot;&gt;variancecharts.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Visualization Driven Development of the Cortical Learning Algorithm</title>
   <link href="http://floybix.github.io/2014/07/11/visualization-driven-development-of-the-cortical-learning-algorithm"/>
   <updated>2014-07-11T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/07/11/visualization-driven-development-of-the-cortical-learning-algorithm</id>
   <content type="html">
&lt;p&gt;I’ve spent the last few months trying to build the Cortical Learning
Algorithm, the core of &lt;a href=&quot;https://numenta.com/technology/&quot;&gt;HTM&lt;/a&gt;, from
scratch. Partly to understand it deeply myself, and partly to help
others understand it. My building material is Clojure. I have
something that looks reasonable now, but it has certainly exposed a
lot of intricacies in the algorithm that are not clear, and some which
are probably open research questions.&lt;/p&gt;

&lt;p&gt;To understand an algorithm, one must of course grasp the idea of it,
and also follow the procedure in code. (I don’t like pseudo-code as it
often skips important details or even turns out to be incorrect.) But
that will not be enough to know what the algorithm will do when played
out over time. To get there, interactive graphic displays are your
friend. They help gain an intuitive understanding as well as answer
specific questions, and to diagnose problems quickly. This is known as
&lt;a href=&quot;https://github.com/Element84/vdd-core/wiki/What-is-Visualization-Driven-Development%3F&quot;&gt;Visualization Driven Development&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my case I was able to run the algorithm directly in a web browser
(since pure Clojure can be compiled to Javascript), which makes it
easier to build an accessible interactive visualization.&lt;/p&gt;

&lt;p&gt;I have started with a one-dimensional input array and a
one-dimensional region of mini-columns. This allows the states to be
lined up over time on the horizontal axis. Color is fundamental to the
display:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;red&lt;/strong&gt; represents active states (of input bits, columns, cells,
  segments)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;blue&lt;/strong&gt; represents predicted states (of input bits, columns, cells)&lt;/li&gt;
  &lt;li&gt;accordingly, &lt;strong&gt;purple&lt;/strong&gt; represents simultaneously active and
predicted states.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simulation can be run and paused for detailed investigation. A
typical example would be to notice some feature of the model, say a
bursting (unpredicted) column where one hoped the input had already
been learned; at this point stop the simulation and click on the
column to reveal its constituent cells and their dendrite
segments. Use the arrow keys to step forwards and backwards in time,
and check which cells, segments and synapses are involved and how they
are being modified. Full details are given in a text box.&lt;/p&gt;

&lt;p&gt;The algorithm parameters are shown and can be changed either during a
run, or after a reset. Please refer to the &lt;a href=&quot;http://floybix.github.io/comportex/&quot;&gt;annotated source
code&lt;/a&gt; of the algorithm for
descriptions of each of the parameters.&lt;/p&gt;

&lt;p&gt;Here it is with four different input streams, presented on separate
pages.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/assets/2014-07-11/simple_steps.html&quot;&gt;Simple Steps&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/assets/2014-07-11/signal_steps.html&quot;&gt;Signal Steps&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/assets/2014-07-11/mixed_fixed_1d.html&quot;&gt;Mixed Fixed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/assets/2014-07-11/block_steps.html&quot;&gt;Block Steps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: Maximise browser window before loading page. Google Chrome
browser recommended.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;The demos here are compiled from
&lt;a href=&quot;https://github.com/floybix/comportex/&quot;&gt;Comportex&lt;/a&gt; 0.0.1 with
&lt;a href=&quot;https://github.com/floybix/comportexviz/&quot;&gt;ComportexViz&lt;/a&gt; 0.0.1.&lt;/p&gt;

&lt;h2 id=&quot;unresolved-questions&quot;&gt;Unresolved questions&lt;/h2&gt;

&lt;p&gt;I should emphasise that I am not sure what I have implemented here is
true to Numenta’s algorithm. And it does not include temporal pooling
yet in any form. My reference was primarily the Numenta CLA White
Paper but ignoring the temporal pooling aspects (since theory has
moved on since it was written). But it leaves some details
unclear.&lt;a href=&quot;#note1&quot;&gt;*&lt;/a&gt;  Some specific questions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;How frequently does boosting in the spatial pooler apply? If
we apply it continuously over a rolling 1000-timestep window, the same
set of columns may be repeatedly boosted hundreds of times before the
long-term average is affected and boosting turns off. On the other
hand if we only apply boosting once every 1000 timesteps (as currently
implemented) this generates a sharp change where all active columns
switch off, and inactive columns switch on, every 1000 steps.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;How do lateral synapses (on dendrite segments) refine their
predictions? The White Paper implies – if I understand correctly – that
if a cell stops predicting, without first becoming active, then the
last active dendrite segments are punished (their active synapses have
their permanence reduced). I have tried to implement this. But I
couldn’t find code for it in NuPIC.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;How exactly is the learning cell and segment chosen from a bursting
column? And from a predicted column with multiple active segments? Do
we choose segments based on their activation level from “learning”
cells? If there are too few, do we fall back to activation from all
active cells? How should we break ties?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Can multiple cells per column be in a predictive state? If so, can
there be multiple learning cells per column? Otherwise, how are they
resolved? If one active cell is chosen to be reinforced, should other
active cells be reinforced too, or punished to differentiate them, or
ignored?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Should we reinforce active synapses only to learning cells, or to
all active cells?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Should a cell learn only when it changes state, or every time step?&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;UPDATE: Chetan very helpfully answered my questions on the mailing
list
&lt;a href=&quot;http://lists.numenta.org/pipermail/nupic-theory_lists.numenta.org/2014-July/000899.html&quot;&gt;here&lt;/a&gt;.
My implementation matches his description except for point 6 (I had
learning every time step even on continuing cells).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;pressing-ahead&quot;&gt;Pressing ahead&lt;/h2&gt;

&lt;p&gt;The most obvious major features to do next are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;add noise to the inputs, with interactive controls;&lt;/li&gt;
  &lt;li&gt;two-dimensional input fields and column arrangements;&lt;/li&gt;
  &lt;li&gt;hierarchy – regions feeding forward into other regions;&lt;/li&gt;
  &lt;li&gt;temporal pooling (the new theory).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to get some more interesting examples going to motivate further
development.&lt;/p&gt;

&lt;p&gt;Looking forward to hearing your thoughts on the &lt;a href=&quot;http://numenta.org/lists/&quot;&gt;Numenta mailing
lists&lt;/a&gt; or by direct email.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;note1&quot;&gt;*&lt;/a&gt;&lt;span style=&quot;font-size: 80%&quot;&gt; &lt;em&gt;I also looked
through the NuPIC source code but could not find answers to all my
questions. It has a mix of different methods, many targeting
classifier accuracy rather than general learning.&lt;/em&gt; &lt;/span&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The General Idea</title>
   <link href="http://floybix.github.io/2014/05/27/the-general-idea"/>
   <updated>2014-05-27T00:00:00+00:00</updated>
   <id>http://floybix.github.io/2014/05/27/the-general-idea</id>
   <content type="html">
&lt;p&gt;Greetings!&lt;/p&gt;

&lt;p&gt;Like many people, it seems, my passion for artificial intelligence has
been re-kindled recently. Douglas Hofstadter and Jeff Hawkins were the
main re-kindlers for me. Now I’ve set off exploring.&lt;/p&gt;

&lt;p&gt;I’m hoping to push the boundaries of artificial intelligence, creating
something that can learn, explore, generalise, theorise, and surprise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because it would be so cool. Also, it seems self-evident that the
tools we build should have some basic intelligence. Software and
games use tricks to appear intelligent, but they are mindless
zombies, unable to
deal with even slightly new situations, and will happily bang their
heads against a brick wall until, um, they’re taken out by a zombie
hunter, or something. Computational intelligence has the potential to
make technology do what we want, with &lt;strong&gt;robust adaptability&lt;/strong&gt;. The
cost is giving up precisely defined behaviour, as well as vastly more
computation and memory requirements. Not to
mention the difficulty of developing all this. But smart people are
working on it. And it is fun.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’m convinced that Jeff Hawkins’ &lt;a href=&quot;https://numenta.com/technology/&quot;&gt;Hierarchical Temporal
Memory&lt;/a&gt; (HTM) is the proper basis for
such computational intelligence. Of course, HTM is a general theory
and has not yet been worked out at a level of detail applicable to
most interesting problems. My strategy will be to focus on examples.
To attack specific problems as a way to inspire development of the
theory. I’ll design simulations with opportunities for learning and
watch what goes wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTM is based on a memory system, arranged in a hierarchy of increasing
abstraction, where the memory is simultaneously a predictive function.
So it can recognise things, or situations or whatever, and infer what
is happening and what may happen next. There is no emotion, no desire,
no fear. Just recognition, generalisation, analogy. Is that scary? Of
course every technology will be put to nasty uses, but I think it’s
hard to argue that more intelligence is a bad thing.&lt;/p&gt;

&lt;p&gt;Anyway, looks like we’ve got a lot of work to do. Better get on with
it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;–Felix&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 
</feed>