Skip to content

Commit 9524b66

Browse files
authored
Update docs (#1095)
1 parent 1112203 commit 9524b66

9 files changed

Lines changed: 65 additions & 46 deletions

File tree

docs/source/best_practice.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ Best Practices
44
Avoid creating intermediate tensors
55
-----------------------------------
66

7-
For efficient and performant data processing, it is advised to not create
8-
an intermediate Tensor for each individual media object (such as single image),
9-
instead create a batch Tensor directly.
7+
For efficient and performant data processing, avoid creating intermediate Tensors
8+
for individual media objects (such as single images). Instead, create batch Tensors directly.
109

1110
We recommend decoding individual frames, then using :py:func:`spdl.io.convert_frames`
1211
to create a batch Tensor directly without creating an intermediate Tensors.
@@ -33,8 +32,8 @@ separately.
3332
return spdl.io.to_torch(buffer)
3433
3534
They can be combined in :py:class:`~spdl.pipeline.Pipeline`, which automatically
36-
discards the items failed to process (for example due to invalid data), and
37-
keep the batch size consistent by using other items successfully processed.
35+
discards items that fail to process (for example, due to invalid data) and
36+
maintains consistent batch size by using successfully processed items.
3837

3938
.. code-block::
4039
@@ -76,7 +75,7 @@ might look like the following.
7675
def __getitem__(self, key: int) -> tuple[Tensor, int]:
7776
...
7877
79-
We recommend to separate the source and process and make them additional
78+
We recommend to separate the source and processing and make them additional
8079
public interface.
8180
(Also, as described above, we recommend to not convert each item into
8281
``Tensor`` for the performance reasons.)

docs/source/faq.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Frequently Asked Questions
44
How to work around GIL?
55
-----------------------
66

7-
In Python, GIL (Global Interpreter Lock) practically prevents the use of multi-threading, however extension modules that are written in low-level languages, such as C, C++ and Rust, can release GIL when executing operations that do not interact with Python interpreter.
7+
In Python, the GIL (Global Interpreter Lock) practically prevents the use of multi-threading. However, extension modules written in low-level languages such as C, C++, and Rust can release the GIL when executing operations that do not interact with the Python interpreter.
88

99
Many libraries used for data loading release the GIL. To name a few;
1010

@@ -13,10 +13,9 @@ Many libraries used for data loading release the GIL. To name a few;
1313
- Decord
1414
- tiktoken
1515

16-
Typically, the bottleneck of model training in loading and pre-processing the media data.
17-
So even though there are still parts of pipelines that are constrained by GIL,
18-
by taking advantage of pre-processing functions that release GIL,
19-
we can achieve high throughput.
16+
Typically, the bottleneck in model training is loading and pre-processing media data.
17+
Even though some parts of pipelines are constrained by the GIL,
18+
we can achieve high throughput by using pre-processing functions that release the GIL.
2019

2120
What if a function does not release GIL?
2221
----------------------------------------
@@ -59,7 +58,7 @@ This will build pipeline like the following.
5958
``initializer`` and ``initargs`` arguments.
6059

6160
The values passed as ``initializer`` and ``initargs`` must be picklable.
62-
If constructing an object in a process that does not support picke, then
61+
If constructing an object in a process that does not support pickle, then
6362
you can pass constructor arguments instead and store the resulting object
6463
in global scope. See also https://stackoverflow.com/a/68783184/3670924.
6564

docs/source/getting_started/concurrency.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Concurrency
66
The pipelines we looked at so far process data sequentially.
77
Now let's introduce concurrency to the pipeline so that it finishes jobs faster.
88

9-
There are two parameters that affects the pipeline performance.
9+
There are two parameters that affect pipeline performance:
1010

1111
1. Stage concurrency
1212
2. Thread pool size
@@ -20,9 +20,8 @@ This argument determines at most how many operations of the stage the event loop
2020

2121
.. important::
2222

23-
Please note that **scheduling multiple tasks concurrently does not necessarily mean
24-
all of them are executed concurrently.** The execution of scheduled tasks is subject to
25-
the availability of resources required for the execution.
23+
Please note that **scheduling multiple tasks concurrently does not guarantee
24+
concurrent execution.** Task execution depends on the availability of required resources.
2625

2726
See the :ref:`Thread Pool Size<Thread Pool Size>` for the detail.
2827

docs/source/getting_started/intro.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Finally call :py:meth:`Pipeline.stop` to stop the background thread.
5454
5555
It is important to call :py:meth:`Pipeline.stop`.
5656
Forgetting to do so will leave the background thread running,
57-
leading to the situation where Python interpreter gets stuck at exit.
57+
which can cause the Python interpreter to hang at exit.
5858

5959
In practice, there is always a possibility that the application is
6060
interrupted for unexpected reasons.
@@ -81,8 +81,7 @@ To make sure that the pipeline is stopped, it is recommended to use
8181
-----------
8282

8383
Unlike processes, threads cannot be killed.
84-
The ``Pipeline`` object uses a thread pool, and it is important to
85-
shutdown the thread pool properly.
84+
The ``Pipeline`` object uses a thread pool, which must be shut down properly.
8685

8786
There are seemingly unharmful patterns, which can cause a deadlock
8887
at the end of the Python interpreter, preventing Python from exiting.
@@ -178,7 +177,7 @@ at the end of the Python interpreter, preventing Python from exiting.
178177
# 🚫 Do not keep the iterator object around
179178
ite = iter(dataloader)
180179
item = next(ite)
181-
# the won't be shutdown won't be shutdown until the `ite` variable
180+
# the pipeline won't be shutdown until the `ite` variable
182181
# goes out of scope. When does that happen??
183182
184183
The ``Pipeline.stop`` is not called until the garbage collector deletes

docs/source/getting_started/parallelism.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Pipeline Parallelism
55

66
.. currentmodule:: spdl.pipeline
77

8-
The :py:class:`Pipeline` supports multi-threading and multi-processing.
8+
The :py:class:`Pipeline` class supports multi-threading and multi-processing.
99
You can also use a ``Pipeline`` objects as source iterator of another ``Pipeline``.
1010
When experimenting, this flexibility makes it easy to switch multi-threading,
1111
multi-processing and mixtures of them.
@@ -87,8 +87,7 @@ There are cases where you want to use a dedicated thread for certain task.
8787
(caching for faster execution or storing the application context)
8888
#. You want to specify a different number of concurrency.
8989

90-
One notable example that comports with these conditions is transferring a
91-
data to the GPU.
90+
One notable example that meets these conditions is transferring data to the GPU.
9291
Due to the hardware constraints, only one data transfer can be performed
9392
at a time.
9493
To transfer data without interrupting the model training,

docs/source/getting_started/stages.rst

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Pipeline Stages
44
.. py:currentmodule:: spdl.pipeline
55
66
:py:class:`Pipeline` is composed of multiple stages.
7-
There are mainly three kind of stages.
7+
There are mainly three kinds of stages.
88

99
- Source
1010
- Processing
@@ -64,12 +64,11 @@ Processing
6464
Pre-processing is where a variety of operations are applied to the items passed
6565
from the previous stages.
6666

67-
You can define processing stage by passing an operator function (callable) to
68-
:py:meth:`~PipelineBuilder.pipe`. (Also there is :py:meth:`~PipelineBuilder.aggregate`
69-
and :py:meth:`~PipelineBuilder.disaggregate`, which can be used to stack/unstack
70-
multiple items.)
67+
You can define a processing stage by passing an operator function (callable) to
68+
:py:meth:`~PipelineBuilder.pipe`. You can also use :py:meth:`~PipelineBuilder.aggregate`
69+
and :py:meth:`~PipelineBuilder.disaggregate` to stack and unstack multiple items.
7170

72-
The operator can be either async function or synchronous function.
71+
The operator can be either an async function or a synchronous function.
7372
It must take exactly one argument†, which is an output from the earlier
7473
stage.
7574

@@ -136,6 +135,31 @@ and send the decoded frames to GPU asynchronously.
136135
Sink
137136
----
138137

139-
Sink is a buffer where the results of the pipeline is accumulated.
140-
A sink can be attached to pipeline with :py:meth:`PipelineBuilder.add_sink` method.
138+
Sink is a buffer where the results of the pipeline are accumulated.
139+
A sink can be attached to a pipeline with :py:meth:`PipelineBuilder.add_sink` method.
141140
You can specify how many items can be buffered in the sink.
141+
142+
Advanced: Merging Multiple Pipelines
143+
-------------------------------------
144+
145+
For more complex data loading scenarios, you can merge outputs from multiple independent
146+
pipelines using :py:class:`~spdl.pipeline.defs.MergeConfig`. This is useful when you need to:
147+
148+
- Combine data from different sources (e.g., multiple datasets or storage locations)
149+
- Process different types of data in parallel and merge them downstream
150+
- Build complex data loading patterns that go beyond linear pipeline structures
151+
152+
The :py:func:`~spdl.pipeline.defs.Merge` function creates a merge configuration that combines
153+
outputs from multiple :py:class:`~spdl.pipeline.defs.PipelineConfig` objects into a single stream.
154+
155+
.. note::
156+
157+
The merge mechanism is not supported by :py:class:`PipelineBuilder`. You need to use
158+
the lower-level :py:mod:`spdl.pipeline.defs` API and :py:func:`~spdl.pipeline.build_pipeline`
159+
function to build pipelines with merge nodes.
160+
161+
.. seealso::
162+
163+
:ref:`Example: Pipeline definitions <example-pipeline-definitions>`
164+
Demonstrates how to build a complex pipeline with merge nodes, including how to
165+
combine multiple data sources and process them through a unified pipeline.

docs/source/installation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The following command will build and install ``spdl`` Python package.
2525
.. note::
2626

2727
Make sure to use ``-v`` to see the log from the actual build process.
28-
The build front end by defaults hide the log of build process.
28+
The build front end by default hides the log of build process.
2929

3030
The build process first downloads/builds/installs some third-party
3131
dependencies, then it builds SPDL and its binding code.

docs/source/overview.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ What is SPDL?
66

77
SPDL (Scalable and Performant Data Loading) is a library for building
88
efficient data preprocessing pipeline, primarily aimed at ML/AI applications.
9-
It was created by a group of engineers/researchers who works on
9+
It was created by a group of engineers/researchers who work on
1010
improving the efficiency of GPU workloads at Meta.
1111

1212
Core Concept
@@ -16,39 +16,39 @@ Its design incorporates the authors' experience on optimizing AI training
1616
pipelines and the UX/DevX feedbacks from pipeline owners.
1717
The key features include
1818

19-
- The pipeline construction is intuitive.
20-
- The pipeline execution is fast and efficient.
21-
- The pipeline abstraction is flexible so that users can choose structures
22-
fit their environment/data/requirements.
19+
- Pipeline construction is intuitive
20+
- Pipeline execution is fast and efficient
21+
- Pipeline abstraction is flexible, allowing users to choose structures that
22+
fit their environment, data, and requirements
2323
- The pipeline can export the runtime statistics of subcomponents, which
2424
helps identify the bottleneck.
2525

26-
These features allow to create a feedback loop, with which users can
27-
iteratively improve the performance of the pipeline.
26+
These features enable a feedback loop that allows users to
27+
iteratively improve pipeline performance.
2828

2929
.. image:: ./_static/data/spdl_overview_feedback_loop.png
3030
:width: 480px
3131

3232
Performance & Efficiency
3333
~~~~~~~~~~~~~~~~~~~~~~~~
3434

35-
Data loading is an important component in AI training. It must be fast
36-
but also efficient because high CPU utilization can degrade
37-
the training performance (see :ref:`noisy-neighbour`).
35+
Data loading is a critical component of AI training. It must be both fast
36+
and efficient, as high CPU utilization can degrade training performance
37+
(see :ref:`noisy-neighbour`).
3838

3939
The following plots are from benchmarks we conducted as part of our
4040
study†.
4141

4242
.. image:: ./_static/data/spdl_overview_performance.png
4343

44-
The figure 5 and 6 show that SPDL if faster than other data loading
44+
The figure 5 and 6 show that SPDL is faster than other data loading
4545
solutions, while utilizing CPU more efficiently.
4646

4747
The pipeline abstraction by default uses multi-threading as the core
4848
parallelism.
4949
The performance of the pipeline is improved with the recent Python
5050
version upgrade, and enabling free-threading makes it even faster.
51-
Aoption of SPDL also paves the way for adoption of free-threaded
51+
Adoption of SPDL also paves the way for adoption of free-threaded
5252
Python in ML/AI application.
5353

5454
.. image:: ./_static/data/spdl_overview_speed_vs_version.png

examples/pipeline_definitions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def run_pipeline_example() -> list[int]:
229229

230230
_LG.info("Main pipeline config: %s", main_pipeline_config)
231231

232-
_LG.info("Builting the pipeline.")
232+
_LG.info("Building the pipeline.")
233233
pipeline = build_pipeline(main_pipeline_config, num_threads=4)
234234

235235
_LG.info("Executing the pipeline.")
@@ -242,7 +242,7 @@ def run_pipeline_example() -> list[int]:
242242

243243

244244
def run() -> None:
245-
"""Run example pipeline and check the resutl."""
245+
"""Run example pipeline and check the result."""
246246
results = run_pipeline_example()
247247

248248
_LG.info("Final results: %s", results)

0 commit comments

Comments
 (0)