Out of Memory when using Streaming Dataloader
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.6k
- Forks
- 206
- PR merge metrics
- No merged PRs in 30d
Description
Environment
- OS: Ubuntu 22.04
To reproduce
Steps to reproduce the behavior:
When using the StreamingDataloader (or the vanilla pytorch Dataloader) with num_workers>0, the processes slowly take more and more memory until the CPU RAM is filled.
Expected behavior
The dataloader should be able to provide samples indefinitely without using a significant portion of available RAM.
Additional context
Below is the dataset and dataloader implementation. Each sample is roughly 10 MB. With 16 workers, a prefetch factor of 4, and a batch size of 32, the total memory usage should be, at max, 20 GB. The dataset is made up of around 1.3 million shards.
A similar problem seems to be documented in an issue and a blog post. I have recreated the graphs found in the blog post below.
class ImageTokenDataset(StreamingDataset):
def __init__(
self,
remote: str,
batch_size: int,
shuffle: bool = False,
local: str | None = None,
split: str | None = None,
transforms: T.Compose = T.Compose([T.ToImage(), T.ToDtype(torch.float32)]),
input_key: str = "jpg",
cond_key: str = "cond",
cond_dropout_rate: float = 0.5,
predownload: int | None = None,
**kwargs,
) -> None:
super().__init__(
local=local,
remote=remote,
shuffle=shuffle,
batch_size=batch_size,
split=split,
predownload=predownload,
**kwargs,
)
self.batch_size = batch_size
self.transforms = transforms
self.input_key = input_key
self.cond_key = cond_key
self.cond_dropout_rate = cond_dropout_rate
def __getitem__(self, at: int) -> Sample:
obj = super().__getitem__(at)
_input = self.transforms(obj[self.input_key])
cond = torch.tensor(obj[self.cond_key])
if torch.rand(1) < self.cond_dropout_rate:
cond = torch.zeros_like(cond)
return inputs, cond
def to_dataloader(
num_workers: int = 8,
prefetch_factor: int | None = None,
persistent_workers: bool = True,
pin_memory: bool = True,
drop_last: bool = True,
batch_size: int | None = None,
):
return StreamingDataLoader(
self,
batch_size=batch_size or self.batch_size,
drop_last=drop_last,
prefetch_factor=prefetch_factor,
num_workers=num_workers,
persistent_workers=persistent_workers,
pin_memory=pin_memory,
)
if __name__ == "__main__":
dataset = ImageTokenDataset(
remote=remote_path,
batch_size=32
local="/tmp/dataset/train",
split="train",
input_key="jpg",
cond_key="t5",
cond_dropout_rate=0.5,
)
dataloader = dataset.to_dataloader(
num_workers=16, persistent_workers=True, pin_memory=False, prefetch_factor=4
)
for _ in tqdm(dataloader):
pass
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the StreamingDataset and StreamingDataLoader entry points and reproduce the example with multiple workers, prefetching, and persistent workers. Compare memory usage over time against a vanilla PyTorch DataLoader and inspect the linked PyTorch issue and blog for relevant multiprocessing behavior. Done means indefinite iteration no longer causes unbounded RAM growth under the reported configuration, with a regression test or documented reproduction result.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- data, machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100