SpikeInterface / SpikeInterface/spikeinterface

Memory error when extracting single channel raw data

Open
#3,303 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

NEO
Dominant language
Python
Stars
847
Forks
280
Avg merge
3d 9h
Merged PRs (30d)
29

Description

Hello,

So I am trying to extract a raw single channel from a biocam recording to use as an electrical stimulus onset TTL pulse timer for removing stimulation artefacts. However when I try to extract it, the script trying to create an array which is the full recording size (>90Gb) and it obviously crashes. This happens whether I try and get the single channel from either the full recording or whether I split off the channel with rec.channel_slice(). The function works find if I work in small time chunks but I would really prefer to get the full trace together. See the code below:

rec = si.BiocamRecordingExtractor('Test_stim_rawData_00.brw')
print(Rec)

BiocamRecordingExtractor: 4096 channels - 19.8kHz - 1 segments - 11,852,265 samples
600.00s (10.00 minutes) - uint16 dtype - 90.43 GiB
file_path: D:\Data\MEA_recording\CloseNIT\20240812\Test_stim_rawData_00.brw

numSamps = rec.get_total_samples()
triggerRec = rec.channel_slice(channel_ids=['1'])
print(triggerRec)
triggerTrace = triggerRec.get_traces(segment_index=0, channel_ids=['1'], start_frame=0, end_frame=numSamps)

ChannelSliceRecording: 1 channels - 19.8kHz - 1 segments - 11,852,265 samples
600.00s (10.00 minutes) - uint16 dtype - 22.61 MiB


MemoryError Traceback (most recent call last)
Cell In[47], line 6
4 triggerRec = rec.channel_slice(channel_ids=['1'])
5 print(triggerRec)
----> 6 triggerTrace = triggerRec.get_traces(segment_index=0, channel_ids=['1'], start_frame=0, end_frame=numSamps)

File D:\Code\python\spikeinterface\src\spikeinterface\core\baserecording.py:342, in BaseRecording.get_traces(self, segment_index, start_frame, end_frame, channel_ids, order, return_scaled, cast_unsigned)
340 num_samples = rs.get_num_samples()
341 end_frame = int(min(end_frame, num_samples)) if end_frame is not None else num_samples
--> 342 traces = rs.get_traces(start_frame=start_frame, end_frame=end_frame, channel_indices=channel_indices)
343 if order is not None:
344 assert order in ["C", "F"]

File D:\Code\python\spikeinterface\src\spikeinterface\core\channelslice.py:99, in ChannelSliceRecordingSegment.get_traces(self, start_frame, end_frame, channel_indices)
92 def get_traces(
93 self,
94 start_frame: int | None = None,
95 end_frame: int | None = None,
96 channel_indices: list | None = None,
97 ) -> np.ndarray:
98 parent_indices = self._parent_channel_indices[channel_indices]
---> 99 traces = self._parent_recording_segment.get_traces(start_frame, end_frame, parent_indices)
100 return traces

File D:\Code\python\spikeinterface\src\spikeinterface\extractors\neoextractors\neobaseextractor.py:351, in NeoRecordingSegment.get_traces(self, start_frame, end_frame, channel_indices)
345 def get_traces(
346 self,
347 start_frame: Union[int, None] = None,
348 end_frame: Union[int, None] = None,
349 channel_indices: Union[List, None] = None,
350 ) -> np.ndarray:
--> 351 raw_traces = self.neo_reader.get_analogsignal_chunk(
352 block_index=self.block_index,
353 seg_index=self.segment_index,
354 i_start=start_frame,
355 i_stop=end_frame,
356 stream_index=self.stream_index,
357 channel_indexes=channel_indices,
358 )
359 if self.inverted_gain:
360 raw_traces = -raw_traces

File C:\ProgramData\anaconda3\envs\si_env2\Lib\site-packages\neo\rawio\baserawio.py:805, in BaseRawIO.get_analogsignal_chunk(self, block_index, seg_index, i_start, i_stop, stream_index, channel_indexes, channel_names, channel_ids, prefer_slice)
802 if np.all(np.diff(channel_indexes) == 1):
803 channel_indexes = slice(channel_indexes[0], channel_indexes[-1] + 1)
--> 805 raw_chunk = self._get_analogsignal_chunk(block_index, seg_index, i_start, i_stop, stream_index, channel_indexes)
807 return raw_chunk

File C:\ProgramData\anaconda3\envs\si_env2\Lib\site-packages\neo\rawio\biocamrawio.py:127, in BiocamRawIO._get_analogsignal_chunk(self, block_index, seg_index, i_start, i_stop, stream_index, channel_indexes)
125 if channel_indexes is None:
126 channel_indexes = slice(None)
--> 127 data = self._read_function(self._filehandle, i_start, i_stop, self._num_channels)
128 return data[:, channel_indexes]

File C:\ProgramData\anaconda3\envs\si_env2\Lib\site-packages\neo\rawio\biocamrawio.py:253, in readHDF5t_brw4(rf, t0, t1, nch)
251 for key in rf:
252 if key[:5] == "Well_":
--> 253 return rf[key]["Raw"][nch * t0 : nch * t1].reshape((t1 - t0, nch), order="C")

File h5py\_objects.pyx:54, in h5py._objects.with_phil.wrapper()

File h5py\_objects.pyx:55, in h5py._objects.with_phil.wrapper()

File C:\ProgramData\anaconda3\envs\si_env2\Lib\site-packages\h5py_hl\dataset.py:758, in Dataset.getitem(self, args, new_dtype)
756 if self._fast_read_ok and (new_dtype is None):
757 try:
--> 758 return self._fast_reader.read(args)
759 except TypeError:
760 pass # Fall back to Python read pathway below

File h5py\_selector.pyx:368, in h5py._selector.Reader.read()

File h5py\_selector.pyx:342, in h5py._selector.Reader.make_array()

MemoryError: Unable to allocate 90.4 GiB for an array with shape (48546877440,) and data type uint16

Any help would be greatly appreciated!

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/spikeinterface/extractors/neoextractors/neobaseextractor.py and the Biocam path shown in neo/rawio/biocamrawio.py, especially readHDF5t_brw4. Run the provided single-channel get_traces reproduction against the 90.43 GiB recording and inspect how the full time range is read. Done means the full single-channel trace can be extracted without attempting a 90 GiB allocation.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.