Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cerebral: mvp python extension #11

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
3 changes: 1 addition & 2 deletions .github/workflows/docs_pages.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
name: Build python packages
name: Build Documentation

on: [push, pull_request]
on:
workflow_dispatch:
branches:
Expand Down
19 changes: 6 additions & 13 deletions .github/workflows/python_packages.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
# Found here: https://tomasfarias.dev/posts/sphinx-docs-with-poetry-and-github-pages/
name: Build Python packages

name: Docs2Pages
on:
workflow_dispatch:
branches:
- main
push:
# tags: '*'
branches:
- main
pull_request:
branches:
- main
on: [push, pull_request]

jobs:
build-wheels:
Expand All @@ -23,6 +12,10 @@ jobs:
uses: actions/checkout@master
with:
fetch-depth: 0
- name: 🐍 Install Python
uses: actions/setup-python@v4
with:
python-version: 3.10.2
- name: 🦀 Install Rust
uses: actions-rs/toolchain@v1
with:
Expand Down
87 changes: 54 additions & 33 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,50 +46,71 @@ efficiency and simplicity (both in terms of implementation and
comprehensibility). Plus, it's my favorite and I'm doing active research with
it.

* Numerical python extensions written in Rust
* Seamless integration via [PyO3](https://pyo3.rs/v0.16.1/) and [rust-numpy](https://docs.rs/numpy/0.7.0/numpy/)
* High-performance via [ndarray](https://github.com/rust-ndarray/ndarray)/[rayon](https://docs.rs/ndarray/0.13.1/ndarray/parallel/index.html), [tch-rs](https://github.com/LaurentMazare/tch-rs) ([PyTorch](https://pytorch.org/) bindings)
* Dependency management / publishing with [Poetry](https://python-poetry.org/docs/) and [Maturin](https://github.com/PyO3/maturin)
* [Monorepo](https://en.wikipedia.org/wiki/Monorepo) with [Cargo workspaces][(](<https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html>))
* Technical documentation / GitHub page with [Sphinx](https://www.sphinx-doc.org/en/master/) and [MyST](https://myst-parser.readthedocs.io/en/latest/sphinx/intro.html)
* Eventually, distributed computation (e.g., [actor model](https://en.wikipedia.org/wiki/Actor_model) or [timely
dataflow](https://timelydataflow.github.io/timely-dataflow/))
* Hopefully, GUI application using [Tauri](https://tauri.studio/), [Angular](https://angular.io/) and [ThreeJS](https://threejs.org/)

Feel free use as a basis for your own projects (MIT licensed).
The development explores:

## Development

For the monorepo, there is a top-level python project defined using poetry. This project is
mainly for dependency locking, integration testing and the overall project's documentation.
The python module
build with Maturin is in a nested folder and it's project file is also created with poetry.
This is necessary as the top-level project can only add local packages that are either
created with Poetry or contain a `setup.py` file.
* Numerical python extensions written in Rust: Seamless integration via [PyO3](https://pyo3.rs/v0.16.1/) and [rust-numpy](https://docs.rs/numpy/0.7.0/numpy/). Dependency management / publishing with [Poetry](https://python-poetry.org/docs/) and [Maturin](https://github.com/PyO3/maturin)
* High-performance via [ndarray](https://github.com/rust-ndarray/ndarray)/[rayon](https://docs.rs/ndarray/0.13.1/ndarray/parallel/index.html).

While this setup supports a monorepo setup (and should support integration
testing on the imported local packages), there is another caveat. Building the python extension with
`pip` creates a temp directory which does not copy the local rust dependencies. Newer versions of `pip`
build within the tree, so this limitation can be avoided easily. Use the following commands to
setup the environment.
## The cerebral and potpourri Python packages

> :warning: We want to avoid creating a virtual environment for the nested packages. Work in
> a top-level shell instead.
The`potpourri` and `citrate` sub folders contain the Python bindings for
the two crates in `potpourri-rs` and `citrate-rs`. You can build them in a
similar fashion.

```sh
cd self-organization
pyenv shell 3.10.2
poetry env use 3.10.2
poetry run pip install -U pip # only required until pip>=22.0 becomes the default
cd citrate
# skip the next line if you are not using pyenv
pyenv shell 3.10.2 # replace with desired/installed version
# skip if you only have one version of python installed
poetry env use 3.10.2 # replace with desired/installed version
# Install dependencies
poetry install
# to debug / develop the extension
# Or optionally, with jupyter
poetry install --with jupyter
# activate the virtual environment
poetry shell
cd pysom
# install into the current environment
maturin develop
# with optimizations (recommended)
maturin develop --release
# build an installable package
maturin build --release
```

To install the virtual environment as a kernel for jupyter:

```sh
python -m ipykernel install --user --name py310_selforganization --display-name "Python3.10 (self-organization)"
poetry add ipykernel
# Adjust names as suitable
python -m ipykernel install --user --name py320_citrate --display-name "Python3.10 (Citrate)"
```

## Development

* Bulding documentation. We need extra headers to have formulas in the rustdoc

```sh
RUSTDOCFLAGS="--html-in-header ./static/header.html" cargo doc -p cerebral --no-deps
RUSTDOCFLAGS="--html-in-header ./static/header.html" cargo doc -F ndarray -p potpourri --no-deps
# Open (e.g. with Firefox)
firefox target/doc/citrate/index.html
firefox target/doc/potpourri/index.html
```

* Benchmarks (currently only in Potpourri)

```sh
cd potpourri-rs
cargo bench -F ndarray
```

* Running individual tests

```sh
cd potpourri-rs
cargo test -F ndarray -p potpourri test_multi_pass
```

## License

Published under the MIT license.
12 changes: 3 additions & 9 deletions cerebral-rs/src/adaptable/kohonen.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
//! Classical Kohonen networks
#[derive(Clone)]

/// Rrepresents the adaptivity as defined by Kohonen
pub struct KohonenAdaptivity {}

use ndarray::{prelude::*, Data};
Expand Down Expand Up @@ -45,12 +48,3 @@ where
Box::new(self.clone()) // Forward to the derive(Clone) impl }
}
}
// #[cfg(test)]
// mod tests {

// #[test]
// fn it_works() {
// let result = 2 + 2;
// assert_eq!(result, 4);
// }
// }
5 changes: 4 additions & 1 deletion cerebral-rs/src/adaptable/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Properties of an adaptative self-organizing network

pub mod kohonen;

pub use kohonen::KohonenAdaptivity;
Expand All @@ -7,12 +9,13 @@ use crate::{Neural, Responsive};

pub type BoxedAdaptable<N, R> = Box<dyn Adaptable<N, R> + Send>;

/// Interface for structures encapsulating algorithms for self-organization
/// Trait that update rules / adaptation to new data.
pub trait Adaptable<N, R>
where
R: Responsive<N>,
N: Neural,
{
/// Adapt a self-organizing network to a single pattern / stimuus
fn adapt(
&mut self,
neurons: &mut N,
Expand Down
87 changes: 74 additions & 13 deletions cerebral-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
//! <img src="../cerebral.svg" width="800" />
//! </div>
//!
//! ## About
//!
//! Naming convenctions
//! * traits: Start with capital letter and are adjectives
//! * structs: Start with capital letter and are substantives
//! This crate provides a library for creating highly customizable
//! self-organizing networks.
//!
//! ## Example
//!
//! ```rust
//! use som_rs::default::*;
Expand Down Expand Up @@ -42,6 +44,74 @@
//! som.adapt(&training.row(0), 0.7, 0.7);
//! }
//! ```
//!
//! ## (Naming) convenctions
//!
//! * traits: Start with capital letter and are adjectives
//! * structs: Start with capital letter and are substantives
//!
//! * All aspects of a model (update rules, training, etc.) are
//! represented by a struct that holds it parameters and provides
//! an implementation for the respective trait
//!
//!
//! ## Glossary / Synonyms / Definitions
//!
//!
//! * *Stimulus* (pattern, data point, feature), see [neural::Neural], [neural::NeuralLayer]
//!
//! Stimuli are data points that trigger a response from the neurons
//! of the self organizing network. In silico, this is simply a data
//! point from a data set.
//!
//! * *codebook* (neural weights / weight vector, feature, tuning), see [neural::Neural], [neural::NeuralLayer]
//!
//! Each neuron has a stimulus that it reacts stronger to than all other neurons. This
//! pattern is sometimes called weight (vector).
//! One can say that a neuron is tuned to its weight vector
//! All weights together form a matrix
//! which is called codebook.
//!
//! * *lateral space* (neural coordinate/space/lattice, latent space, hidden space),
//! see [topological::Topological], [topological::CartesianTopology], [neural::Neural], [neural::NeuralLayer]
//!
//! In a simplified reality, each neuron has a 2D coordinate marking its physcal
//! position on the cortex (the neural space). In a self-organizing network, the
//! topology and dimension of this space plays an important role
//!
//! * *Response*, see [responsive::Responsive], [responsive::CartesianResponsiveness]
//!
//! Presented a stimuli, each neuron of a self-organizing network
//! can produce a response. Within the network, exactly one neuron
//! can be triggered from an individual stimulus. In vivo, this neuron
//! suppresses possible responses from other neurons.
//!
//!
//! * *Best-matching unit* (BMU, winning neuron, competive learning), see [responsive::Responsive], [responsive::CartesianResponsiveness]
//!
//! The neuron the creates the stongest (and in vivo, fastest) response to
//! a stimulus. Being the fastest and strongest, it is often referred to as the
//! winning neuron and it suppresses the response of all other neurons. In silico
//! this is the neuron which neural weights resembles most the input given a
//! metric.
//!
//!
//! * *Adaptation* (update, update rule, tuning), see [adaptable::Adaptable], [adaptable::KohonenAdaptivity]
//!
//! The ability of a network to respond and tune to a stimuli. The BMU tunes itself further
//! to the stimulus but so do its adjacent neighbors but with less intensity diminishing with
//! the distance in the neural space
//!
//! * *Training* (learning), see [trainable::Trainable], [trainable::IncrementalLearning]
//!
//! In this context, learning is a process of adapting to multiple stimuli
//! and over an extended period of time possibly with multiple repetitions (i.e., epochs)
//!
//! * Self-organization, see [selforganizing::Selforganizing], [selforganizing::SelforganizingNetwork]
//!
//! A trait of a neural network that emerges when competive learning is implemented.
//! The network starts to map similar input stimuli to adjacent regions in the network
//! thus mapping the topology of input space onto its own neural lattice.

pub mod neural;
pub mod selforganizing;
Expand All @@ -59,6 +129,7 @@ pub use responsive::{BoxedResponsive, Responsive};
pub use topological::{BoxedTopological, Topological};
pub use trainable::{BoxedTrainable, Trainable};

/// Default exports. TODO: rename in prelude
pub mod default {
pub use crate::adaptable::KohonenAdaptivity;
pub use crate::responsive::CartesianResponsiveness;
Expand All @@ -68,13 +139,3 @@ pub mod default {

// #[cfg(feature = "ndarray")]
pub mod nd_tools;

#[cfg(test)]
mod tests {

#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}
33 changes: 0 additions & 33 deletions cerebral-rs/src/main.rs

This file was deleted.

2 changes: 1 addition & 1 deletion cerebral-rs/src/nd_tools/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! This module defines extensions to the ndarray crate. General functions are defined in the top-level
//! Extensions to the ndarray crate. General functions are defined in the top-level

pub mod ndindex;
pub mod point_set;
Expand Down
13 changes: 3 additions & 10 deletions cerebral-rs/src/nd_tools/ndindex.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Indices for ndarrays

use ndarray::{prelude::*, Shape};

/// An iterator over the indices of an ndarray
pub struct NdIndexIterator<D: Dimension> {
shape: Shape<D>,
counter: usize,
Expand Down Expand Up @@ -66,13 +69,3 @@ where

result
}

#[cfg(test)]
mod tests {

#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}
10 changes: 0 additions & 10 deletions cerebral-rs/src/nd_tools/point_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,3 @@ where
row_norm_l2(&self.get_differences(point))
}
}

#[cfg(test)]
mod tests {

#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}
Loading