Phase-1: from-scratch Zipformer-M CTC streaming (Hindi/Hinglish) + full training scripts
e146811 verified | #!/usr/bin/env python3 | |
| """Build lhotse CutSets from cleaned manifests (one cut == one utterance). | |
| Reads {train,dev,eval_*}.jsonl (fields: audio,dur,source,tok,text) and writes | |
| cuts_{name}.jsonl.gz. Supervision.text = 'tok' (▁-joined, codepoint units). | |
| All cuts resampled to 16 kHz (on-the-fly). Features are NOT precomputed | |
| (training uses --on-the-fly-feats). | |
| """ | |
| import argparse | |
| import json | |
| import os | |
| from concurrent.futures import ThreadPoolExecutor | |
| from lhotse import CutSet, Recording, SupervisionSegment | |
| from lhotse.audio import AudioSource | |
| def make_cut(row, idx): | |
| from lhotse import MonoCut | |
| try: | |
| rec = Recording.from_file(row["audio"], recording_id=f"{row['source']}_{idx:07d}") | |
| except Exception as e: | |
| return None | |
| sup = SupervisionSegment( | |
| id=rec.id, recording_id=rec.id, start=0.0, | |
| duration=rec.duration, channel=rec.channel_ids[0], | |
| text=row["tok"], language=row["source"], | |
| ) | |
| cut = MonoCut(id=rec.id, start=0.0, duration=rec.duration, | |
| channel=rec.channel_ids[0], recording=rec, supervisions=[sup]) | |
| if rec.sampling_rate != 16000: | |
| cut = cut.resample(16000) | |
| return cut | |
| def build(jsonl, out, workers): | |
| rows = [json.loads(l) for l in open(jsonl)] | |
| cuts = [] | |
| with ThreadPoolExecutor(max_workers=workers) as ex: | |
| for c in ex.map(lambda a: make_cut(a[1], a[0]), list(enumerate(rows))): | |
| if c is not None: | |
| cuts.append(c) | |
| cs = CutSet.from_cuts(cuts) | |
| cs.to_file(out) | |
| dur = sum(c.duration for c in cuts) / 3600 | |
| print(f"{os.path.basename(out)}: {len(cuts)} cuts {dur:.1f}h (from {len(rows)} rows)") | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--manifests", required=True, help="dir with *.jsonl") | |
| ap.add_argument("--out", required=True, help="output dir for cuts") | |
| ap.add_argument("--workers", type=int, default=32) | |
| ap.add_argument("--sets", nargs="+", | |
| default=["train", "dev", "eval_iv_hi", "eval_svarah", "eval_call_test"]) | |
| args = ap.parse_args() | |
| os.makedirs(args.out, exist_ok=True) | |
| for name in args.sets: | |
| jsonl = os.path.join(args.manifests, f"{name}.jsonl") | |
| if not os.path.exists(jsonl): | |
| print(f"skip {name} (no {jsonl})"); continue | |
| build(jsonl, os.path.join(args.out, f"cuts_{name}.jsonl.gz"), args.workers) | |
| if __name__ == "__main__": | |
| main() | |