A tool for fixing oversplitting errors in high-density ephys spike sorting.
Project description
SLAy oversplitting errors in your spike sorting!
Manually merging spike sorted units is time-consuming, subjective, and lacks reproducibility. SLAy uses quantitative metrics to automatically identify oversplit units, which can then be merged automatically or reviewed further manually. Specifically, we developed a novel metrics for (1) calculating waveform similarity using an autoencoder, and (2) capturing structure in cross-correlograms. When used with automatic unit quality labelling (e.g., via SpikeInterface or BombCell), SLAy can fully automate the manual curation process, making it feasible to quickly process many single- or multi- probe ephys recordings. Read our paper to learn more about SLAy.
Installation
We recommend using uv to install SLAy. If you want to use your GPU to train SLAy's autoencoder, which is recommended, you will also need CUDA (if on an NVIDIA GPU) and the GPU version of pytorch. The instructions below show how to install pytorch for CUDA 12.6, but you should modify it to match your CUDA version.
uv (recommended)
- Install CUDA if you don't already have it.
- Install pytorch for GPU following the instructions here.
- Install SLAy:
uv add slay
pip + conda (slower)
-
Install CUDA if you don't already have it.
-
Create a new conda environment.
conda create -n slay python=3.11 conda activate slay # optional but highly recommended, for GPU autoencoder training pip install torch --index-url https://download.pytorch.org/whl/cu126
-
Install SLAy.
pip install slay
(Prerequisite) SpikeInterface SortingAnalyzer
Create a SortingAnalyzer
To ensure compatibility with any recording hardware and spike sorter, SLAy operates on SpikeInterface's SortingAnalyzer. If your pipeline already uses SpikeInterface for preprocessing and sorting, you can create a SortingAnalyzer like this:
sorting_analyzer = si.create_sorting_analyzer(
sorting,
recording_preprocessed,
format="binary_folder", # change if desired
folder="/my_sorting_analyzer",
**job_kwargs
)
Otherwise, you can use SpikeInterface's read_XXX functions (see a full list) to load in your pre-processed recording and spike sorter output. For example, to load in a SpikeGLX recording processed with CatGT and sorted with Kilosort:
import spikeinterface.full as si
recording_preprocessed = si.read_spikeglx(
recording_folder,
stream_id="imec0.ap"
)
sorting = si.read_kilosort(kilosort_folder)
sorting_analyzer = si.create_sorting_analyzer(
sorting,
recording_preprocessed,
format="binary_folder", # change if desired
folder="/my_sorting_analyzer",
**job_kwargs
)
Compute extensions
SLAy's metrics rely on your SortingAnalyzer to access spike waveforms and cross-correlograms. SLAy will use your SortingAnalyzer to compute these automatically if they are not already present, but we recommend precomputing them for use in other processing steps and so SLAy runs faster:
job_kwargs = dict(n_jobs=-1, progress_bar=True, chunk_duration="1s")
sorting_analyzer.compute("random_spikes", method="uniform", max_spikes_per_unit=500)
sorting_analyzer.compute("waveforms", **job_kwargs)
sorting_analyzer.compute("templates", **job_kwargs)
sorting_analyzer.compute("correlograms", window_ms=100, bin_ms=2.) # change to match your brain region/animal model
sorting_analyzer.compute("quality_metrics", metric_names=["snr", "firing_rate"])
You should set the cross-correlogram parameters based on the standard range for your brain region(s) and animal model.
Remove noise and multi-units
To avoid extra computations, you should give SLAy a SortingAnalyzer that does not contain noise or multi-units. This can be done with si.select_units().
Using SLAy
(default) with autoencoder and automatic parameter selection
You do not need a pre-trained autoencoder to run SLAy. To run SLAy with autoencoder-based similarity and automatic parameter selection:
from slay import compute_slay_merges
merges, sorting_analyzer, slay_metrics = compute_slay_merges(
sorting_analyzer,
model_path="save/path/for/autoencoder.pt",
)
This will extract spike snippets from your recording, train and save the autoencoder, compute the SLAy merge metrics, and output a list of suggested merges. By default, SLAy will automatically select the appropriate parameters (coefficients and merge threshold) for your recording. You can use SpikeInterface to merge the suggestions:
merged_sorting_analyzer = sorting_analyzer.merge_units(
merges,
censor_ms=5/30000, # remove duplicate spikes
format="binary_folder",
folder="/my_merged_sorting_analyzer"
)
or review them manually in SpikeInterface-GUI or Phy.
Note: If you have a pretrained model, you can point
model_pathto the.ptfile and SLAy will automatically use it! SLAy's autoencoder usually trains in under 10 minutes, but if you are processing many recordings from the same animal with the same site map, you can save time by reusing the same autoencoder.
with manual parameter selection
If you want manual control over SLAy's parameters, you can specify custom parameters through the merge_parameters argument. You must specify a dictionary with values for "k1" (coefficient for CCG structure metric), "k2" (coefficient for refractory period penalty), and "merge_threshold". Below is a reasonable starting point for manual adjustment:
merges, sorting_analyzer, slay_metrics = compute_slay_merges(
sorting_analyzer,
merge_parameters={"k1": 0.25, "k2": 1, "merge_threshold": 0.5},
model_path="save/path/for/autoencoder.pt",
)
with L2 waveform similarity
If you don't want to use autoencoder-based waveform similarity (e.g., if you don't have a GPU and CPU-training would be too slow), you can run SLAy with a simpler measure of waveform similarity:
merges, sorting_analyzer, slay_metrics = compute_slay_merges(
sorting_analyzer,
model_path="save/path/for/autoencoder.pt",
similarity_type="l2"
)
We found that the L2 similarity performs similarly to the autoencoder for some recordings, but has false positives and negatives for others (see paper to learn more about SLAy).
directly through SpikeInterface
If you do not want to use autoencoder-based waveform similarity or automatic parameter selection, you can run an L2-similarity version of SLAy directly through SpikeInterface:
from spikeinterface.curation import compute_merge_unit_groups
merges = compute_merge_unit_groups(
sorting_analyzer,
preset="slay",
steps_params={"slay_score": {"k1": 0.25, "k2": 1.0, "slay_threshold": 0.5}},
resolve_graph=True # find multi-way merges (>2 units)
)
merged_sorting_analyzer = sorting_analyzer.merge_units(
merges,
censor_ms=5/30000, # remove duplicate spikes
format="binary_folder",
folder="/my_merged_sorting_analyzer"
)
Questions/Issues
This codebase is in beta --- if you have questions or run into any errors, open a GitHub issue or shoot me an email!
Citing
If you use SLAy in your own work, please cite our paper!
S. Koukuntla, T. Deweese, A. Cheng, R. Mildren, A. Lawrence, A. Graves, K.E. Cullen, J. Colonell, T.D. Harris, and A.S. Charles. SLAy-ing errors in high-density electrophysiology spike sorting. bioRxiv, doi: 10.1101/2025.06.20.660590., 2025 https://www.biorxiv.org/content/10.1101/2025.06.20.660590v1.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slay-0.1.0a0.tar.gz.
File metadata
- Download URL: slay-0.1.0a0.tar.gz
- Upload date:
- Size: 39.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b93d00028c76806ac023c6e5623d0d085de040a35678552f103208cef03e51bf
|
|
| MD5 |
18887d5dc1f0b9ced4b6b6d1fd18b323
|
|
| BLAKE2b-256 |
a6081b373f1bab2079b1a54cf54d7eab3b70fe824c01092b795f1d01809b646f
|
File details
Details for the file slay-0.1.0a0-py3-none-any.whl.
File metadata
- Download URL: slay-0.1.0a0-py3-none-any.whl
- Upload date:
- Size: 40.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e778b16d1f5860c9a1080a0032569afca99fd0f1a176fffd3ac9fcbaedb56ecc
|
|
| MD5 |
3226993e3266627d838eca02c991aed9
|
|
| BLAKE2b-256 |
c91cdf042fd58c98c5b30ca0bc339143410073b031aeb781a6b8ebb536a7d469
|