ASL-Video-To-Sentence-Translation / scripts /prepare_asl_citizen.py
fgar13
Add ASL Qwen training pipeline
babffc8
Raw
History Blame Contribute Delete
4.44 kB
from __future__ import annotations
import argparse
import sys
from pathlib import Path
import pandas as pd
sys.path.append(str(Path(__file__).resolve().parents[1]))
from src.io_utils import load_config, resolve_path, write_jsonl
from src.label_utils import normalize_label
VIDEO_COLUMNS = ["video_path", "path", "file", "filename", "video"]
LABEL_COLUMNS = ["label", "gloss", "sign", "sign_label", "text"]
SPLIT_COLUMNS = ["split", "subset"]
ID_COLUMNS = ["id", "sign_id"]
def pick_column(columns: list[str], candidates: list[str], name: str) -> str:
lower = {c.lower(): c for c in columns}
for cand in candidates:
if cand.lower() in lower:
return lower[cand.lower()]
raise ValueError(f"Missing {name} column. Tried: {', '.join(candidates)}")
def read_metadata(path: Path) -> pd.DataFrame:
suffix = path.suffix.lower()
if suffix == ".csv":
return pd.read_csv(path)
if suffix in {".jsonl", ".ndjson"}:
return pd.read_json(path, lines=True)
if suffix == ".json":
return pd.read_json(path)
raise ValueError(f"Unsupported metadata format: {path.suffix}. Use CSV, JSON, or JSONL.")
def normalize_split(value: str) -> str:
value = str(value).strip().lower()
if value in {"train", "training"}:
return "train"
if value in {"val", "valid", "validation", "dev"}:
return "val"
if value in {"test", "testing"}:
return "test"
return value
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--config", default=None)
parser.add_argument("--metadata", required=True)
parser.add_argument("--video_root", required=True)
parser.add_argument("--out_train", default=None)
parser.add_argument("--out_val", default=None)
parser.add_argument("--skip_missing_check", action="store_true")
parser.add_argument("--val_fraction", type=float, default=0.1)
args = parser.parse_args()
cfg = load_config(args.config) if args.config else {}
out_train = args.out_train or cfg.get("train_jsonl", "data/asl_citizen_train.jsonl")
out_val = args.out_val or cfg.get("val_jsonl", "data/asl_citizen_val.jsonl")
metadata_path = resolve_path(args.metadata, Path.cwd())
video_root = resolve_path(args.video_root, Path.cwd())
if not metadata_path.exists():
raise FileNotFoundError(f"Metadata file not found: {metadata_path}")
if not video_root.exists():
raise FileNotFoundError(f"Video root not found: {video_root}")
df = read_metadata(metadata_path)
columns = list(df.columns)
video_col = pick_column(columns, VIDEO_COLUMNS, "video path")
label_col = pick_column(columns, LABEL_COLUMNS, "label")
id_col = next((c for c in ID_COLUMNS if c in columns), None)
split_col = next((c for c in SPLIT_COLUMNS if c in columns), None)
rows = []
for idx, row in df.iterrows():
label = normalize_label(row[label_col])
if not label:
raise ValueError(f"Missing label in metadata row {idx}")
raw_video = Path(str(row[video_col]))
video_path = raw_video if raw_video.is_absolute() else video_root / raw_video
if not args.skip_missing_check and not video_path.exists():
raise FileNotFoundError(f"Missing video at metadata row {idx}: {video_path}")
split = normalize_split(row[split_col]) if split_col else None
rows.append(
{
"id": str(row[id_col]) if id_col else str(idx),
"video_path": str(video_path),
"label": label,
"split": split,
}
)
if split_col:
train_rows = [r for r in rows if r["split"] == "train"]
val_rows = [r for r in rows if r["split"] in {"val", "validation", "dev"}]
if not train_rows or not val_rows:
raise ValueError("Found a split column, but could not find both train and val rows.")
else:
split_at = max(1, int(len(rows) * (1 - args.val_fraction)))
train_rows = rows[:split_at]
val_rows = rows[split_at:]
for r in train_rows:
r["split"] = "train"
for r in val_rows:
r["split"] = "val"
write_jsonl(out_train, train_rows)
write_jsonl(out_val, val_rows)
print(f"Wrote {len(train_rows)} train rows to {out_train}")
print(f"Wrote {len(val_rows)} val rows to {out_val}")
if __name__ == "__main__":
main()