Yet another "Yet Another HTM Implementation"



Hey folks!

Jeff’s talk at the APL last month reinvigorated my interest in HTM, so I’ve spent the last month or so catching up on the current state of things. To help me with that goal, I ended up tinkering on ZHTM after work.

ZHTM is a Python 3 implementation of both a Spatial Pooler and the Temporal Memory algorithm (as defined largely by BAMI). The current implementation uses just base Python; the only dependencies (thus far) are pytest and pytest-mock for testing purposes.

As of earlier today, it is at least possible to feed inputs into the Temporal Memory algorithm repeatedly without obvious errors, so I’m celebrating that milestone by posting here.

I’ve also got some super-hacky Vue.js visualizations in progress, but they are a significantly less demo-worthy at the moment:


Over the next month, I am hoping to move the system from “doesn’t throw exceptions” into “might be useful” territory:

  • Add integration tests to assert that Spatial Pooler and Temporal Memory operate as expected at a higher level than the unit tests currently provide
  • Create example systems with known data sets (e.g. the gym or traffic data sets)
  • Add 5+ of the basic encoders
  • Create demos of at least 3 major components of the system via the web viewer (unpublished)

Anyway, thanks to everyone for your helpful posts and articles. I haven’t said much in the last month, but I appreciate all the knowledge you’ve been sharing.

P.S. Here’s part of the call graph from calling the Temporal Memory algorithm 20 times. I just thought it looked neat.


Thanks for sharing - yet another concrete interpretation of BAMI. Although I try to avoid repeating myself, I’m also slowly writing an HTM framework primarily for learning HTM theory. I tend to learn algorithms better by reading/writing code than text docs or videos.

I thought of using plain objects as well as it would ease the learning process, but I think I will be using a different approach to future proof it. Just to inform you, I have also loosely asked around about how much matrix/linear algebra is used in nupic py and c++. I didnt get much responses, however at this stage, I think that HTM algorithms doesn’t have to use linear algebra libs as much as those existing ML fwks today.


I hear you there! It’s really easy to just skim some code and think that you understand something. Nothing forces you to prove it like making working code.


Quick status update!

I’ve been plugging away at this implementation. Yesterday I managed to run a zhtm system through the anomaly benchmark. This is using raw prediction-error scoring, as I haven’t implemented the ‘anomaly likelihood’ stuff quite yet.

I did discover a pretty big conceptual misunderstanding to work through: I totally misinterpreted how data was passed from the spatial pooler into the temporal memory. Rather than send the spatial pooler’s active columns directly into the temporal memory system, I was re-sampling the spatial pooler’s output, in the same way that the spatial pooler samples the input space. Once I fixed that mistake, the system started behaving itself more like I expected.

Anomaly benchmark

Here are some super preliminary results from the final_results.json file that NAB generates:

    "null": {
        "reward_low_FN_rate": 0.0,
        "reward_low_FP_rate": 0.0,
        "standard": 0.0
    "numenta": {
        "reward_low_FN_rate": 74.32064726862069,
        "reward_low_FP_rate": 61.70812096732759,
        "standard": 69.67062607534481
    "zhtm": {
        "reward_low_FN_rate": 73.01327530933908,
        "reward_low_FP_rate": 56.10583427353449,
        "standard": 66.84749917090518

Despite not having the likelihood stuff implemented, my system appears to be within the same ballpark as the Numenta detector, which is exciting for me! (You can see the ‘official’ scores for other detectors here, in the section labeled ‘Scoreboard’).

Part of me is worried I’ve done something wrong that is artificially inflating the score, so I’ll be on the lookout for that as I improve and refine the code base.

Brief system config I used:

input SDR
* basic ScalarEncoder
* num_buckets clamped to [150, 1000]
* num_active_bits: 41

spatial pooler
* num_columns: 2048
* stimulus_threshold: 0
* winning_column_count: 41
* min_overlap_duty_cycle_percent = 0.001
* boost_strength = 0.01
* percent_potential = 0.8

temporal memory
* num_columns = 2048
* TMColumn.cell_count = 32

* Cell.new_synapse_count = 15
* Cell.desired_synapses_per_segment = 32
* Cell.distal_segment_activation_threshold = 0
* Cell.distal_segment_matching_threshold = 0

* DendriteSegment.permanence_increment = 0.1
* DendriteSegment.permanence_decrement = 0.05