Buckets:

KaisResearch's picture
download
raw
4.26 kB
"""Unified dataset that merges any number of preprocessed clip roots
(e.g. LRS2-derived clips, LRS3-derived clips, your own recordings).
Every source uses the same on-disk layout, produced by scripts/prepare_data.py:
<root>/<WORD>/<split>/<clip_id>.npy # uint8 (T, H, W), 0..255
Because every source shares this layout, they combine transparently:
build_datasets() scans every root in cfg.data_roots, unions the word list
into a single label map, and returns train/val/test datasets drawn from all
of them.
"""
from __future__ import annotations
import glob
import json
import os
from typing import List, Tuple
import numpy as np
import torch
from torch.utils.data import Dataset
from src.transforms import ClipTransform
SPLITS = ("train", "val", "test")
def _scan_words(roots: List[str]) -> List[str]:
words = set()
for root in roots:
if not root or not os.path.isdir(root):
continue
for name in os.listdir(root):
if os.path.isdir(os.path.join(root, name)):
words.add(name)
return sorted(words)
def _collect(roots: List[str], split: str,
label_map: dict) -> List[Tuple[str, int]]:
items: List[Tuple[str, int]] = []
for root in roots:
if not root or not os.path.isdir(root):
continue
for word, label in label_map.items():
pattern = os.path.join(root, word, split, "*.npy")
for path in glob.glob(pattern):
items.append((path, label))
return items
class ClipDataset(Dataset):
def __init__(self, items: List[Tuple[str, int]], transform: ClipTransform):
self.items = items
self.transform = transform
def __len__(self) -> int:
return len(self.items)
def __getitem__(self, idx: int):
path, label = self.items[idx]
clip = np.load(path) # (T, H, W) uint8 or float32
if clip.dtype == np.uint8:
clip = clip.astype(np.float32) / 255.0
return self.transform(clip), label
class DummyDataset(Dataset):
"""Synthetic clips for smoke-testing the pipeline end to end."""
def __init__(self, n: int, num_classes: int, num_frames: int, size: int):
self.n = n
self.num_classes = num_classes
self.num_frames = num_frames
self.size = size
def __len__(self) -> int:
return self.n
def __getitem__(self, idx: int):
label = idx % self.num_classes
rng = np.random.default_rng(idx)
# Give each class a distinct brightness bias so the model can learn.
clip = rng.random((1, self.num_frames, self.size, self.size),
dtype=np.float32) * 0.2 + label / self.num_classes
return torch.from_numpy(clip), label
def build_datasets(cfg):
"""Return (train_ds, val_ds, test_ds, label_map)."""
if cfg.dummy:
label_map = {f"word{i}": i for i in range(cfg.dummy_classes)}
make = lambda n: DummyDataset(n, cfg.dummy_classes,
cfg.num_frames, cfg.image_size)
return (make(cfg.dummy_samples), make(cfg.dummy_samples // 4),
make(cfg.dummy_samples // 4), label_map)
roots = [r.strip() for r in cfg.data_roots.split(",") if r.strip()]
words = ([w.strip() for w in cfg.words.split(",") if w.strip()]
or _scan_words(roots))
if not words:
raise RuntimeError(
"No word folders found. Run scripts/prepare_data.py first, "
"point --data_roots at your data (comma-separated), or use --dummy.")
label_map = {w: i for i, w in enumerate(words)}
train_tf = ClipTransform(cfg.image_size, cfg.num_frames, train=True)
eval_tf = ClipTransform(cfg.image_size, cfg.num_frames, train=False)
train_ds = ClipDataset(_collect(roots, "train", label_map), train_tf)
val_ds = ClipDataset(_collect(roots, "val", label_map), eval_tf)
test_ds = ClipDataset(_collect(roots, "test", label_map), eval_tf)
return train_ds, val_ds, test_ds, label_map
def save_label_map(label_map: dict, out_dir: str) -> None:
os.makedirs(out_dir, exist_ok=True)
with open(os.path.join(out_dir, "label_map.json"), "w") as f:
json.dump(label_map, f, indent=2)

Xet Storage Details

Size:
4.26 kB
·
Xet hash:
c718a0da5f15d173ef159cf52527c940f8be7bbb0b5b1f6d3cd7cf49f9c3af95

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.