numenta / nupic-legacy

Numenta Platform for Intelligent Computing is an implementation of Hierarchical Temporal Memory (HTM), a theory of intelligence based strictly on the neuroscience of the neocortex.
http://numenta.org/
GNU Affero General Public License v3.0
6.34k stars 1.55k forks source link

Speed up CoordinateEncoder for streaming data #2150

Open breznak opened 9 years ago

breznak commented 9 years ago

hey all, it would be awesome if we could speed up coordinate encoder something like 60x+ :man_with_turban:

Use case: I have real world date where 3+s ~ 600k+ data points, but just processing with coordinate encoder takes 180+s.

Here's the profile:

        128703788 function calls (128701858 primitive calls) in 189.398 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.497    0.497  189.399  189.399 retina.py:1(<module>)
   663257    0.393    0.000  182.238    0.000 retina.py:170(run)
   389924    2.433    0.000  181.845    0.000 retina.py:47(encode)
   389924    1.597    0.000  178.010    0.000 retina.py:25(encodeIntoArray)
   389924    7.379    0.000  175.725    0.000 coordinate.py:100(encodeIntoArray)
  3509316    4.033    0.000  106.439    0.000 coordinate.py:112(<lambda>)
  3509316    9.117    0.000  102.406    0.000 coordinate.py:174(_bitForCoordinate)
  7018632   21.687    0.000   98.697    0.000 coordinate.py:151(_hashCoordinate)
  7019198   13.218    0.000   66.038    0.000 {method 'join' of 'str' objects}
   389924    6.516    0.000   56.352    0.000 coordinate.py:134(_topWCoordinates)
 21055896   22.783    0.000   52.819    0.000 coordinate.py:154(<genexpr>)
  3509316    7.557    0.000   46.932    0.000 coordinate.py:160(_orderForCoordinate)
  7018632    7.489    0.000   30.036    0.000 numeric.py:1681(array_str)
  7018635   14.164    0.000   27.245    0.000 math.py:5978(__init__)
  7018632   18.718    0.000   22.547    0.000 arrayprint.py:343(array2string)
  7018635   13.082    0.000   13.082    0.000 {_math.new_Random}
  7018633    6.228    0.000    6.228    0.000 {_hashlib.openssl_md5}
        1    0.012    0.012    5.005    5.005 spatial_pooler.py:52(__init__)

Limitations: The task has some preconditions, which hopefully could be exploited!

What do you think, should I try, or start from somewhere else completely?

breznak commented 9 years ago

@chetan51 @oxtopus guys, do you have some tricks in your sleeves? :wink:

cogmission commented 9 years ago

Do all these methods reflect a single call stack? Or are they separate branches resulting from a single call to compute?

chetan51 commented 9 years ago

@breznak What radius are you using? The larger the radius, the longer the encoder takes. Try to keep the radius small by reducing the minimum resolution of your data.

breznak commented 9 years ago

Do all these methods reflect a single call stack? Or are they separate branches resulting from a single call to compute?

@cogmission from a single "task", that is, encode() gets called ~390.000x

What radius are you using? The larger the radius, the longer the encoder takes. Try to keep the radius small by reducing the minimum resolution of your data.

@chetan51 the data is 2 natural numbers from 1..128 interval, I want to distinguish each 2 numbers. Setting range=0(does the value make sense?) reduces the time already to 54s!

Thank you both for help!

chetan51 commented 9 years ago

@breznak When you say range, do you mean radius?

breznak commented 9 years ago

@chetan51 sorry for thread-zombie, I've missed that reply.

When you say range, do you mean radius?

yes.

Still, I can squeeze about 50% time when I prehash the values, instead of computing them interactively. Do you think we should speed up _hashCoordinate() by using internal array _hash[x][y] that is random initialized during init? It makes initialization last a while for longer arrays, but then _hashCoordinate is constant time.

chetan51 commented 9 years ago

Do you think we should speed up _hashCoordinate() by using internal array _hash[x][y] that is random initialized during init?

But how many values would you initialize? The Coordinate Encoder currently works for infinite space.

breznak commented 9 years ago

But how many values would you initialize? The Coordinate Encoder currently works for infinite space.

Ouch, my mistake, in my scenario I use fixed-sized coordinate dimensions. Maybe worth adding optional param dimensionsSizes[]? Then the speedup could be applied.

chetan51 commented 9 years ago

A cleaner optimization might be to just cache computed coordinates, so we would still get speedups for repeating sequences.

breznak commented 9 years ago

A cleaner optimization might be to just cache computed coordinates, so we would still get speedups for repeating sequences.

Great idea! So even infinite-space coords would benefit, also we'd expect some repetitive patterns in sequences, so this cache should hit more likely. And for fixed sized we'd set cacheSize=dim(x)*dim(y)

breznak commented 9 years ago

@chetan51 I've implemented the caching (cache (input,bitvector output) pairs) with very good results! I'm wondering if this could be generalized and moved all this logic to base encoder, so we could get the gains through all encoders? Anyway, this issue is addressed by the PR above already.

chetan51 commented 9 years ago

@breznak Great! If you can make it a generalized decorator, then we can reuse it across encoders.