Skip to content

Allow for the creation of template libraries from a recording - #4906

Open
chrishalcrow wants to merge 6 commits into
SpikeInterface:mainfrom
chrishalcrow:just-template-library
Open

chrishalcrow wants to merge 6 commits into
SpikeInterface:mainfrom
chrishalcrow:just-template-library

Conversation

@chrishalcrow

@chrishalcrow chrishalcrow commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Sometimes you just want a template library.

Would close #4747

In e.g. very long recordings, it might be a good idea to create a template library by sampling the whole recording. Once you have your template library, you can then parallelize the actual template matching easily. This requires the template library creation being separated out from the peak detection.

The main problem is that building a template library depends on TONS of parameters, since they often use many functions (e.g. lupin uses: get_noise_levels, get_prototype_and_waveforms_from_recording, detect_peaks, select_peaks, find_clusters_from_peaks, compute_sparsity_from_peaks_and_label, estimate_templates_with_accumulator and clean_templates).

To avoid regurgitating the complex parameter handling needed for this task, this PR implements a simple idea, originally implemented by @yger: just run the sorters and bail out before the template matching step.

This requires minimal adjustments to the sorters, and a bit of a hack in the estimate_templates_from_recording to deal with our expected folder structures in run_sorter.

I think it's neat!

Alternatively, we could make a new estimate_templates function that would look like a big chain of sorting components, which would also have to handle parameters. I think this is a bad idea.

Also removes the old estimate_templates_from_recording which has been broken for a while.

@yger yger left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I think this the general spirit and this is good enough to get quickly a Template library for a given dataset


def estimate_templates_from_recording(
recording: BaseRecording,
sorter_name: Literal["spykingcircus2", "tridesclous2", "lupin"] = "spykingcircus2",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think lupin could be the default

"seed": None,
"save_array": True,
"debug": False,
"_just_make_template_library": False,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we sure we want this to be a private param? then _templates_only might be better or shorter, no?

@chrishalcrow
chrishalcrow marked this pull request as ready for review November 10, 2026 09:26
@yger

yger commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Actually, here also maybe we should be a bit more cautious, or at least be warning the user at the end that the templates are computed in the whitened space. In fact, Lupin even if the data are preprocessed will ALWAYS whiten, and thus work in such a space. Maybe this would be interesting to save the whitening matrix, and unwhitened the templates?


from spikeinterface.sortingcomponents.tools import estimate_templates_from_recording

templates = estimate_templates_from_recording(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said, this is the tricky problem of whitening. Do we want to warn the user that the templates will be (sometimes) obtained in a space which is not the one of the provided data? We need to deal with that more carefully I think, otherwise this could be confusing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or at the very least, state that explicitly in the docs. I'll double check, but not even sure lupin, sc2 and tdc2 behaves the same with respect to whitening. Some will do it even if apply_preprocessing is False (lupin), and some will not (sc2 and tdc2).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about adding an optional whitening_matrix to the Templates class? Then we can always save unwhitened and propagate the whitening option. The Templates themselves could return get_whitened_templates

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah, sounds tricky to solve in general. And we don't know what sorters will look like in the future. For my use case, I just want whatever templates the sorters will go on to use in their template matching. But for comparisons / visualisations I guess you want more control. I'll add some docs at the very least.

@JoeZiminski JoeZiminski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool, on the whitening if the matrix is readily available in the sorter code might as well return it, but if its a pain to get I wouldn't bother.

Could be an idea to add this to kilosort4 too? I think it would be a few lines after the detect_spikes is run:

templates = (
    Wall.unsqueeze(-1).cpu() * ops["wPCA"].cpu()
).sum(axis=-2).numpy()

templates = templates.transpose(0, 2, 1)
# shape: (num_units, num_samples, num_channels)

# save templates...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add function to estimate_templates_from_recording

4 participants