From 6cf0535233569a01e6d24391204cd51144acc5b2 Mon Sep 17 00:00:00 2001 From: Felix Fischer Date: Thu, 18 Sep 2025 11:43:47 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20Added=20speed=20comparision?= =?UTF-8?q?=20to=20other=20loaders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 45 ++++++++++++++++++++--------- docs/_static/speed_comparision.png | Bin 0 -> 19173 bytes 2 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 docs/_static/speed_comparision.png diff --git a/README.md b/README.md index e3d03c2..f6a0f76 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # arrayloaders > [!CAUTION] -> This pacakge does not have a stable API. However, we do not anticipate the on-disk format to change as it is simply an anndata file. +> This pacakge does not have a stable API. However, we do not anticipate the on-disk format to change as it is simply an +> anndata file. [![Tests][badge-tests]][tests] [![Documentation][badge-docs]][documentation] @@ -53,7 +54,7 @@ create_store_from_h5ads( "path/to/your/file1.h5ad", "path/to/your/file2.h5ad" ], - output_path="path/to/output/store", # a directory containing `chunk_{i}.zarr` + output_path="path/to/output/store", # a directory containing `chunk_{i}.zarr` shuffle=True, # shuffling is needed if you want to use chunked access ) ``` @@ -102,7 +103,8 @@ for batch in ds: ... ``` -For performance reasons, you should use our dataloader directly without wrapping it into a {class}`torch.utils.data.dataloader`. +For performance reasons, you should use our dataloader directly without wrapping it into a {class} +`torch.utils.data.dataloader`. Your code will work the same way as with a {class}`torch.utils.data.dataloader`, but you will get better performance. #### User configurable sampling strategy @@ -110,36 +112,53 @@ Your code will work the same way as with a {class}`torch.utils.data.dataloader`, At the moment we do not support user-configurable sampling strategies like weighting or sampling. With a pre-shuffled store and blocked access, your model fit should not be affected by using chunked access. -If you are interested in contributing this feature to the project or leaning more, please get in touch on [zulip](https://scverse.zulipchat.com/) or via the GitHub issues here. +If you are interested in contributing this feature to the project or leaning more, please get in touch +on [zulip](https://scverse.zulipchat.com/) or via the GitHub issues here. ## Speed comparison to other dataloaders -We provide a quickstart notebook that gives both some boilerplate code and provides a speed comparison to other comparable dataloaders: +We provide a speed comparison to other comparable dataloaders below. +Notably, our data loader comes with a significant speedup compared to other dataloaders: -TODO: figure and notebook +fit_time_vs_loading_speed + +We've run the above benchmark on an AWS `ml.m5.8xlarge` instance. +The code to reproduce the above results can be found on LaminHub: + +* [Benchmark results](https://lamin.ai/laminlabs/arrayloader-benchmarks/transform/e6Ry7noc4Y0d) +* [Arrayloaders code](https://lamin.ai/laminlabs/arrayloader-benchmarks/transform/yl0iTPhJjkqW) +* [MappedCollection code](https://lamin.ai/laminlabs/arrayloader-benchmarks/transform/YfzHfoomTkfu) +* [scDataset code](https://lamin.ai/laminlabs/arrayloader-benchmarks/transform/L6CAf9w0qdQj) ## Why data loading speed matters? -Most models for scRNA-seq data are pretty small in terms of model size compared to models in other domains like computer vision or natural language processing. +Most models for scRNA-seq data are pretty small in terms of model size compared to models in other domains like computer +vision or natural language processing. This size differential puts significantly more pressure on the data loading pipeline to fully utilize a modern GPU. Intuitively, if the model is small, doing the actual computation is relatively fast. Hence, to keep the GPU fully utilized, the data loading needs to be a lot faster. -As an illustrative, example let's train a logistic regression model ([notebook hosted on LaminHub](https://lamin.ai/laminlabs/arrayloader-benchmarks/transform/cV00NQStCAzA?filter%5Band%5D%5B0%5D%5Bor%5D%5B0%5D%5Bbranch.name%5D%5Beq%5D=main&filter%5Band%5D%5B1%5D%5Bor%5D%5B0%5D%5Bis_latest%5D%5Beq%5D=true)). -Our example model has 20.000 input features and 100 output classes. We can now look how the total fit time changes with data loading speed: +As an illustrative, example let's train a logistic regression +model ([notebook hosted on LaminHub](https://lamin.ai/laminlabs/arrayloader-benchmarks/transform/cV00NQStCAzA?filter%5Band%5D%5B0%5D%5Bor%5D%5B0%5D%5Bbranch.name%5D%5Beq%5D=main&filter%5Band%5D%5B1%5D%5Bor%5D%5B0%5D%5Bis_latest%5D%5Beq%5D=true)). +Our example model has 20.000 input features and 100 output classes. We can now look how the total fit time changes with +data loading speed: fit_time_vs_loading_speed -From the graph we can see that the fit time can be decreased substantially with faster data loading speeds (several orders of magnitude). -E.g. we are able to reduce the fit time from ~280s for a data loading speed of ~1000 samples/sec to ~1.5s for a data loading speed of ~1.000.000 samples/sec. +From the graph we can see that the fit time can be decreased substantially with faster data loading speeds (several +orders of magnitude). +E.g. we are able to reduce the fit time from ~280s for a data loading speed of ~1000 samples/sec to ~1.5s for a data +loading speed of ~1.000.000 samples/sec. This speedup is more than 100x and shows the significant impact data loading has on total training time. ## When would you use this data laoder? -As we just showed, data loading speed matters for small models (e.g., on the order of an scVI model, but perhaps not a "foundation model"). +As we just showed, data loading speed matters for small models (e.g., on the order of an scVI model, but perhaps not a " +foundation model"). But loading minibatches of bytes off disk will be almost certainly slower than loading them from an in-memory source. Thus, as a first step to assessing your needs, if your data fits in memory, load it into memory. -However, once you have too much data to fit into memory, for whatever reason, the data loading functionality offered here can provide significant speedups over state of the art out-of-core dataloaders. +However, once you have too much data to fit into memory, for whatever reason, the data loading functionality offered +here can provide significant speedups over state of the art out-of-core dataloaders. ## Release notes diff --git a/docs/_static/speed_comparision.png b/docs/_static/speed_comparision.png new file mode 100644 index 0000000000000000000000000000000000000000..36af3ff13a282a21f7ae78e03582e872500bada8 GIT binary patch literal 19173 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 Date: Sun, 21 Sep 2025 13:07:01 +0200 Subject: [PATCH 2/2] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6a0f76..af3c7d7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # arrayloaders > [!CAUTION] -> This pacakge does not have a stable API. However, we do not anticipate the on-disk format to change as it is simply an +> This package does not have a stable API. However, we do not anticipate the on-disk format to change as it is simply an > anndata file. [![Tests][badge-tests]][tests]