Skip to content

Commit

Permalink
update axon readme
Browse files Browse the repository at this point in the history
  • Loading branch information
rcoreilly committed Aug 16, 2024
1 parent d2300a4 commit e102f05
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 52 deletions.
56 changes: 11 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
[![codecov](https://codecov.io/gh/emer/axon/branch/master/graph/badge.svg)](https://codecov.io/gh/emer/axon)
![CI](https://github.com/emer/axon/actions/workflows/build.yml/badge.svg?branch=master)

This is the Go implementation of the Axon algorithm for spiking, biologically based models of cognition, based on the [Go emergent](https://github.com/emer/emergent) framework (with optional Python interface), and the [Leabra](https://github.com/emer/leabra) framework for rate-code models.
This is the Go implementation of the Axon algorithm for spiking, biologically based models of cognition, based on the [emergent](https://github.com/emer/emergent) framework (with optional Python interface), and the [Leabra](https://github.com/emer/leabra) framework for rate-code models.

Axon is the spiking version of [Leabra](https://github.com/emer/leabra), with several advances. As an acronym, *axon* could stand for *Adaptive eXcitation Of Noise*, reflecting the ability to learn using the power of error-backpropagation in the context of noisy spiking activation. The spiking function of the axon is what was previously missing from Leabra.

See [Wiki Install](https://github.com/emer/axon/wiki/Install) for installation instructions.
Axon and emergent use the [Cogent Core](https://cogentcore.org/) GUI framework. See [install](https://www.cogentcore.org/core/setup/install) instructions there. Once those prerequisites are in place, then the simplest way to run a simulation is:

See the [ra25 example](examples/ra25/README.md) for a complete working example (intended to be a good starting point for creating your own models), and any of the 26 models in the [Comp Cog Neuro sims](https://github.com/CompCogNeuro/axon) repository which also provide good starting points. See the [etable wiki](https://github.com/emer/etable/wiki) for docs and example code for the widely used etable data table structure, and the `family_trees` example in the CCN textbook sims which has good examples of many standard network representation analysis techniques (PCA, cluster plots, RSA).
```sh
$ core run <platform>
```

The [Wiki Convert From Leabra](https://github.com/emer/axon/wiki/Convert-From-Leabra) page has information for converting existing Go leabra models.
where `<platform>` is optional (defaults to your local system), and can include `android`, `ios` and `web`!

See [python README](python/README.md) and [Python Wiki](https://github.com/emer/emergent/wiki/Python) for info on using Python to run models. NOTE: not yet updated.
See the [ra25 example](examples/ra25/README.md) for a complete working example, which is intended to be a good starting point for creating your own models.

# Current Status / News

* August 2024: **v2.0.0-dev-x.x.x**: in process transition to Cogent Core infrastructure, and major improvements in the [Rubicon](Rubicon.md) framework. Also finally figured out how to avoid the computationally expensive integration of calcium at each individual synapse at a cycle-by-cycle level, using a reasonable linear model based on activity windows on the sending and receiving neuron, with multiplicative factors (r^2 is .96 at capturing the cycle-by-cycle values). A full "2.0" release will be made once Cogent Core gets to a 1.0 stable release, and all the tests etc are updated.

* June 2023: **v1.8.0** Neuron and Synapse memory now accessed via methods with arbitrary strides so GPU and CPU can each have optimal memory ordering -- NVIDIA A100 performance now comparable to Mac M1, which also improved by 25%. Includes data parallel processing (multiple input patterns processed in parallel using shared weights) which makes GPU faster than CPU even with small networks (e.g., ra25). See [GPU](GPU.md) and [data parallel](#data_parallel) section.

* Feb 2023: **v1.7.9** completed first pass on [GPU](GPU.md) implementation based on [gosl](https://github.com/goki/gosl) conversion from the Go source to Vulkan HLSL shaders running under the [vgpu](https://github.com/goki/vgpu) framework.
Expand All @@ -31,64 +35,26 @@ See [python README](python/README.md) and [Python Wiki](https://github.com/emer/

## Building

If you get build failures having to do with the `_string.go` files, you likely need
to regenerate them. They are generated by `go generate` and a fork of the stringer tool.

```sh
go install github.com/goki/stringer@latest
go generate ./...
```

There is a `-tags multinet` build tag needed to enable there to be multiple Network objects in use at one time in a given simulation. Typically there is just one, and with the GPU-compatible global access methods for accessing network variables, it is faster to directly use a single `*Network` pointer instead of indexing into a slice of multiple networks.

The tests are one one place where `-tags multinet` must be passed, as multiple different networks are built there.

## Release

There are a few main parts to releasing a new version.

### Update version.go

1. Increment the `VERS` string in [axon/Makefile](axon/Makefile).
1. Make sure `goimports` is on your `$PATH`. If you don't have it, you can run: `go install golang.org/x/tools/cmd/goimports@latest`
1. Run `make -C axon version`. This will modify [axon/version.go](axon/version.go) and commit it.
1. Open a pull request with this change and get it merged into master.

### Tag the commit

```sh
git switch master
git fetch origin master && git reset --hard FETCH_HEAD
make -C axon release
```
Use `core next-release` to push a tag at the next patch increment, or `core release v*` for a specific version tag.

# Design and Organization

* `ActParams` (in [act.go](axon/act.go)), `InhibParams` (in [inhib.go](axon/inhib.go)), and `LearnNeurParams` / `LearnSynParams` (in [learn.go](axon/learn.go)) provide the core parameters and functions used.

* There are 3 main levels of structure: `Network`, `Layer` and `Path` (pathway). The network calls methods on its Layers, and Layers iterate over both `Neuron` data structures (which have only a minimal set of methods) and the `Path`s, to implement the relevant computations. The `Path` fully manages everything about a pathway of connectivity between two layers, including the full list of `Synapse` elements in the connection. The Layer also has a set of `Pool` elements, one for each level at which inhibition is computed (there is always one for the Layer, and then optionally one for each Sub-Pool of units).

* The `NetworkBase`, `LayerBase`, and `PathBase` structs manage all the core structural aspects (data structures etc), and then the algorithm-specific versions (e.g., `axon.Network`) use Go's anonymous embedding (akin to inheritance in C++) to transparently get all that functionality, while directly implementing the algorithm code. The [layer_compute.go](axon/layer_compute.go) file has the core algorithm specific code, while [layer.go](axon/layer.go) has other algorithm specific maintenance code.
* The `networkbase.go`, `layerbase.go`, and `pathbase.go` code builds on the [emergent](https://github.com/emer/emergent) infrastructure to manage all the core structural aspects (data structures etc), while the non-base code implements algorithm-specific functions. Everything is defined on the same core types (e.g., `axon.Network`). The [layer_compute.go](axon/layer_compute.go) file breaks out has the core algorithm specific code, while [layer.go](axon/layer.go) has other algorithm specific code.

* To enable the [GPU](GPU.md) implementation, all of the layer parameters are in `LayerParams` (accessed via `Layer.Params`) and path params in `PathParams` (accessed via `Path.Params`), in [layerparams.go](layerparams.go) and [pathparams.go](pathparams.go) respectively. `LayerParams` contains `ActParams` field (named `Act`), etc.

* The ability to share parameter settings across multiple layers etc is achieved through a **styling**-based paradigm -- you apply parameter "styles" to relevant layers -- see [Params](https://github.com/emer/emergent/wiki/Params) for more info. We adopt the CSS (cascading-style-sheets) standard where parameters can be specifed in terms of the Name of an object (e.g., `#Hidden`), the *Class* of an object (e.g., `.TopDown` -- where the class name TopDown is manually assigned to relevant elements), and the *Type* of an object (e.g., `Layer` applies to all layers). Multiple space-separated classes can be assigned to any given element, enabling a powerful combinatorial styling strategy to be used.

* Go uses `interface`s to represent abstract collections of functionality (i.e., sets of methods). The `emer` package provides a set of interfaces for each structural level (e.g., `emer.Layer` etc) -- any given specific layer must implement all of these methods, and the structural containers (e.g., the list of layers in a network) are lists of these interfaces. An interface is implicitly a *pointer* to an actual concrete object that implements the interface. Thus, we typically need to convert this interface into the pointer to the actual concrete type, as in:

```Go
func (nt *Network) InitActs() {
for _, ly := range nt.Layers {
if ly.IsOff() {
continue
}
ly.(AxonLayer).InitActs()
}
}
```

* The `emer` interfaces are designed to support generic access to network state, e.g., for the 3D network viewer, but specifically avoid anything algorithmic. Thus, they allow viewing of any kind of network, including PyTorch backprop nets.

* Layers have a `Shape` property, using the `tensor.Shape` type, which specifies their n-dimensional (tensor) shape. Standard layers are expected to use a 2D Y*X shape (note: dimension order is now outer-to-inner or *row-major* now), and a 4D shape then enables `Pools` as hypercolumn-like structures within a layer that can have their own local level of inihbition, and are also used extensively for organizing patterns of connectivity.

# Data Parallel
Expand Down
14 changes: 7 additions & 7 deletions kinasex/contprjn.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ func (pj *MatrixPath) InitWeights() {
// at the NMDA N2B site. When the synaptic activity has fallen from a
// local peak (CaDMax) by a threshold amount (CaDMaxPct) then the
// last TDWt value converts to an actual synaptic change: DWt
func (pj *ContPath) SendSynCa(ltime *Time) {
func (pj *ContPath) SendSynCa(ctx *Time) {
kp := &pj.Learn.KinaseCa
if !pj.Learn.Learn {
return
}
switch pj.Rule {
case kinase.SynSpkTheta:
pj.Path.SendSynCa(ltime)
pj.Path.SendSynCa(ctx)
return
case kinase.NeurSpkTheta:
return
Expand Down Expand Up @@ -209,17 +209,17 @@ func (pj *ContPath) SendSynCa(ltime *Time) {
}

// DWt computes the weight change (learning) -- on sending pathways
func (pj *ContPath) DWt(ltime *Time) {
func (pj *ContPath) DWt(ctx *Time) {
if !pj.Learn.Learn {
return
}
switch pj.Rule {
case kinase.SynSpkTheta:
pj.Path.DWTSynSpkTheta(ltime)
pj.Path.DWTSynSpkTheta(ctx)
case kinase.NeurSpkTheta:
pj.Path.DWTNeurSpkTheta(ltime)
pj.Path.DWTNeurSpkTheta(ctx)
default:
pj.DWtCont(ltime)
pj.DWtCont(ctx)
}
}

Expand All @@ -228,7 +228,7 @@ func (pj *ContPath) DWt(ltime *Time) {
// computed DWt from TDWt.
// Applies post-trial decay to simulate time passage, and checks
// for whether learning should occur.
func (pj *ContPath) DWtCont(ltime *axon.Time) {
func (pj *ContPath) DWtCont(ctx *axon.Time) {
kp := &pj.Learn.KinaseCa
slay := pj.Send.(AxonLayer).AsAxon()
rlay := pj.Recv.(AxonLayer).AsAxon()
Expand Down

0 comments on commit e102f05

Please sign in to comment.