4moha commited on
Commit
5d536d6
·
verified ·
1 Parent(s): 0928c49

Add train_narrator_tts.py

Browse files
Files changed (1) hide show
  1. train_narrator_tts.py +13 -17
train_narrator_tts.py CHANGED
@@ -20,9 +20,10 @@ Output: pushed to HF_TTS_MODEL_REPO
20
  Key F5-TTS internals learned from source inspection:
21
  - Dataset path: {f5_tts_pkg}/../../data/{dataset_name}/ (load_from_disk)
22
  - Checkpoint out: {f5_tts_pkg}/../../ckpts/{dataset_name}/
23
- - HFDataset accesses row["audio"]["array"] (numpy) + row["audio"]["sampling_rate"]
24
- - Audio decode via soundfile (not torchcodec) -- so store paths, not arrays
25
  - --tokenizer_path only respected when --tokenizer custom (not char/pinyin)
 
26
 
27
  Env vars:
28
  HF_TOKEN — HF write token (injected as --secrets HF_TOKEN)
@@ -55,7 +56,6 @@ MAX_SECS = 12.0
55
 
56
  DATASET_NAME = "narrator"
57
  EXP_ARCH = "F5TTS_v1_Base"
58
- WAVS_DIR = Path("/tmp/f5_work/wavs")
59
 
60
 
61
  def _lib_root() -> Path:
@@ -75,7 +75,7 @@ def _pkg_ckpt_root() -> Path:
75
 
76
 
77
  def prepare_data() -> None:
78
- """Download LJSpeech, write WAVs, build HF dataset + vocab at paths F5-TTS expects."""
79
  tar_path = Path("/tmp/ljspeech.tar.bz2")
80
  lj_root = Path("/tmp/LJSpeech-1.1")
81
 
@@ -87,9 +87,12 @@ def prepare_data() -> None:
87
  tar.extractall("/tmp/", filter="data")
88
  print(f"Extracted -> {lj_root}")
89
 
90
- WAVS_DIR.mkdir(parents=True, exist_ok=True)
91
-
92
- wav_paths: list[str] = []
 
 
 
93
  texts: list[str] = []
94
  durations: list[float] = []
95
  count = 0
@@ -119,9 +122,7 @@ def prepare_data() -> None:
119
  import librosa
120
  arr = librosa.resample(arr, orig_sr=orig_sr, target_sr=TARGET_SR)
121
 
122
- dest = WAVS_DIR / f"{clip_id}.wav"
123
- sf.write(str(dest), arr, TARGET_SR)
124
- wav_paths.append(str(dest))
125
  texts.append(text)
126
  durations.append(len(arr) / TARGET_SR)
127
  count += 1
@@ -129,17 +130,12 @@ def prepare_data() -> None:
129
  print(f"Prepared {count} samples")
130
 
131
  # F5-TTS dataset.py builds the path as data/{dataset_name}_{tokenizer}/raw/
132
- # The base model (F5TTS_v1_Base) was trained with --tokenizer pinyin (2546-token vocab).
133
- # We MUST use pinyin to keep text_embed.weight shape [2546, 512] matching the checkpoint.
134
- # Pinyin tokenizer handles English ASCII fine (maps each char through its vocab).
135
  token_dir = _pkg_data_root() / f"{DATASET_NAME}_pinyin"
136
  raw_dir = token_dir / "raw"
137
  raw_dir.mkdir(parents=True, exist_ok=True)
138
 
139
- # Pass file PATHS (strings) to Audio feature — encode_example for a string stores
140
- # {"path": str, "bytes": None} without torchcodec. Decode at training time uses soundfile.
141
- ds = hf_datasets.Dataset.from_dict({"audio": wav_paths, "text": texts})
142
- ds = ds.cast_column("audio", hf_datasets.Audio(sampling_rate=TARGET_SR))
143
  ds.save_to_disk(str(raw_dir))
144
  print(f"Saved dataset -> {raw_dir}")
145
 
 
20
  Key F5-TTS internals learned from source inspection:
21
  - Dataset path: {f5_tts_pkg}/../../data/{dataset_name}/ (load_from_disk)
22
  - Checkpoint out: {f5_tts_pkg}/../../ckpts/{dataset_name}/
23
+ - CustomDataset accesses row["audio"]["array"] + row["audio"]["sampling_rate"]
24
+ - Store audio as plain dict (no hf_datasets.Audio feature) to avoid torchcodec/FFmpeg dep
25
  - --tokenizer_path only respected when --tokenizer custom (not char/pinyin)
26
+ - Must use --tokenizer pinyin to match base model text_embed shape [2546, 512]
27
 
28
  Env vars:
29
  HF_TOKEN — HF write token (injected as --secrets HF_TOKEN)
 
56
 
57
  DATASET_NAME = "narrator"
58
  EXP_ARCH = "F5TTS_v1_Base"
 
59
 
60
 
61
  def _lib_root() -> Path:
 
75
 
76
 
77
  def prepare_data() -> None:
78
+ """Download LJSpeech, build HF Arrow dataset + vocab at paths F5-TTS expects."""
79
  tar_path = Path("/tmp/ljspeech.tar.bz2")
80
  lj_root = Path("/tmp/LJSpeech-1.1")
81
 
 
87
  tar.extractall("/tmp/", filter="data")
88
  print(f"Extracted -> {lj_root}")
89
 
90
+ # Store audio as pre-decoded float arrays — NO hf_datasets.Audio feature.
91
+ # Using Audio feature triggers torchcodec at read time, which requires FFmpeg
92
+ # system libs that aren't available in HF Jobs. Storing plain dicts sidesteps this:
93
+ # row["audio"]["array"] is a Python list[float], row["audio"]["sampling_rate"] is int.
94
+ # F5-TTS CustomDataset calls torch.FloatTensor(row["audio"]["array"]) which accepts lists.
95
+ audio_data: list[dict] = []
96
  texts: list[str] = []
97
  durations: list[float] = []
98
  count = 0
 
122
  import librosa
123
  arr = librosa.resample(arr, orig_sr=orig_sr, target_sr=TARGET_SR)
124
 
125
+ audio_data.append({"array": arr.tolist(), "sampling_rate": TARGET_SR})
 
 
126
  texts.append(text)
127
  durations.append(len(arr) / TARGET_SR)
128
  count += 1
 
130
  print(f"Prepared {count} samples")
131
 
132
  # F5-TTS dataset.py builds the path as data/{dataset_name}_{tokenizer}/raw/
133
+ # Must use pinyin tokenizer to match base model's 2546-token text_embed shape.
 
 
134
  token_dir = _pkg_data_root() / f"{DATASET_NAME}_pinyin"
135
  raw_dir = token_dir / "raw"
136
  raw_dir.mkdir(parents=True, exist_ok=True)
137
 
138
+ ds = hf_datasets.Dataset.from_dict({"audio": audio_data, "text": texts})
 
 
 
139
  ds.save_to_disk(str(raw_dir))
140
  print(f"Saved dataset -> {raw_dir}")
141