SpikeInterface / spikeinterface

A Python-based module for creating flexible and robust spike sorting pipelines.
https://spikeinterface.readthedocs.io
MIT License
492 stars 188 forks source link

About metric #3240

Open bxy666666 opened 1 month ago

bxy666666 commented 1 month ago

Traceback (most recent call last): File "G:\bxy\spikeinterface-main\examples\get_started\quickstart.py", line 102, in metric = spost.compute_template_metrics(we_KS2, include_multi_channel_metrics=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\spikeinterface\postprocessing\template_metrics.py", line 320, in compute_template_metrics tmc.run() File "C:\Python312\Lib\site-packages\spikeinterface\core\waveform_extractor.py", line 2025, in run self._run(*kwargs) File "C:\Python312\Lib\site-packages\spikeinterface\postprocessing\template_metrics.py", line 172, in _run value = func( ^^^^^ File "C:\Python312\Lib\site-packages\spikeinterface\postprocessing\template_metrics.py", line 935, in get_spread MM = gaussian_filter1d(MM, spread_sigma) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\scipy\ndimage_filters.py", line 276, in gaussian_filter1d lw = int(truncate sd + 0.5) ^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: cannot convert float NaN to integer

JoeZiminski commented 1 month ago

Hi @bxy666666, thanks for the bug report. Did you make any changes to the quickstart.py script? What version of spikeinterface are you running?

MilagrosMarin commented 1 month ago

Hi @JoeZiminski,

I've encountered a similar error today while running the latest version of SpikeInterface 0.101.0 through a DataJoint pipeline. The error stack is copied below. Any help you can provide would be greatly appreciated. Thanks!

`Traceback (most recent call last):
  File "/opt/conda/lib/python3.10/site-packages/datajoint/autopopulate.py", line 315, in _populate1
    make(dict(key), **(make_kwargs or {}))
  File "/opt/conda/lib/python3.10/site-packages/element_array_ephys/spike_sorting/si_spike_sorting.py", line 364, in make
    _sorting_analyzer_compute()
  File "/opt/conda/lib/python3.10/site-packages/element_interface/utils.py", line 235, in wrapped
    results = func(*args, **kwargs)
  File "/opt/conda/lib/python3.10/site-packages/element_array_ephys/spike_sorting/si_spike_sorting.py", line 346, in _sorting_analyzer_compute
    sorting_analyzer.compute(extensions_to_compute, **job_kwargs)
  File "/opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py", line 890, in compute
    self.compute_several_extensions(extensions=input, save=save, verbose=verbose, **job_kwargs)
  File "/opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py", line 1029, in compute_several_extensions
    self.compute_one_extension(extension_name, save=save, verbose=verbose, **extension_params)
  File "/opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py", line 967, in compute_one_extension
    extension_instance.run(save=save, verbose=verbose)
  File "/opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py", line 1640, in run
    self._run(**kwargs)
  File "/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py", line 251, in _run
    value = func(
  File "/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py", line 891, in get_spread
    MM = gaussian_filter1d(MM, spread_sigma)
  File "/opt/conda/lib/python3.10/site-packages/scipy/ndimage/_filters.py", line 276, in gaussian_filter1d
    lw = int(truncate * sd + 0.5)
ValueError: cannot convert float NaN to integer`
zm711 commented 1 month ago

@MilagrosMarin,

My guess is that the sd is being converted to a NaN because some number of spikes have Nan values. If you could provide more of the script that feeding into that, we could better diagnose this, specifically:

Like which template metrics are you calculating ? Are you using defaults or other values? What type of Sorting are you putting in (i.e. is this Mountainsort5 or Kilosort4)? Is your recording filtered?

The more your script you're willing to share the more we can diagnose if it is an input error or whether we need to check for a bug in the template_metrics code.

MilagrosMarin commented 1 month ago

@zm711 , of course, and thank you for your reply and time. Here are some more details, please let me know if you need any other info:

For PreProcessing:

recording = si.preprocessing.bandpass_filter(
        recording=recording, freq_min=300, freq_max=4500
    )
    recording = si.preprocessing.common_reference(
        recording=recording, operator="median"

For Processing and PostProcessing:

include_multi_channel_metrics=True seems to be the cause for the mentioned error ValueError: cannot convert float NaN to integer. Here is the specific paramset used for the processing and postprocessing, which corresponds to the default parameter set for spyking circus2 using SpikeInterface v0.101:

{'SI_SORTING_PARAMS': {'general': {'ms_before': 2,
    'ms_after': 2,
    'radius_um': 100},
   'filtering': {'freq_min': 150},
   'detection': {'peak_sign': 'neg', 'detect_threshold': 4},
   'selection': {'method': 'smart_sampling_amplitudes',
    'n_peaks_per_channel': 5000,
    'min_n_peaks': 20000,
    'select_per_channel': False},
   'clustering': {'legacy': False},
   'matching': {'method': 'circus-omp-svd', 'method_kwargs': {}},
   'apply_preprocessing': True,
   'cache_preprocessing': {'mode': 'memory',
    'memory_limit': 0.5,
    'delete_cache': True},
   'multi_units_only': False,
   'job_kwargs': {'n_jobs': 0.8},
   'debug': False},
  'SI_POSTPROCESSING_PARAMS': {'extensions': {'random_spikes': {},
    'waveforms': {},
    'templates': {},
    'noise_levels': {},
    'correlograms': {},
    'isi_histograms': {},
    'principal_components': {'n_components': 5, 'mode': 'by_channel_local'},
    'spike_amplitudes': {},
    'spike_locations': {},
    'template_metrics': {'include_multi_channel_metrics': True},
    'template_similarity': {},
    'unit_locations': {},
    'quality_metrics': {}},
   'job_kwargs': {'n_jobs': -1, 'chunk_duration': '1s'},
   'export_to_phy': True,
   'export_report': True}}}

I've debugged further into the error and here are the outputs for your reference:

This is the code snippet computing the template metrics without including the multichannel metrics (setting it to False), and a successful run:

`In [11]: extensions_to_compute
Out[11]:
{'random_spikes': {},
 'waveforms': {},
 'templates': {},
 'noise_levels': {},
 'correlograms': {},
 'isi_histograms': {},
 'principal_components': {'n_components': 5, 'mode': 'by_channel_local'},
 'spike_amplitudes': {},
 'spike_locations': {},
 'template_metrics': {'include_multi_channel_metrics': False},
 'template_similarity': {},
 'unit_locations': {},
 'quality_metrics': {}}

In [12]:             sorting_analyzer.compute(extensions_to_comput
    ...: e, **job_kwargs)
    ...:
compute_waveforms: 100%|████████| 900/900 [00:16<00:00, 54.42it/s]
Fitting PCA: 100%|████████████████| 20/20 [00:05<00:00,  3.39it/s]
Projecting waveforms: 100%|██████| 20/20 [00:00<00:00, 334.42it/s]
/opt/conda/lib/python3.10/site-packages/spikeinterface/core/job_tools.py:103: UserWarning: `n_jobs` is not set so parallel processing is disabled! To speed up computations, it is recommended to set n_jobs either globally (with the `spikeinterface.set_global_job_kwargs()` function) or locally (with the `n_jobs` argument). Use `spikeinterface.set_global_job_kwargs?` for more information about job_kwargs.
  warnings.warn(
Compute : spike_amplitudes + spike_locations: 100%|█| 900/900 [00:
calculate_pc_metrics: 100%|███████| 20/20 [00:02<00:00,  8.95it/s]

This is the case where include_multi_channel_metrics is set to True and rise the mentioned error.

In [14]: sorting_analyzer.compute({'template_metrics': {'include_m
    ...: ulti_channel_metrics': True}})
/opt/conda/lib/python3.10/site-packages/spikeinterface/core/job_tools.py:103: UserWarning: `n_jobs` is not set so parallel processing is disabled! To speed up computations, it is recommended to set n_jobs either globally (with the `spikeinterface.set_global_job_kwargs()` function) or locally (with the `n_jobs` argument). Use `spikeinterface.set_global_job_kwargs?` for more information about job_kwargs.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:233: UserWarning: With less than 10 channels, multi-channel metrics might not be reliable.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:820: OptimizeWarning: Covariance of the parameters could not be estimated
  popt, _ = curve_fit(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:233: UserWarning: With less than 10 channels, multi-channel metrics might not be reliable.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:820: OptimizeWarning: Covariance of the parameters could not be estimated
  popt, _ = curve_fit(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:233: UserWarning: With less than 10 channels, multi-channel metrics might not be reliable.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:820: OptimizeWarning: Covariance of the parameters could not be estimated
  popt, _ = curve_fit(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:233: UserWarning: With less than 10 channels, multi-channel metrics might not be reliable.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:820: OptimizeWarning: Covariance of the parameters could not be estimated
  popt, _ = curve_fit(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:233: UserWarning: With less than 10 channels, multi-channel metrics might not be reliable.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:820: OptimizeWarning: Covariance of the parameters could not be estimated
  popt, _ = curve_fit(
/opt/conda/lib/python3.10/site-packages/sklearn/metrics/_regression.py:1211: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples.
  warnings.warn(msg, UndefinedMetricWarning)
/opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:233: UserWarning: With less than 10 channels, multi-channel metrics might not be reliable.
  warnings.warn(
/opt/conda/lib/python3.10/site-packages/numpy/core/fromnumeric.py:3504: RuntimeWarning: Mean of empty slice.
  return _methods._mean(a, axis=axis, dtype=dtype,
/opt/conda/lib/python3.10/site-packages/numpy/core/_methods.py:129: RuntimeWarning: invalid value encountered in scalar divide
  ret = ret.dtype.type(ret / rcount)
------------------------------------------------------------------
ValueError                       Traceback (most recent call last)
Cell In[14], line 1
----> 1 sorting_analyzer.compute({'template_metrics': {'include_multi_channel_metrics': True}})

File /opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py:890, in SortingAnalyzer.compute(self, input, save, extension_params, verbose, **kwargs)
    888     params_, job_kwargs = split_job_kwargs(kwargs)
    889     assert len(params_) == 0, "Too many arguments for SortingAnalyzer.compute_several_extensions()"
--> 890     self.compute_several_extensions(extensions=input, save=save, verbose=verbose, **job_kwargs)
    891 elif isinstance(input, list):
    892     params_, job_kwargs = split_job_kwargs(kwargs)

File /opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py:1029, in SortingAnalyzer.compute_several_extensions(self, extensions, save, verbose, **job_kwargs)
   1027         self.compute_one_extension(extension_name, save=save, verbose=verbose, **extension_params, **job_kwargs)
   1028     else:
-> 1029         self.compute_one_extension(extension_name, save=save, verbose=verbose, **extension_params)
   1030 # then extensions with pipeline
   1031 if len(extensions_with_pipeline) > 0:

File /opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py:967, in SortingAnalyzer.compute_one_extension(self, extension_name, save, verbose, **kwargs)
    965     extension_instance.run(save=save, verbose=verbose, **job_kwargs)
    966 else:
--> 967     extension_instance.run(save=save, verbose=verbose)
    969 self.extensions[extension_name] = extension_instance
    971 return extension_instance

File /opt/conda/lib/python3.10/site-packages/spikeinterface/core/sortinganalyzer.py:1640, in AnalyzerExtension.run(self, save, **kwargs)
   1637     self._save_params()
   1638     self._save_importing_provenance()
-> 1640 self._run(**kwargs)
   1642 if save and not self.sorting_analyzer.is_read_only():
   1643     self._save_data(**kwargs)

File /opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:251, in ComputeTemplateMetrics._run(self, verbose)
    248             sampling_frequency_up = sampling_frequency
    250         func = _metric_name_to_func[metric_name]
--> 251         value = func(
    252             template_upsampled,
    253             channel_locations=channel_locations_sparse,
    254             sampling_frequency=sampling_frequency_up,
    255             **self.params["metrics_kwargs"],
    256         )
    257         template_metrics.at[index, metric_name] = value
    258 self.data["metrics"] = template_metrics

File /opt/conda/lib/python3.10/site-packages/spikeinterface/postprocessing/template_metrics.py:891, in get_spread(template, channel_locations, sampling_frequency, **kwargs)
    888     from scipy.ndimage import gaussian_filter1d
    890     spread_sigma = spread_smooth_um / np.median(np.diff(np.unique(channel_depths)))
--> 891     MM = gaussian_filter1d(MM, spread_sigma)
    893 MM = MM / np.max(MM)
    895 channel_locations_above_threshold = channel_locations[MM > spread_threshold]

File /opt/conda/lib/python3.10/site-packages/scipy/ndimage/_filters.py:276, in gaussian_filter1d(input, sigma, axis, order, output, mode, cval, truncate, radius)
    274 sd = float(sigma)
    275 # make the radius of the filter equal to truncate standard deviations
--> 276 lw = int(truncate * sd + 0.5)
    277 if radius is not None:
    278     lw = radius

ValueError: cannot convert float NaN to integer`
zm711 commented 1 month ago

Let me actually tag @alejoe91, since he knows this better than I do. I think he may have tried to work on this to protect for nans. So this may be fixed on main. It might be worth installing from main/source and see if it is fixed @MilagrosMarin.