Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions dingo/core/utils/torchutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

def fix_random_seeds(_):
"""Utility function to set random seeds when using multiple workers for DataLoader."""
np.random.seed(int(torch.initial_seed()) % (2 ** 32 - 1))
np.random.seed(int(torch.initial_seed()) % (2**32 - 1))
try:
bilby.core.utils.random.seed(int(torch.initial_seed()) % (2 ** 32 - 1))
bilby.core.utils.random.seed(int(torch.initial_seed()) % (2**32 - 1))
except AttributeError: # In case using an old version of Bilby.
pass

Expand Down Expand Up @@ -190,7 +190,9 @@ def build_train_and_test_loaders(
dataset: torch.utils.data.Dataset,
train_fraction: float,
batch_size: int,
num_workers: int,
num_workers: int = 0,
pin_memory: bool = True,
prefetch_factor: int = 1,
):
"""
Split the dataset into train and test sets, and build corresponding DataLoaders.
Expand All @@ -204,6 +206,14 @@ def build_train_and_test_loaders(
Should lie between 0 and 1.
batch_size : int
num_workers : int
Number of workers. Default 0.
pin_memory : bool
If True, use pinned memory for faster GPU transfers. This increases memory
usage significantly (roughly 2x the prefetch buffer size) but can speed up
data transfer to GPU. Default is True.
prefetch_factor : int
Number of batches each worker prefetches. Higher values use more memory
but can improve throughput. Default is 1.

Returns
-------
Expand All @@ -215,22 +225,26 @@ def build_train_and_test_loaders(
dataset, train_fraction
)

# prefetch_factor is only valid when num_workers > 0
loader_kwargs = dict(
batch_size=batch_size,
pin_memory=pin_memory,
num_workers=num_workers,
worker_init_fn=fix_random_seeds,
)
if num_workers > 0:
loader_kwargs["prefetch_factor"] = prefetch_factor

# Build DataLoaders
train_loader = DataLoader(
train_dataset,
batch_size=batch_size,
shuffle=True,
Comment thread
annalena-k marked this conversation as resolved.
pin_memory=True,
num_workers=num_workers,
worker_init_fn=fix_random_seeds,
**loader_kwargs,
)
test_loader = DataLoader(
test_dataset,
batch_size=batch_size,
shuffle=False,
pin_memory=True,
num_workers=num_workers,
worker_init_fn=fix_random_seeds,
**loader_kwargs,
)

return train_loader, test_loader
Expand Down
18 changes: 12 additions & 6 deletions dingo/gw/training/train_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@


def copy_files_to_local(
file_path: str, local_dir: Optional[str], leave_keys_on_disk: bool, is_condor: bool = False,
file_path: str,
local_dir: Optional[str],
leave_keys_on_disk: bool,
is_condor: bool = False,
) -> str:
"""
Copy files to local node if local_dir is provided to minimize network traffic during training.
Expand Down Expand Up @@ -232,7 +235,7 @@ def initialize_stage(
pm: BasePosteriorModel,
wfd: WaveformDataset,
stage: dict,
num_workers: int,
local_settings: dict,
resume: bool = False,
):
"""
Expand All @@ -249,7 +252,8 @@ def initialize_stage(
wfd : WaveformDataset
stage : dict
Settings specific to current stage of training
num_workers : int
local_settings : dict
Local settings for training (num_workers, pin_memory, prefetch_factor, etc.)
resume : bool
Whether training is resuming mid-stage. This controls whether the optimizer and
scheduler should be re-initialized based on contents of stage dict.
Expand All @@ -269,7 +273,9 @@ def initialize_stage(
wfd,
train_settings["data"]["train_fraction"],
stage["batch_size"],
num_workers,
num_workers=local_settings.get("num_workers", 0),
pin_memory=local_settings.get("pin_memory", True),
prefetch_factor=local_settings.get("prefetch_factor", 1),
)

if not resume:
Expand Down Expand Up @@ -343,13 +349,13 @@ def train_stages(
print(f"\nBeginning training stage {n}. Settings:")
print(yaml.dump(stage, default_flow_style=False, sort_keys=False))
train_loader, test_loader = initialize_stage(
pm, wfd, stage, local_settings["num_workers"], resume=False
pm, wfd, stage, local_settings, resume=False
Comment thread
annalena-k marked this conversation as resolved.
)
else:
print(f"\nResuming training in stage {n}. Settings:")
print(yaml.dump(stage, default_flow_style=False, sort_keys=False))
train_loader, test_loader = initialize_stage(
pm, wfd, stage, local_settings["num_workers"], resume=True
pm, wfd, stage, local_settings, resume=True
)
early_stopping = None
if stage.get("early_stopping"):
Expand Down
8 changes: 8 additions & 0 deletions docs/source/training.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ local:
checkpoint_epochs: 10
leave_waveforms_on_disk: True
local_cache_path: tmp
# pin_memory: True
# prefetch_factor: 1
# condor:
# bid: 100
# num_cpus: 16
Expand Down Expand Up @@ -172,6 +174,12 @@ leave_waveforms_on_disk
local_cache_path
: When training on a cluster and loading waveforms during training (i.e., `leave_waveforms_on_disk=True`), the waveform dataset should be copied to the disk storage of the local node at the beginning of training. This prevents unexpected long data loading times during training due to network traffic. Usually, paths for local storage are `tmp` or `dev/shm`. When submitting the job with `condor`, `request_disk: 50GB` should be included in the `condor` settings with the requested disk space larger than the size of the waveform dataset used for training.

pin_memory
: If `True` (default), use pinned (page-locked) memory for faster CPU to GPU data transfers. This speeds up training by ~20% but increases memory usage. The memory overhead scales as `num_workers × prefetch_factor × batch_size × sample_size`, and is roughly doubled when using pinned memory (once for the worker prefetch queue, once for the pinned copy). Set to `False` if memory is constrained.

prefetch_factor
: Number of batches each DataLoader worker prefetches (default 1). Higher values can improve throughput by hiding data loading latency, but increase memory usage proportionally. In testing, `prefetch_factor=1` performs as well as `prefetch_factor=2` while using less memory.

condor
: Settings for [HTCondor](https://htcondor.readthedocs.io/en/latest/index.html). The condor script will (re)submit itself according to these options.

Expand Down
2 changes: 2 additions & 0 deletions examples/fmpe_model/train_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,5 @@ local:
max_epochs_per_run: 500
max_time_per_run: 360000
leave_waveforms_on_disk: True
# pin_memory: True # Set False to reduce memory usage, but slows down transfer of batches from CPU to GPU

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was testing this, it was confusing that this line is commented out.
As far as I understood, pin_memory=True by default, right?
Therefore, uncommenting this line actually does nothing. This is conceptually different from how we previously included comments in the example settings files, e.g. the early stopping is commented (disabled) and the user can uncomment it to enable it. Similar for local_cache_path. Defaults like leave_waveforms_on_disk: True are not commented.

I would recommend to stay consistent and not comment defaults to make it easy to understand for the user.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same applies to prefetch_factor and all example files.

# prefetch_factor: 1 # Number of batches each worker prefetches; higher uses more memory
2 changes: 2 additions & 0 deletions examples/gnpe_model/train_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ local:
max_epochs_per_run: 500
checkpoint_epochs: 10
leave_waveforms_on_disk: True
# pin_memory: True # Set False to reduce memory usage, but slows down transfer of batches from CPU to GPU
# prefetch_factor: 1 # Number of batches each worker prefetches; higher uses more memory
# local_cache_path: tmp # uncomment to avoid slow data loading during training due to network traffic on cluster
# Local settings related to condor, remove if not used on cluster
condor:
Expand Down
2 changes: 2 additions & 0 deletions examples/gnpe_model/train_settings_init.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ local:
max_epochs_per_run: 500
checkpoint_epochs: 10
leave_waveforms_on_disk: True
# pin_memory: True # Set False to reduce memory usage, but slows down transfer of batches from CPU to GPU
# prefetch_factor: 1 # Number of batches each worker prefetches; higher uses more memory
# local_cache_path: tmp # uncomment to avoid slow data loading during training due to network traffic on cluster
condor:
num_cpus: 16
Expand Down
2 changes: 2 additions & 0 deletions examples/npe_model/train_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ local:
max_epochs_per_run: 500
checkpoint_epochs: 50
leave_waveforms_on_disk: True
# pin_memory: True # Set False to reduce memory usage, but slows down transfer of batches from CPU to GPU
# prefetch_factor: 1 # Number of batches each worker prefetches; higher uses more memory
# local_cache_path: tmp # uncomment to avoid slow data loading during training due to network traffic on cluster
# Local settings related to condor, remove if not used on cluster
condor:
Expand Down
4 changes: 3 additions & 1 deletion examples/toy_npe_model/train_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ local:
runtime_limits:
max_time_per_run: 3600000
max_epochs_per_run: 30
checkpoint_epochs: 15
checkpoint_epochs: 15
Comment thread
annalena-k marked this conversation as resolved.
# pin_memory: True # Set False to reduce memory usage, but slows down transfer of batches from CPU to GPU
# prefetch_factor: 1 # Number of batches each worker prefetches; higher uses more memory