DAMN (Design A Matrix Now) is a fully-featured Python toolkit for building time-aligned design matrices and fitting Poisson (and other) GLMs to neural data.
It provides:
- Design matrix construction for event-based (e.g. stimulus onset) and continuous (e.g. wheel velocity) regressors
- Automatic resampling of continuous regressors to master timebins
- Many basis functions
- Basis function truncation to avoid trial edge artifacts
- Trial-aligned or session-aligned matrix construction
- Easy dot-based access of individual regressors
- Tags to quickly access and modify (shuffle, zero-out, etc.) regressors of the same group (e.g. stimulus, choice and reward regressors can all be tagged as "task" and accessed together with that tag)
- Kernel reconstruction from weights and basis functions
- GPU-accelerated Poisson GLM fitting (PyTorch), with regularization
- Sklearn-compatible estimator API
- Convenience scoring metrics
# create new python environment with 3.11
conda create --name damn python=3.11
conda activate damnhttps://pytorch.org/get-started/locally/
# clone and install repo
git clone https://github.com/mdmelin/DAMN.git
cd DAMN
pip install -e .
See examples folder for more detailed examples of building and fitting models.
import numpy as np
from damn.objects.design_matrix_objects import DesignMatrix
from damn.objects.regressor_objects import EventRegressor
from damn.objects.basis_function_objects import RaisedCosineBasis
BINWIDTH_S = 0.001
PRE_S = 0.1
POST_S = 0.4
stim_times = np.array([1.0, 2.0, 3.0])
stim_contrasts = np.array([1.0, 0.5, 1.0])
stim_reg = EventRegressor(
name="stimulus",
event_times=stim_times,
event_values=stim_contrasts,
binwidth_s=BINWIDTH_S,
basis_objects=[RaisedCosineBasis(8, 0, 0.6, BINWIDTH_S, log_scale=True)],
)
dmat = DesignMatrix(
master_alignment_times=stim_times,
master_pre_s=PRE_S,
master_post_s=POST_S,
binwidth_s=BINWIDTH_S,
)
dmat.add_regressor(stim_reg)
dmat.build_matrix()
X = dmat.X
print(X.shape)from damn.alignment import compute_spike_count
# spike_times is 1D array for one unit
Y = compute_spike_count(
event_times=stim_times,
spike_times=spike_times,
pre_seconds=PRE_S,
post_seconds=POST_S,
binwidth_s=BINWIDTH_S,
)[0]
# flatten to (T, 1) if needed
Y = Y.reshape(-1, 1)from damn.fit import fit_poisson_glm_lbfgs
W, b, train_loss_hist, val_loss_hist, train_bps_hist, val_bps_hist = fit_poisson_glm_lbfgs(
X=X,
Y=Y,
alpha=1e-8,
max_epochs=1000,
val_fraction=0.1,
early_stopping="train",
patience=10,
)Predicted rates:
Yhat = np.exp(X @ W + b)Defined in damn/basis_functions.py and object wrappers in
damn/objects/basis_function_objects.py.
Implemented basis families include:
no_basisboxcar_smoothgaussian_smoothdelta_basisraised_cosine_basisgaussian_basisbspline_basisfir_basis
Object model:
EventRegressor: sparse events convolved with basis functionsContinuousRegressor: continuous signal resampled to matrix time binsDesignMatrix: container that aligns regressors and exposes concatenatedXmatrix
Useful workflow features:
- name/tag-based grouping
- hide/unhide regressors
- shuffle or zero regressors globally or by tag
- per-regressor kernel reconstruction after fitting coefficients
Available in damn/fit.py:
fit_poisson_glm_lbfgs: full-batch optimizer, generally fastest if data fits VRAMfit_poisson_glm_adam: minibatch optimizer for larger datasetsfit_poisson_glm_best_alpha: choose one best L2 penalty from gridfit_poisson_glm_best_alpha_per_target: choose one alpha per output targetchoose_optimizer: heuristic helper for LBFGS vs Adam choice
damn/sklearn.py provides PoissonGLM, a BaseEstimator/RegressorMixin class.
from damn.sklearn import PoissonGLM
model = PoissonGLM(
optimizer_type="lbfgs",
alpha="find", # automatic alpha search
per_target_alpha=True,
alpha_grid=np.logspace(-12, -8, 5),
max_epochs=1000,
val_fraction=0.1,
)
model.fit(X, Y)
Yhat = model.predict(X)Available in damn/scoring.py:
bits_per_spikebits_per_spike_multi_targetr_squaredr_squared_multi_target
Notebook examples:
examples/1_build_design_matrix.ipynb: design matrix construction and kernel reconstruction.examples/2_fit_poisson_glm_gpu.ipynb: GPU fitting, alpha selection, and cross-validation.
- DAMN is designed around fixed bin width across regressors.
- Trialized matrices are typically preferred over non-trialized matrices.
- Some basis families are intentionally stubbed and raise
NotImplementedError. - For best GPU performance, prefer
fit_poisson_glm_lbfgswhen memory allows.
For feedback, questions, or bug reports, please open an issue on GitHub or email.
This project is licensed under GPL-3.0 (see LICENSE).