Optimal Transport Theory to Extract Spiking Motifs
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 154 lines · 7.8 KB · no license
- # %%
- %load_ext autoreload
- %autoreload 2
- # %%
- import torch
- import matplotlib.pyplot as plt
- import numpy as np
- from dataset_generation import generate_dataset, sm_generative_model
- from wassa_plots import plot_SM, plot_colored_raster
- # %% [markdown]
- # # Generative model for raster plots and spiking motifs
- # %% [markdown]
- # List of parameters for this generative model
- # %%
- dataset_parameters = {
- 'seed' : 81,
- 'N_pre' : 100, # number of neurons
- 'N_timesteps' : 1000, # number of timesteps for the raster plot (in ms)
- 'N_samples' : 60, # total number of samples in the dataset
- 'N_delays' : 51, # number of timesteps in spiking motifs, must be a odd number for convolutions
- 'N_SMs' : 3, # number of structured spiking motifs
- 'avg_fr' : 20, # average firing rate of the neurons (in Hz)
- 'std_fr' : .1, # standard deviation for the firing rates of the different neurons
- 'overlapping_sms' : True, # possibility to have overlapping sequences
- 'temporal_jitter' : .1, # temporal jitter for the spike generation in motifs
- 'dropout_proba' : 0, # probabilistic participations of the different neurons to the spiking motif
- 'additive_noise' : .1, # percentage of background noise/spontaneous activity
- 'warping_coef' : 1, # coefficient for time warping
- }
- dataset_parameters.update({'N_involved':dataset_parameters['N_pre']*torch.ones(dataset_parameters['N_SMs'])}) # number of neurons involved in the spiking motif
- dataset_parameters.update({'frs' : torch.normal(dataset_parameters['avg_fr'], dataset_parameters['std_fr'], size=(dataset_parameters['N_pre'],)).abs()})
- dataset_parameters.update({'freq_sms' : 4*torch.ones(dataset_parameters['N_SMs'])}) # frequency of apparition of the different spiking motifs (in Hz)
- dataset_parameters.update({'coefficient_variation' : 1*torch.ones(dataset_parameters['N_pre'])}) # coefficient of variation of the FRs of each neuron (within VS. without a motif)
- # %%
- sm = sm_generative_model(dataset_parameters)
- # %% [markdown]
- # The generative model will draw raster plots generated from both a spontaneous (random) activity and from spiking motifs. There are *parameters.N_SM* spiking motifs represented in the next plot. There are given as a spiking probability for each presynatpic neuron and each timestep (or delay).
- # %%
- plot_SM(sm.SMs);
- # %% [markdown]
- # The raster plot is produced with a sequence of apparition of the different motifs and random activity when no motif occurs.
- # %%
- number_of_trials = 100
- input_rp, output_rp = sm.draw_input(nb_trials=number_of_trials)
- # %%
- random_ind = torch.randint(dataset_parameters['N_samples'],[1])
- plot_colored_raster(input_rp[random_ind].squeeze(0), output_rp[random_ind].squeeze(0), dataset_parameters['N_delays'], dataset_parameters['warping_coef']);
- # %% [markdown]
- # The not structured spiking activity of the different neurons is given by their FRs (*parameters.frs*). Then, it is given by the occurence of a motif (colored parts of the raster plot) and the structure of the motif. The occurence of a motif is given by a random trial defining its timing and its type (or color).
- #
- # The raster plot is obtained with a Bernoulli trial on the probability distribution representing the non structured (flat distribution) or the structured (probability distributions of the different motifs). When motifs overlap the formula used to merge the motifs and obtain the expected raster plot is the following:
- # $$Bernoulli(p) + Bernoulli(q) = Bernoulli(p+q-p*q)$$
- #
- # It leads to Poisson distribution with an expected number of spike during the trial and their relative temporal dependencies that can vary with the number of motifs, their frequency of apparition (*parameters.freq_sm*) or the number of neurons involved in the motif (*parameters.N_involved*)
- # %%
- def moving_average(x, w):
- return np.convolve(x, np.ones(w), 'valid') / w
- fig, ax = plt.subplots(figsize = (12, 1.61803))
- ax.plot(moving_average(input_rp[0].sum(axis=(0)),1))
- ax.set_xlim(0, dataset_parameters['N_timesteps'])
- ax.set_xlabel('Time (a. u.)')
- ax.set_ylabel('Spike number')
- ax.set_title('Moving average of the number of spike per timebin');
- # %% [markdown]
- # The instantaneous firing rate sumed over the different trials shows that the distribution is Poisson. And we can check the effective number of spikes per neuron compared to the expected firing rate. Firing rate of the different neurons can be easily changed, default is chosen by following a normal distribution around an average firing rate.
- # %%
- fig, ax = plt.subplots()
- ax.bar(np.arange(dataset_parameters['N_pre']),1e3*input_rp.mean(axis=(0,2)))
- ax.plot(dataset_parameters['frs'], 'ro', label='expected firing rate')
- ax.set_xlabel('@ Neuron')
- ax.set_ylabel('Firing rate (in Hz)')
- ax.legend();
- ax.set_title('Average number of spikes per neuron');
- # %% [markdown]
- # We can also check the number of occurence of the motifs and compare it to the expected number of occurence.
- # %%
- fig, ax = plt.subplots()
- ax.bar(np.arange(dataset_parameters['N_SMs']),output_rp.sum(axis=(0,2)))
- ax.plot(dataset_parameters['freq_sms']*number_of_trials*dataset_parameters['N_timesteps']*1e-3, 'ro', label='expected number')
- ax.set_xlabel('Spiking motif #')
- ax.set_ylabel('Number of occurence')
- ax.set_title('Occurence of the different motifs');
- ax.legend();
- # %% [markdown]
- # ## No overlap of the motifs
- #
- # If you set the following parameter to False, then the overlap of the motifs is prevented.
- # %%
- sm.opt['overlapping_sms'] = False
- input_rp, output_rp = sm.draw_input(nb_trials=100)
- # %%
- random_ind = torch.randint(dataset_parameters['N_samples'],[1])
- plot_colored_raster(input_rp[random_ind].squeeze(0), output_rp[random_ind].squeeze(0), dataset_parameters['N_delays'], dataset_parameters['warping_coef']);
- # %%
- fig, ax = plt.subplots()
- ax.bar(np.arange(dataset_parameters['N_SMs']),output_rp.sum(axis=(0,2)))
- ax.plot(dataset_parameters['freq_sms']*dataset_parameters['N_timesteps']*number_of_trials*1e-3, 'ro', label='expected number')
- ax.set_xlabel('Spiking motif #')
- ax.set_ylabel('Number of occurence')
- ax.set_title('Occurence of the different motifs');
- ax.legend();
- # %% [markdown]
- # ## Save a dataset
- #
- # You can also easily save a dataset with a defined number of trials (*total_number_of_trials*). It will split the dataset into a training (80% of the trials) and a testing (20% of the trials) of the trials sets.
- # %%
- total_number_of_trials = 1000
- sm, dataset_input, dataset_output = generate_dataset(dataset_parameters, record_path = './synthetic_data/')
- # %%
- random_ind = torch.randint(dataset_parameters['N_samples'],[1])
- plot_colored_raster(input_rp[random_ind].squeeze(0), output_rp[random_ind].squeeze(0), dataset_parameters['N_delays'], dataset_parameters['warping_coef']);
- # %% [markdown]
- # ## Alteration of the motifs
- #
- # There are different types of noise that can be added to the motifs:
- # - temporal jitter: the timing of a spiking can be shifted in time. It is modeled by convolving the precise spiking motifs with a gaussian kernel (its standard deviation (*parameters.temporal_jitter*) gives the amount of jitter).
- # - stochatistic activation of the neurons: neurons can also not participate in the generation of a spike at a specific spatio temporal location. This participation is obtained with a random trial on which neurons will be activated with a probability of activation for each neuron (*parameters.dropout_proba*)
- # - additive noise: percentage of background activity given by (*parameters.additive_noise*).
- # - time warping: the kernel is streched in time with a specific coefficient (parameters.warping_coef)
- # %% [markdown]
- # Because we maintain a constant firing rates for the different trials and the way the generative model is defined, these types of alteration will occur only at the motif level and then, a background activity of 100% leads to the same type of unstructured activity as a dropout probability of 1 for each of the neurons or an infinite temporal jitter.
- # %%
TUTO_generation_synthetic_datasets.ipynb at commit bb3d841, no license · at the source
Overview
- Centre de Recherche Cerveau et Cognition (CerCo), UMR 5549, CNRS, Université Toulouse III – Paul Sabatier, Toulouse, France
- Ernst Strüngmann Institute for Neuroscience, Ernst Strüngmann Institute, Frankfurt am Main, Germany
- Center for Neurology, Department of Parkinson, Sleep and Movement Disorders (DZNE), Bonn, Germany
- Institute of Informatics, Austral University of Chile, Valdivia, Chile
- Institut de Neurosciences de la Timone (INT), UMR 7289, CNRS, Aix-Marseille Université, Marseille, France
- Donders Centre for Neuroscience, Radboud University Nijmegen, Nijmegen, Netherlands
Abstract
Spatiotemporal spike motifs, i.e. repeating temporal sequences, of neural activity are thought to carry information beyond average firing rates, yet extracting such motifs from noisy spike trains remains challenging. In particular, most approaches rely on bin-by-bin comparisons that are sensitive to bin size and temporal jitter. Here, we investigate the use of the Earth Mover’s Distance (EMD), a metric from optimal transport theory, as a reconstruction loss for learning spiking motifs. We compare EMD to the conventional mean squared error (MSE) by training single-layer autoencoders with tied positive weights to reconstruct neural raster plots. Using synthetic spike trains with known ground-truth motifs, we systematically evaluate how each loss recovers spatiotemporal structure under varying numbers of training samples and different noise regimes, including temporal jitter, sequence warping, neuron dropout, and additive Poisson noise. We show that EMD-based training is more robust to temporal jitter and sequence warping, and more reliably estimates aligned spike timings when the number of training samples is limited. In contrast, MSE better captures the full spike distribution, i.e. the relative timing of the spikes as well as their temporal precision, when large datasets are available and is more resilient to additive noise. Applying the same framework to Neuropixels recordings from the Allen Institute visual coding dataset reveals that motifs learned with EMD are more discriminative of visual stimuli than those learned with MSE. Together, these results highlight the advantages of optimal transport–based losses for learning spatiotemporal motifs in neural population activity.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above.
antoinegrimaldi/wassa
bb3d84170378752c63ec54cde202c8143b612ee0, 8 July 2026Availability: 1 check, the latest on 30 September 2026: the link answers
- 30 September 2026: the link answers
40 files
- dev/
TUTO_generation_syntheti , Jupyter, 154 linesc_datasets.ipynb - dev/
TUTO_learning_patterns.i , Jupyter, 100 linespynb - dev/
adamw_eg.py , Python, 377 lines - dev/
allendataset_training_sy , Jupyter, 224 linesnthetic_data-Copy1.ipynb - dev/
allendataset_training_sy , Jupyter, 134 linesnthetic_data.ipynb - dev/
dataset_generation.py , Python, 180 lines - dev/
figure_3_dropout.ipynb , Jupyter, 132 lines - dev/
results_jitter.ipynb , Jupyter, 106 lines - dev/
wassa.py , Python, 78 lines - dev/
wassa_allen.py , Python, 70 lines - dev/
wassa_functions.py , Python, 172 lines - dev/
wassa_metrics.py , Python, 88 lines - dev/
wassa_plots.py , Python, 289 lines - dev/
wassa_training.py , Python, 248 lines - dev/
wassa_utils.py , Python, 174 lines - results_paper/
adamw_eg.py , Python, 377 lines - results_paper/
annexe_allendataset_deco , Jupyter, 847 linesding.ipynb - results_paper/
annexe_allendataset_deco , Jupyter, 211 linesding_multipatterns.ipynb - results_paper/
annexe_allendataset_deco , Jupyter, 285 linesding_n_epochs.ipynb - results_paper/
annexe_allendataset_deco , Jupyter, 605 linesding_no_normalization_FR s.ipynb - results_paper/
annexe_allendataset_resu , Jupyter, 465 lineslts_id_vs_ood.ipynb - results_paper/
annexe_allendataset_resu , Jupyter, 1,081 lineslts_one_animal.ipynb - results_paper/
annexe_results_num_patte , Jupyter, 128 linesrns.ipynb - results_paper/
dataset_generation.py , Python, 154 lines - results_paper/
figure_2_num_samples.ipy , Jupyter, 142 linesnb - results_paper/
figure_3_all.ipynb , Jupyter, 143 lines - results_paper/
figure_3_background_nois , Jupyter, 123 linese.ipynb - results_paper/
figure_3_dropout.ipynb , Jupyter, 136 lines - results_paper/
figure_3_jitter.ipynb , Jupyter, 118 lines - results_paper/
figure_3_warping.ipynb , Jupyter, 119 lines - results_paper/
figure_4_allendataset_de , Jupyter, 622 linescoding.ipynb - results_paper/
generation_synthetic_dat , Jupyter, 72 linesasets.ipynb - results_paper/
wassa.py , Python, 61 lines - results_paper/
wassa_allen.py , Python, 131 lines - results_paper/
wassa_functions.py , Python, 174 lines - results_paper/
wassa_metrics.py , Python, 170 lines - results_paper/
wassa_plots.py , Python, 302 lines - results_paper/
wassa_training.py , Python, 216 lines - results_paper/
wassa_utils.py , Python, 161 lines - README.md, Text, 8 lines
Code Availability
This work is made reproducible. The code reproducing the manuscript and all figures is available on https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 39 scripts, each with its path and the digest of its content;
- no match between paragraphs and code yet;
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data and Materials Availability
Not applicable.
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 September 2026: the first record
Recorded: type, journal, dates, 6 authors, 4 keywords, 1 funder, 18 references.
Cite
This paper
Grimaldi, A., Sotomayor-Gómez, B., Gilson, M., Perrinet, L. U., Alamia, A., & Vinck, M. (2026). Optimal Transport Theory to Extract Spiking Motifs. Research Square (preprint). https://
BibTeX
@article{grimaldi2026opt
author = {Grimaldi, Antoine and Sotomayor-Gómez, Boris and Gilson, Mathieu and Perrinet, Laurent U and Alamia, Andrea and Vinck, Martin},
title = {{Optimal Transport Theory to Extract Spiking Motifs}},
journal = {Research Square (preprint)},
year = {2026},
month = apr,
publisher = {Research Square},
issn = {2693-5015},
doi = {10.21203/
url = {https://
}
RIS
TY - JOUR
AU - Grimaldi, Antoine
AU - Sotomayor-Gómez, Boris
AU - Gilson, Mathieu
AU - Perrinet, Laurent U
AU - Alamia, Andrea
AU - Vinck, Martin
TI - Optimal Transport Theory to Extract Spiking Motifs
T2 - Research Square (preprint)
J2 - Res Sq
PY - 2026
DA - 2026/
SN - 2693-5015
PB - Research Square
DO - 10.21203/
UR - https://
ER -
CSL-JSON
{
"id": "10.21203/
"type": "article",
"title": "Optimal Transport Theory to Extract Spiking Motifs",
"container-title": "Research Square (preprint)",
"author": [
{
"family": "Grimaldi",
"given": "Antoine"
},
{
"family": "Sotomayor-Gómez",
"given": "Boris"
},
{
"family": "Gilson",
"given": "Mathieu"
},
{
"family": "Perrinet",
"given": "Laurent U"
},
{
"family": "Alamia",
"given": "Andrea"
},
{
"family": "Vinck",
"given": "Martin"
}
],
"container-title-short":
"DOI": "10.21203/
"ISSN": "2693-5015",
"publisher": "Research Square",
"URL": "https://
"issued": {
"date-parts": [
[
2026,
4,
30
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.3390/brainsci13010068 [code]
- Precise Spiking Motifs in Neurobiological and Neuromorphic Data.Journal: Brain sciencesIn common: PyTorch, seaborn, pandas, 3 other tools, computational, 1 reference
- [2] doi:10.1371/journal.pcbi.1010764 [code]
- Improved visualization of high-dimensional data using the distance-of-distance transformation.Journal: PLoS computational biologyIn common: PyTorch, pandas, SciPy, 2 other tools, 2 references
- [3] doi:10.1016/j.celrep.2026.117159 [code]
- Cellular and subcellular specialization enables biology-constrained deep learning.Journal: Cell reportsIn common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
- [4] doi:10.1038/s41467-026-76939-w [code]
- HIPPIE: a generative model for electrophysiological analysis across species, technologies, and modalities.Journal: Nature communicationsIn common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
- [5] doi:10.1038/s41467-025-64259-4 [code]
- Data-driven fine-grained region discovery in the mouse brain with transformers.Journal: Nature communicationsIn common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
- [6] doi:10.1038/s41562-025-02252-z [code]
- In silico discovery of representational relationships across visual cortex.Journal: Nature human behaviourIn common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
- [7] doi:10.1371/journal.pcbi.1010233 [code]
- Sequence learning, prediction, and replay in networks of spiking neurons.Journal: PLoS computational biologyIn common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
- [8] doi:10.1038/s41593-024-01626-2 [code]
- Dimensionality reduction beyond neural subspaces with slice tensor component analysis.Journal: Nature neuroscienceIn common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
- [9] doi:10.1371/journal.pcbi.1011335 [code]
- SpikeShip: A method for fast, unsupervised discovery of high-dimensional neural spiking patterns.Journal: PLoS computational biologyIn common: Matplotlib, NumPy, 3 references
- [10] doi:10.1007/s00422-026-01048-2 [code]
- A quality measure for repeating multiple-unit spike patterns.Journal: Biological cyberneticsIn common: Matplotlib, NumPy, computational, 2 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 39 scripts, and 0 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:967914e9fba6b6b4…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1.svg
:target: https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1"><img src="https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".
If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
