Add Thousand Brains Theory and predictive coding components - #69
Add Thousand Brains Theory and predictive coding components#69soroushdeimi wants to merge 14 commits into
Conversation
New modules: - Grid cells and displacement cells for reference frames - Active dendrites with NMDA nonlinearity - Temporal Memory (HTM sequence learning) - Spatial Pooler (SDR encoding) - SDR operations (overlap, union, encoding) - Column voting for inter-column consensus Bug fixes: - Fix connect_dst condition in CorticalLayerConnection - Fix build_helper key reconstruction in CorticalColumn - Fix Local2dSTDP using wrong spike variable Improvements: - Improved __repr__ methods across structure classes - Updated README with Thousand Brains documentation
- Add __all__ to all 10 __init__.py modules for explicit exports - Add docstrings to all module init files - Create conex/nn/utils/precision.py with: - PrecisionMode enum (FULL, HALF, BFLOAT16, MIXED) - PrecisionConfig dataclass for configuration - MixedPrecisionManager for autocast and gradient scaling - Hardware support detection utilities - Optimal precision auto-configuration - Fix incorrect __all__ entries to match actual class names
Implements predictive processing based on Free Energy Principle: Core Behaviors (conex/behaviors/neurons/predictive_coding.py): - PredictionUnit: Generates predictions about expected input - ErrorUnit: Computes prediction errors (surprise) - PrecisionWeighting: Adaptive uncertainty estimation - TopDownPrediction: Higher-to-lower layer predictions - PredictiveCodingLearning: Weight updates via error minimization - FreeEnergyMinimization: Tracks variational free energy - HierarchicalPredictiveCoding: Multi-level processing Predictive Synapses (conex/behaviors/synapses/predictive.py): - FeedbackPredictionSynapse: Top-down predictions - FeedforwardErrorSynapse: Bottom-up errors - LateralPredictionSynapse: Same-level context - PredictiveConnection: Factory for connections High-Level Structures (conex/nn/structure/predictive_hierarchy.py): - PredictiveHierarchy: Multi-level hierarchy builder - PredictiveCorticalColumn: Canonical microcircuit (L4/L2-3/L5/L6) References: - Rao & Ballard (1999): Predictive coding in visual cortex - Friston (2005): Free Energy Principle - Bastos et al. (2012): Canonical microcircuits
The 25 behaviors added for Thousand Brains Theory and predictive coding had no entry in priority.py, so prioritize_behaviors() raised a bare KeyError for every one of them. Placement follows the data flow of each group: - encoding ahead of the dendrites (SDREncoder, SpatialPooler, TemporalMemory, grid and location modules) - predictive coding between dendrite structure and computation, ordered prediction -> error -> precision -> free energy - learning and readout after Fire (PredictiveCodingLearning, SDRClassifier) - predictive synapses alongside their dendritic-input and learning peers Existing priority values are unchanged. prioritize_behaviors() now names the offending class instead of raising a bare KeyError.
The __all__ lists added to the package __init__ files were missing most of the existing API. Because conex/__init__.py re-exports through star imports, a short __all__ in an intermediate package stops those names from binding on conex at all, which breaks explicit imports too. `from conex import *` had dropped to 11 names. LIF, Fire, KWTA, SimpleSTDP, WeightInitializer and 11 others were no longer reachable as conex.<name>, Example/test/mnist.py could not import replicate or save_structure, and the newly added SDR, GridCellModule, TemporalMemory and SpatialPooler were unreachable as well. Leaf packages now list everything their modules define; behaviors, nn and the top-level package build __all__ from their children so the two cannot drift apart again. Internal imports (Behavior, torch, typing names) stay unexported. `from conex import *` now yields 142 names.
The Thousand Brains and predictive coding work landed without tests. This adds 114, all runnable on CPU in about a second. - test_exports.py: every legacy and new name resolves from conex, __all__ has no duplicates and matches `import *`, and every Behavior in the package has a priority entry. These pin the two regressions above. - test_sdr.py: overlap, union, intersection, difference, subsample and the Jaccard and threshold measures, plus UnionSDR membership. - test_htm.py: spatial pooler sparsity, stability and permanence bounds; temporal memory bursting, winner selection, anomaly score and the drop in anomaly once a sequence repeats. - test_grid_cells.py: activation bounds and determinism, module scales, path integration, and periodicity on the hexagonal lattice, where the shortest translation is 2*lambda/sqrt(3) at theta+30 degrees. - test_predictive_coding.py: error, precision weighting, prediction smoothing and the free energy terms. - test_learning.py: regression tests for the Local2dSTDP fix. All six fail if the update reads pre_spike again. - conftest.py: shared network builder. Behaviors read network.dt, so test networks need TimeResolution.
|
Thank you for This PR. As it's quite lengthy and covers multiple avenues, its review takes some time. On the positive note, CoNeX should finally enjoy from wildcard imports :) Was any Agent/LLM involved in this PR? |
|
Thanks for taking a look no rush, I know it's a big diff. The Thousand Brains and predictive coding work is mine, from December last year. I had actually discussed these changes with Dr. Tabesh back then, but I got the impression he wasn't very enthusiastic about my contribution, so I ended up shelving the idea. Today, while organizing my files, I came across the code again. I thought it held up well and decided it was worth opening a PR in case it could be of some help. The three commits at the top of the branch are more recent. I had been using the library myself and kept hitting the export and priority problems. It seemed a shame to leave them as is, so I sat down this week to fix them properly, which included the I was also planning to add a CI workflow nothing currently runs the tests on a PR, which seemed worth fixing if the project is going to grow. Happy to walk through any part of it. If it'd be easier to review. |
|
I really don't like to change minimum version of python. As far as I can tell, you only used (note: in case of DendriteSegment behavior you also need to change |
|
Please add your name and email address as author on top of following files:
(basically all the new behavior files + precision + structure) |
Adds an Author line to the module docstring of each new file, as requested in review. Docstring-only change, no behavior touched.
@DataClass(slots=True) requires Python 3.10, while setup.py declares python_requires=">=3.8". It was used on two config classes, DendriticSegmentConfig and SDRConfig, where it bought nothing: both are short-lived parameter bundles built once when a behavior is constructed, never in the simulation loop. vermin puts the package minimum back at 3.8, down from 3.10, and these two decorators were its only violations. The config classes themselves stay — plain dataclasses are 3.7+, and NamedTuple configs were never affected.
|
Done dropped slots=True from DendriticSegmentConfig and SDRConfig I kept the config classes themselves for now, since they turned out not to if you'd still rather see them go on design grounds, I'm happy to Same for SpatialPooler and DendriticSegment. Right now they can only be |
Yes, please remove All the data classes. should be the list below?
and corresponding test? |
|
Before I start the previous commit already fixed the version issue, so I want to check that removing the classes is still what you want. vermin on the package, before and after dropping slots=True: So 3.8 works today with the config classes still in place. slots was the only That makes removing them a design decision rather than a compatibility one. If you do want it there is five dataclasses total: PredictiveCodingConfig is the bulk of the work: 60 references across the And two questions:
|
|
|
Okay. two more things, and I should be done.
|
What this adds
Two related groups of behaviors, plus tests and some fixes to existing code
that turned up along the way.
Thousand Brains / HTM
Predictive coding
L4 / L2-3 / L5 / L6 microcircuit
All new behaviors are registered in
conex/nn/priority.py, so they composewith
prioritize_behaviors()like the existing ones. Priorities follow eachgroup's data flow: encoding runs ahead of the dendrites, predictive coding
sits between dendrite structure and computation in the order
prediction -> error -> precision -> free energy, and learning and readout
run after
Fire.Fixes to existing code
Local2dSTDP.compute_dwbuilt its post-synaptic spike term frompre_spike.Conv2dSTDPalready usedpost_spike— this was acopy-paste slip that made the LTP term wrong, and raised a shape error
whenever source and destination sizes differed.
CorticalLayerConnection.connect_dsttestedself.dsttwice instead ofself.srcandself.dst, so it could try to build synapses with no source.CorticalColumn.save_helperand its loader indexedsub_structuresforboth layers and layer connections, which mixed the two up on reload.
Layers are now keyed by tag.
InputLayer.__repr__andOutputLayer.__repr__chained conditionalexpressions whose precedence made them return the wrong string.
Public API
Package
__init__files now declare__all__. The leaf packages list whattheir modules define;
behaviors,nnand the top-level package buildtheirs by aggregating from their children, so the lists cannot drift out of
sync with the code. Internal imports (
Behavior,torch, typing names) areno longer re-exported.
from conex import *gives 142 names.Tests
114 new tests, CPU only, about a second to run:
test_sdr.py— overlap, union, intersection, difference, subsample,Jaccard and threshold matching, UnionSDR membership
test_htm.py— spatial pooler sparsity, stability and permanence bounds;temporal memory bursting, winner selection, anomaly score, and the drop in
anomaly once a sequence repeats
test_grid_cells.py— activation bounds, determinism, module scales, pathintegration, and periodicity on the hexagonal lattice (the shortest
translation that returns all three wave vectors is 2*lambda/sqrt(3) at
theta+30 degrees)
test_predictive_coding.py— error computation, precision weighting,prediction smoothing, free energy terms
test_learning.py— regression tests for theLocal2dSTDPfix; all sixfail if the update reads
pre_spikeagaintest_exports.py— every public name resolves fromconex, and everyBehaviorin the package has a priority entrytests/conftest.pyhas a shared network builder. Behaviors across CoNeX readnetwork.dt, so test networks needTimeResolutionattached.Known gaps
Worth flagging before review:
ActiveDendriteComputation, the new behaviors do not read orwrite
neurons.spikes/neurons.I. They are driven by explicit methodcalls and by attributes the caller sets (
sp_input,tm_input_columns),so for now they sit alongside the spiking pipeline rather than inside it.
Wiring them in is the obvious follow-up.
@dataclass(slots=True)insdr.pyandactive_dendrites.pyneedsPython 3.10, but
setup.pystill declarespython_requires=">=3.8".nn/utils/precision.pycallstorch.amp.GradScaler, which is torch 2.3+,while
requirements.txtpinstorch==1.13.1. It also targetstorch.nn.Module, so it does not apply to CoNeX behaviors yet.SDR.overlapassumes the index tensor holds no duplicates; theconstructor does not deduplicate.
conex.helpers.transforms.masksimportstorchvisionand it is not ininstall_requires, soimport conexfailson a clean install. Happy to fix that here or separately.