Heavy-experiment loader flags¶
When your dataset is large, dense annotation arrays (bounding boxes, masks,
point clouds) can easily overflow RAM if they are all preloaded at startup.
Use the three array_* flags together with preload_labels=False to defer
all array materialisation until it is actually needed:
train_loader = wl.watch_or_edit(
train_dataset,
flag="data",
loader_name="train_loader",
batch_size=8,
shuffle=True,
is_training=True,
# Don't store the dense arrays (predictions and ground truth) in RAM;
# only keep their file paths with a small LRU cache for recent ones.
array_autoload_arrays=False,
array_return_proxies=True,
array_use_cache=True,
# Load labels on demand — don't scan every annotation at startup.
preload_labels=False,
)
What each flag does:
array_autoload_arrays=FalseAnnotation arrays written by signal calls are not read back into RAM during startup or ledger queries. Only their storage paths are kept in the dataframe. Use this whenever per-sample arrays are larger than ~1 MB or the dataset has more than a few thousand samples.
array_return_proxies=TrueReads of array columns return lazy
ArrayProxyobjects that load the underlying file only when.numpy()/.__array__()is called. Studio thumbnails and overlays trigger this load just-in-time, so only the arrays currently visible in the UI are in memory.array_use_cache=TrueRecently accessed arrays are kept in a small LRU cache. This is crucial when the studio repeatedly accesses the same samples (e.g. a zoomed-in view of 20 images), avoiding redundant disk reads.
preload_labels=FalseLabels (bounding boxes, masks, class IDs) are read inside
__getitem__on demand rather than scanned for all samples at init. Use this for datasets where label parsing is expensive or where not all samples will be visited in a single run.
Note
For light experiments (small datasets, fast iteration), you can skip these flags. The default behaviour (preloaded, in-memory) is simpler and has lower per-batch latency.
Implementing get_items in your dataset class¶
WeightsLab occasionally needs to access a sample’s metadata or label without
loading the full image (e.g. computing class weights, building a histogram of
annotation counts). Implement get_items with optional loading of each
component so callers can request only what they need:
class MyDataset(Dataset):
...
def get_items(self, idx,
include_metadata=False,
include_labels=False,
include_images=False):
img_path = self.images[idx]
mask_path = self.masks[idx]
uid = os.path.splitext(os.path.basename(img_path))[0]
metadata = None
if include_metadata:
metadata = {
"img_path": img_path,
"mask_path": mask_path,
}
img_t = None
if include_images:
img = Image.open(img_path).convert("RGB")
img_t = self.image_transform(img)
target = None
if include_labels:
target = self._load_boxes(mask_path)
return img_t, uid, target, metadata
Why this matters: without get_items, any WeightsLab utility that
scans annotations (class-weight computation, distribution analysis, label
preloading) is forced to run the full __getitem__ pipeline — including
image decode, resize, and augmentation — even though it only needs the label.
On a large dataset this can cost minutes at startup.
Warning
When include_images and include_labels are requested in separate
get_items calls (as in the pattern below), any random augmentation
(random crop, flip, etc.) must not be re-sampled independently on each
call — otherwise the transform applied to the image and the transform
applied to its annotations will diverge, silently misaligning boxes/masks
with the image they describe. Derive the augmentation deterministically
per sample (e.g. a seed keyed by uid/idx), or sample it once and
cache it — for instance in metadata — so every subsequent
get_items call for that sample reuses the same transform instead of
drawing a new random one.
Usage pattern:
# Compute class weights without loading any images
for idx in range(len(train_dataset)):
_, uid, target, _ = train_dataset.get_items(idx, include_labels=True)
count_annotations(target)
# Load a thumbnail for the studio without re-running augmentation
img_t, uid, _, _ = train_dataset.get_items(idx, include_images=True)
The standard return order is (image, uid, target, metadata), mirroring
what the DataSampleTrackingWrapper yields from __iter__.