fix(streaming): copy deserialized numpy arrays so they are writable - #887
Merged
tchaton merged 1 commit intoAug 18, 2026
Merged
Conversation
np.frombuffer returns a read-only view over its input, so arrays from NumpySerializer and NoHeaderNumpySerializer were non-writable and made torch.from_numpy warn on every collate. On the PyTreeLoader fast path the input is a memoryview over a live mmap, so the array also aliased a chunk mapping that can be unmapped under cache pressure. Copy on deserialize, matching the idiom TokensLoader already uses in item_loader.py. Fixes Lightning-AI#818
hdimer
marked this pull request as ready for review
August 18, 2026 13:34
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #887 +/- ##
=====================================
- Coverage 82% 82% -0%
=====================================
Files 65 65
Lines 13377 13377
=====================================
- Hits 10956 10949 -7
- Misses 2421 2428 +7 🚀 New features to boost your workflow:
|
tchaton
approved these changes
Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #818.
NumpySerializer.deserializeandNoHeaderNumpySerializer.deserializereturnnp.frombuffer(...)directly.np.frombufferwraps its input as a read-only view, so every numpy array coming out of aStreamingDatasetis non-writable and the default collate'storch.from_numpywarns on it:The warning is the visible symptom, but the view is the bigger problem. On the
PyTreeLoaderfast path,_slice_item_bytesreturns amemoryviewover a livemmap.ACCESS_READmapping and passes it straight to the serializer, so the returned array aliases a mapped chunk file that_close_mapping/_evict_mapped_chunkscan unmap under LRU pressure. That's the same hazardTokensLoaderalready guards against, with the same idiom, initem_loader.py:So this just applies that existing pattern to the two numpy serializers.
Cost
One extra
memcpyper numpy field per item: ~1 µs for a 3 KB embedding or CIFAR-sized image, ~240 µs for a 3 MB array. On the non-mmap path the slice of the sourcebytesalready costs about the same, so for those callers it is roughly a doubling of an existing copy rather than a new one.setflags(write=True)isn't an option — numpy refuses it on a bytes-backed array — andfrombuffer(bytearray(...))costs the identical copy.Scope
Only the two numpy deserializers change. I left the torch serializers and the
warnings.filterwarnings("ignore", message=".*The given buffer is not writable.*")inreader.pyalone: that one targetstorch.frombuffer's different "given buffer is not writable" message and looks deliberate, and it never covered the numpy warning in #818. Happy to follow up if you'd like the tensor path to match.While in here I noticed
if tensor.shape == shapeinNumpySerializer.deserializecompares a tuple against a list, so it is alwaysFalseand thenp.reshapepath always runs. Harmless, and left alone to keep this diff to the reported bug. The.copy()sits before that branch, so it holds either way.Tests
Added a
flags.writeableassertion to the two existing numpy serializer tests rather than a new test:test_numpy_serializeralready loops over every supported dtype and five shapes, so it pins writability across all of them, and keeping the two serializers in separate tests means a failure says which one broke. Both assertions fail onmainand pass here.test_serializer.py,test_item_loader.pyandtest_reader.pyare green locally (72 passed, 4 skipped), as areruff,ruff format,codespellandmypy. I also ran the reporter's reproducer from #818 end to end: the warning fires onmainand is gone with this change.I used an AI assistant while working on this. I reproduced the bug, verified the tests fail without the fix, and reviewed the change myself.
Used AI assistance on this; I reviewed and tested the change myself.