Releases: facebookresearch/spdl
v0.3.0
SPDL v0.3.0 Release Notes
Highlights
Polymorphic Aggregate API — The pipeline's aggregation stage now supports custom aggregation logic via the new Aggregator abstract base class. Subclass Aggregator and implement accumulate() / flush() methods for custom batching strategies (e.g., size-based batching, time-windowed aggregation, conditional grouping).
The built-in Collate class provides the previous fixed-size batching behavior. (#1289, #1291)
Streaming decoding now returns Iterators — Streaming decode methods (streaming_decode_packets and flush methods of AudioDecoder and VideoDecoder) now return proper Python iterators instead
of Optional[Frames]. This makes the interface more Pythonic and naturally handles cases where feeding packets or flushing produces multiple batches of frames. (#1280)
Fraction-based failure rate thresholds — Pipeline stages now support Fraction-based failure thresholds (e.g., Fraction(1, 10) for 10% max failure rate) in addition to absolute integer counts. (#1296)
BC-Breaking Changes
- Streaming decoding returns
Iteratorinstead ofOptional[Frames](#1280):Decoder.streaming_decode_packets()andDecoder.flush()now return iterator objects.
Code that checked return values forNonemust migrate to iteration (for frames in decoder.streaming_decode_packets(packets)).ImageDecoderhas been removed as a public class. TaskHook.task_hook()signature changed (#1287): Thetask_hook()method now accepts aninput_itemparameter, allowing hooks to inspect which input item caused a failure. All existingTaskHooksubclasses must update their signature fromasync def task_hook(self)toasync def task_hook(self, input_item=None).AggregateConfignow requires op parameter (#1291):AggregateConfigno longer acceptsnum_itemsdirectly. Migrate fromAggregateConfig(..., num_items=N, ...)toAggregateConfig(..., op=Collate(N), ...), or use the convenience functionAggregate(N).
New Features
- Add polymorphic Aggregate API with Aggregator base class and Collate built-in implementation (#1289)
- Add
set_buffer_size()forVideoDecoderto control the number of frames yielded per iteration during streaming decode (#1284) - Add GNU/PAX long filename extension support to
iter_tar, enabling correct handling of archives with filenames exceeding the 100-byte TAR limit
(#1283) - Add Fraction-based failure rate threshold support for pipeline stages (#1296)
- Add p90 and p99 percentile tracking to pipeline performance stats (#1306)
Bug Fixes
- Fix off-by-one error in
max_failuresthreshold check —max_failures=Nnow correctly allows N failures before stopping (#1297) - Fix symbol resolution for removed
ImageDecoderin__init__.py(#1292) - Fix implicit string concatenation issues (#1275)
Other Changes
- Extract duplicated failure error raising logic into
_FailCounter.raise_for_failures()(#1303) - Remove unused Python imports (#1282)
- Add defaults for
python_versionandfree_threadedfields in benchmark utilities (#1286)
Documentation
v0.2.0
BC-breaking Changes
What's Changed
- [io] Update the annotation of the high-level functions by @mthrok in #1247
- [io] Warn only once about the fraction reduction by @mthrok in #1238
- [io] Transfer only CPU tensors by @mthrok in #1254
Performance Improvements
New Features
- [io] Allow passing name to demuxer by @mthrok in #1245
- [io] Add
parse_wavfunction for WAV header metadata extraction by @mthrok in #1242 - [io] Add compact log mode by @mthrok in #1248
BC-breaking changes
- [io] Default to per-thread default stream by @mthrok in #1255
When a CUDA stream is not specified, the CUDA-related IO functions defaulted to use the legacy default stream. Since SPDL IOs are intended for data loading happening outside of model computation, this has been changed to par-thread default stream. This allows to execute CUDA kernels without interrupting the legacy default stream by default. - [libspdl/io] Use batch allocation in NVDEC decoder by @mthrok in #1271
Previously, the CUDA frame was allocated par each decoded frame. This turned out to be inefficient (See #1260) therefore the NVDEC decoder has been rewritten to pre-allocate a buffer for a batch of frames. To accommodate this change, the interface of streaming GPU decoding has been changed. The APIs for one-off decoding and streaming decoding were split. The new implementation process media by the number of fixed frames par API call. - [libspdl/IO] Update NV12 color conversion function by @mthrok in #1269, #1272
Following the change in NVDEC decoder, the function for converting NV12 frames in CUDA memory is updated. The input format has been changed from list of single CUDA frames to a batched CUDA frames.
Bug fixes
- [io] Handle RASL frames on best-effort basis by @mthrok in #1236
- [io] Fix Decoder caching mechanism by @mthrok in #1241
- [io] Use the specified CU stream in CUDA functions by @mthrok in #1256
- [libspdl] Fix Generator move implementation by @mthrok in #1262
Documentation updates
- Add documentation to libspdl public APIs by @moto-meta in #1237
- Fix docstring by @mthrok in #1239
- Fix docstring by @mthrok in #1243
- Update docstring by @mthrok in #1249
- Rewrite and migrate packets/frames lifecycle docs by @mthrok in #1250
Other changes
- [libspdl] Optimize batched NV12 color conversion by @mthrok in #1267
- [libspdl] Refactor implementation of NvDecDecoderCore by @mthrok in #1259
- [libspdl] Refactor NVDEC decoder impl by @mthrok in #1261
- [libspdl] Tweak Generator impl by @mthrok in #1263
- [libspdl] Add C++ iterator support to Generator by @mthrok in #1264
- [libspdl] Remove StreamingDemuxer wrapper by @mthrok in #1265
- [libspdl] Fix conditional operator argument copy in decoder by @mthrok in #1270
- [libspdl] Encapsulate frame buffer in NVDEC by @mthrok in #1268
Full Changelog: v0.1.7...v0.2.0
v0.1.7
SPDL v0.1.7 Release Notes
New major features
-
Sub-interpreter support for pipelines & iteration
-
Rational handling for demuxing/decoding
- Support fractional timestamps for media demuxing, allowing to avoid rounding error when passing timestamp as float.
PR: #1194
- Support fractional timestamps for media demuxing, allowing to avoid rounding error when passing timestamp as float.
-
Pipeline builder enhancements
-
Add a build callback hook to pipeline building.
PR: #1162, #1215, #1208, #1207Combining the
locate_sourcebellow, this allows to log the source of the pipeline being built. This is useful for large teams/organizations where multiple teams may be using SPDL, and can help to identify the source code of a pipeline when debugging its performance.
-
-
New utilities
- Add utility
locate_sourceto locate the source of Python objects and include source location inPipelineConfig.__repr__, improving debuggability.
PRs: #1156, #1160 - Add benchmark and example for exploring video decoder thread configuration, including doc integration and a result image.
PRs: #1196, #1199, #1203
- Add utility
Improvements
-
Type system & interface files
-
Improved timestamp & rational handling for demuxing/decoding
- Refactor rational handling and timestamp handling across demux/decoder paths (including
Framesobjects) for correctness and consistency.
PRs:
- Refactor rational handling and timestamp handling across demux/decoder paths (including
-
Gateway API / C++ integration changes
- Make the gateway API mechanism dynamic, allowing more flexible interaction with C++ classes.
PR: #1145 - Remove Python wrappers for low-level C++ encoder/decoder and filter components (now accessed via the standardized gateway).
PRs:
- Make the gateway API mechanism dynamic, allowing more flexible interaction with C++ classes.
Bug fixes
-
GPU / NVDEC video decoding
-
CUDA / memory
- Fix race condition in
CUDACachingAllocator.
PR: #1082
- Fix race condition in
-
Timestamps & demuxing
- Fix integer overflow when converting PTS to rational type (part of the broader timestamp refactor).
PR: #1185 - Use stream time base for seeking to avoid incorrect seek positions.
PR: #1152 - Fix timestamps returned from
Framesobjects.
PR: #1192 - Add tests to cover timestamped demuxing and decode windows.
PRs: #1154, #1221
- Fix integer overflow when converting PTS to rational type (part of the broader timestamp refactor).
-
I/O, filters and frames
-
Subprocess / pipeline / utilities
- Make subprocess tests more robust.
PR: #1090 - Ensure pipeline global ID is inherited correctly in subprocesses.
PR: #1091 - Fix GC warning tests and improve cleanup behavior; generalize cleanup and ensure upstream pipelines are properly cleaned up.
PRs: #1097, #1207, #1208 - Fix the case where
locate_sourcecould hang.
PR: #1216 - Ensure pipeline global IDs are correctly inherited in subprocesses.
PR: #1091
- Make subprocess tests more robust.
-
Type checking / stubs
-
OSS & packaging
BC-breaking changes
-
Removal of deprecated API
- Remove deprecated
Demuxer.streaming_demux_video.
PR: #1140
- Remove deprecated
-
Removal of compatibility arguments and methods
- Remove various compatibility arguments and methods that had been kept for backward compatibility.
PR: #1225
- Remove various compatibility arguments and methods that had been kept for backward compatibility.
Documentation updates
-
New and expanded docs on I/O
-
GPU video decoder / encoding docs
- Add documentation for GPU video decoder (NVDEC).
PR: [#1107](https://github.com/faceb...
- Add documentation for GPU video decoder (NVDEC).
v0.1.6
What's New
- Support custom merge operation by @mthrok, @moto-meta in #1012, #1047, #1045
Please check the documentation for usage https://facebookresearch.github.io/spdl/main/generated/spdl.pipeline.defs.Merge.html#spdl.pipeline.defs.Merge - Introduce config system to change default queue/hook/callbacks by @moto-meta in #1018, #1042, #1033
This allows to change the default Queue/TaskHook/ProfileHook so that teams/projects can use a standard one. This is particularly helpful to log the performance across organization without manually configuring it for each pipeline. https://facebookresearch.github.io/spdl/main/generated/spdl.pipeline.config.html
Bugfix
- Fix the return values of ordered pipe by @mthrok in #1024 (Thanks @EthanRosenthal for reporting #1023)
- Fix type annotation by @mthrok in #1062
What's Changed
- Remove type parameter from
AsyncQueueby @mthrok in #1021 - Removes source annotation from
PipelineConfigby @moto-meta in #1043 - Update Pipeline Queue annotation by @mthrok in #1025
- Throw if no input in profiling by @moto-meta in #1038
- Use
weakref.finalizeto clean up the Pipeline by @moto-meta in #1039
Examples
- Update benchmark scripts to save result to CSV by @moto-meta and @mthrok in #1017, #1019
Packaging
- Add missing 3.13t to Linux
aarch64build by @mthrok in #1014 - Lower to
manylinux_2_26foraarch64by @mthrok in #1015
Documentation Update
Internal / Refactor
- Move the type alias of callable to
defsby @mthrok in #1004 - Refactor 1 - Move queue and hook by @moto-meta in #1026
- Refactor 2 - Move node by @moto-meta in #1027
- Refactor 3 - Build logic by @moto-meta in #1031
- Refactor 4 - Make agg and disagg specialized config by @moto-meta in #1028
- Refactor 5 - Add _cmponents/init.py by @moto-meta in #1029
- Refactor 6 - Use defs/init.py by @moto-meta in #1032
- Refactor 7 - Refactor utilities by @moto-meta in #1030
- Update import path by @moto-meta in #1037
- Remove
op_require_eoffrom _PipeArgs by @moto-meta in #1040 - Set
pyre-strictin _node.py by @moto-meta in #1046 - Migrate pipeline_profiling_test to Python unittest by @moto-meta in #1044
- Migrate configs_test.py from pytest to unittest by @vbourgin in #1057
- Migrate video_frame_slice_test.py from pytest to unittest by @vbourgin in #1053
- Migrate zero_copy_bytes_passing_test.py from pytest to unittest by @vbourgin in #1050
- Migrate video_encoding_test.py from pytest to unittest by @vbourgin in #1049
- Migrate frames_test.py from pytest to unittest by @vbourgin in #1058
- Migrate audio_decoding_test.py from pytest to unittest by @vbourgin in #1055
- Migrate tar_test.py from pytest to unittest by @vbourgin in #1056
- Migrate demuxer_test.py from pytest to unittest by @vbourgin in #1052
- Migrate image_decoding_test.py from pytest to unittest by @vbourgin in #1048
- Migrate async_test.py from pytest to unittest by @vbourgin in #1051
- Migrate audio_encoding_test.py from pytest to unittest by @vbourgin in #1054
- Migrate buffer_conversion_refcount_test.py from pytest to unittest by @vbourgin in #1059
- Migrate streaming_decoding_test.py from pytest to unittest by @vbourgin in #1066
Full Changelog: v0.1.5...v0.1.6
v0.1.5
What's new
New Python version support
The spdl-io packages now include binaries for Python 3.13t, 3.14 and 3.14t on all supported platforms (macOS, Linux aarch64, Linux x86_64 and Windows).
They are now compiled with CUDA 12.8.1.
(spdl-core remains pure Python package without any dependency.)
Pipeline profiling and self-diagnostic mode
Pipeline profiling function
The spdl.pipeline.profile_pipeline function is added.
This function executes each stage separately with different multi-threading concurrency and reports the speed of executions. This helps find how each stage function scales with multi-threading.
Please check out the example for the usage and what you can infer from the profiling result.
Self-diagnostic mode
By setting environment variable SPDL_PIPELINE_DIAGNOSTIC_MODE=1, the Pipeline is built with self-diagnostic mode.
In this mode, internally it calls the profile_pipeline and exit.
This helps profiling the pipeline in production environment without changing the code.
(contributed by @ncorriveau and @mthrok)
Support for sub-pipelines
A new pipeline definition component, spdl.pipeline.defs.MergeConfig and its factory function spdl.pipeline.defs.Merge
have been added.
This allows to merge multiple pipelines and attach downstream stages.
Please check out the example for the usage.
spdl.io.load_wav for loading WAV from memory without copy
The spdl.io.load_wav function is added. This function is specialized for loading WAV audio from memory. It does not make any copy, so it is very fast. Please refer to the benchmark.
spdl.io.iter_tarfile for iterating TAR files
The spdl.io.iter_tarfile function is added. This function can iterate on TAR file in memory or file-like object. It is at least as fast as Python's built-in tarfile module. If the input is bytes type, then it can perform zero-copy parsing. (Proposed by @nicolas-dufour, @npuichigo [discussion])
Updates on failure monitoring mechanism
- You can now overwrite the
max_failuresat each stage. (Proposed by @EthanRosenthal #942)
Pass max_failures to spdl.pipeline.PipelineBuilder.pipe method, or spdl.pipeline.defs.Pipe function.
- Fix the way failed stages are reported (#1006)
When a pipeline stage fails more than it is allowed, the pipeline fails with error message. Previously all the stages were included in the message. Now, only the stages that actually failed are included.
What's Changed
-
zlib is statically linked in Linux/macOS binaries
Previously, thespdl_iopackages required an external installation ofzlibfor Linux and macOS, while it was statically linked in Windows packages. Nowzlibis also statically linked in Linux/macOS, making NumPy the only required dependency ofspdl-io,
New Contributors
- @ncorriveau made their first contribution in #957
Full Changelog: v0.1.4...v0.1.5
v0.1.4
New features
Config-based Pipeline constructions.
The newly introduced spdl.pipeline.defs module contains the definitions and helper functions you can use to build Pipeline object with declarative manner. For the detail, please refer to #902
You can now construct Pipeline in the following ways. Also please checkout the Hydra Integration Example.
| PipelineBuilder (existing) | PipelineDefinition (new) | Hydra |
builder = (
PipelineBuilder()
.add_source(Sampler())
.pipe(
funcA,
concurrency=...)
.pipe(
funcB,
concurrency=...,
executor=...)
.sink(...)
)
pipeline = builder.build(
num_threads=...) |
pdef = PipelineConfig(
src=Sampler(),
stages=[
PipeConfig(
funcA,
concurrency=...),
PipeConfig(
funcB,
concurrency=...,
executor=...),
],
sink=...
)
pipeline = build_pipeline(
pdef, num_threads=...) |
_target_: build_pipeline
num_threads: ...
definition:
_target_: PipelineConfig
src:
_target_: Sampler
stages:
- _target_: PipeConfig:
op: funcA
concurrency: ...
- _target_: PipeConfig:
op: funcB
concurrency: ...
executor: ...
sink:
... |
[Experimental] Windows Support
SPDL I/O now supports building on Windows. The binary distribution contains CUDA integration and NVDEC support.
Logging change
Previously, if a function passed to a pipe fails, the error was logged in one line. Now the full stack trace is printed.
Bug fix
What's Changed
v0.1.3
New features
- Support clases with
__getitem__method in pipe by @mthrok in #872 - Add VideoPackets.get_timestamps method by @mthrok in #875
- Add VideoFrames::get_timestamp method by @mthrok in #877
- Add VideoFrames.get_pts / time_base attributes to VideoFrames by @mthrok in #883
- Add support for FFmpeg 8 #869
Bug fix
- Fix the handling of StopAsyncIterator for FailCounter by @moto-meta in #862
- Fix include by @mthrok in #874
- Correctly detect that callable is a generator when it is a class's call method by @yit-b in #870
- Fix type stub by @mthrok in #884
What's Changed
- Update imagenet example by @mthrok in #860
- Add debug print for pipeline structure by @mthrok in #868
- Define a dedicated type alias for pipe input by @mthrok in #885
Full Changelog: v0.1.2...v0.1.3
v0.1.2
New features
- Support
__len__for SPDL dataloader by @vbourgin in #839 - Add
SizedIterable[WithShuffle]protocol by @mthrok in #840 - Move DistributedSampler to SPDL core by @vbourgin in #841
- Move
load_npyto C++ by @mthrok in #849 - Use libdeflate for loading compressed NumPy Z file. by @mthrok in #855
- Add
transfer_tensorfunction by @mthrok in #853
What's Changed
- Release the GIL when flushing decoder by @mthrok in #828
- Fix
embed_shuffleby @moto-meta in #857
Documentation updates
BC-breaking changes
Full Changelog: v0.1.1...v0.1.2
v0.1.1
BC-breaking changes
-
Replace
run_pipeline_in_subprocessimpl by @moto-meta in #780Previously
run_pipeline_in_subprocessreturned an iterator and was not reusable.
Now it returns an iterable, which can be iterated multiple times.
Following this change, the object returned fromrun_pipeline_in_subprocessdoes not provide iterator-specific method such asnextExample
# Construct a builder builder = ( spdl.pipeline.PipelineBuilder() .add_source(...) .pipe(...) ... .add_sink(...) ) # Move it to the subprocess, build the Pipeline iterable = run_pipeline_in_subprocess(builder, ...) # Iterate - epoch 0 for item in iterable: ... # Iterate - epoch 1 for item in iterable: ...
What's Changed
- Support multiple initializers in
iterate_in_subprocessandrun_pipeline_insubprocessby @mthrok in #783
Now you can pass multiple initializer functions toiterate_in_subprocessandrun_pipeline_insubprocesswhich are called in the subprocess before the first iteration starts. - Allow Zero Weights in MergeIterator by @vbourgin in #784
Previously, theMergeIteratordid not allow 0 value as weights. Now this is relaxed and you can pass 0.
The iterators with 0 weight are not iterated. - Shuffle Before Iterating by Default for
embed_shuffleby @vbourgin in #785
Previously,embed_shuffledefaulted to shuffle after each iteration, but this was counter-intuitive.
Now the default behavior is to shuffle before each iteration. - Adhere to PEP 561 (Fixes a mypy bug) by @alxmrs in #790
Now SPDL package containpy.typedfile so that type-checkers can analyze the code. - Ensure core bindings is loaded when loading CUDA binding by @mthrok in #792
When loading CUDA extension inspdl.iomodule, it ensures that the CPU extension is loaded. - Support batch loading images with NVJPEG by @mthrok in #794
Thespdl.io.decode_image_nvjpegfunction supports loading multiple images. (Note that the function is still experimental.) - Enable compilation warnings by @mthrok in #806, #821
The C++ code ofspdl.iois hardened by turning few selected compiler warnings into error. - Fix nanobind option for archive module by @mthrok in #814
The extension module for archive (zip) parsing was not compiled with free-threading support. - Mypy type-checking feedback for all "pyre safe" sources. by @alxmrs in #801
Now CImypytype checking. Themypycompatibility is not enforced at the moment aspyrehas been (and still is) used. We plan to gradually make the codebase compatible withmypy.
New Contributors
Full Changelog: v0.1.0...v0.1.1
v0.1.0
What's Changed
- [BC-breaking] Replace load_npz implementation by @mthrok in #739
- [BC-breaking] Remove fallback for API transition by @mthrok in #770
- [BC-breaking] Replace iterate_in_subprocess implementation by #776 @mthrok in #779
- Add support for DEFLATE algorithm by @mthrok in #744
- Name threads by @mthrok in #728
- Update
load_npyto accept memoryview by @mthrok in #738 - Remove libzip dependency by @mthrok in #746
- Default to the default context by @mthrok in #762
- Revise the way periodic task is terminated by @mthrok in #768
- Add the funtionality to suppress repeated errors in spdl by @gregorpm in #773
- Add function to convert IterableWithShuffle to Iterable by @mthrok in #775, #777
Examples
Docs
- Add section on data format by @mthrok in #729
- Introduce Case Studies by @mthrok in #731, #741, #754, #755
- Add caveats and update links by @mthrok in #752, #751
Full Changelog: v0.0.14...v0.1.0