Spaces:
Sleeping
Sleeping
jefffffff9 Claude Sonnet 4.6 commited on
Commit ·
aef60bc
1
Parent(s): 8e41441
Proactive notebook audit: fix 5 issues before they cause errors
Browse files1. Cell 3: remove dead LORA_R/ALPHA/DROPOUT/TARGETS vars (PEFT removed)
2. Cell 13: fix train_test_split test_size -- was float(0.05) which gives
0 eval samples on small datasets; now max(1, int(0.05 * n))
3. Cell 22: remove forced_decoder_ids kwarg from model.generate() --
transformers 5.x removed this param; config already has it set
4. Cell 13: remove num_proc=2 from waxal map (multiprocessing + audio can
hang on Kaggle when dataset is small)
5. Update stale markdown cells (LoRA/PEFT/8-bit references removed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
notebooks/kaggle_master_trainer.ipynb
CHANGED
|
@@ -62,7 +62,7 @@
|
|
| 62 |
"metadata": {},
|
| 63 |
"outputs": [],
|
| 64 |
"source": [
|
| 65 |
-
"# ── Cell 3: CONFIGURATION — edit these before each run ───────────────────────\nimport os\n\n# ─── Language to train ───────────────────────────────────────────────────────\n# 'bam' = Bambara 'ful' = Fula\nTRAIN_LANG = 'bam'\n\n# ─── Model ───────────────────────────────────────────────────────────────────\nWHISPER_MODEL_ID = 'openai/whisper-small'\nTARGET_SR = 16_000\n\n# ─── HuggingFace repos ───────────────────────────────────────────────────────\nHF_USERNAME = 'ous-sow'\nFEEDBACK_REPO_ID = f'{HF_USERNAME}/sahel-agri-feedback'\nADAPTER_REPO_ID = f'{HF_USERNAME}/sahel-agri-adapters'\n\n# ───
|
| 66 |
]
|
| 67 |
},
|
| 68 |
{
|
|
@@ -141,7 +141,9 @@
|
|
| 141 |
"id": "cell-merge",
|
| 142 |
"metadata": {},
|
| 143 |
"outputs": [],
|
| 144 |
-
"source":
|
|
|
|
|
|
|
| 145 |
},
|
| 146 |
{
|
| 147 |
"cell_type": "code",
|
|
@@ -155,7 +157,9 @@
|
|
| 155 |
"cell_type": "markdown",
|
| 156 |
"id": "md-model",
|
| 157 |
"metadata": {},
|
| 158 |
-
"source":
|
|
|
|
|
|
|
| 159 |
},
|
| 160 |
{
|
| 161 |
"cell_type": "code",
|
|
@@ -262,13 +266,17 @@
|
|
| 262 |
"id": "cell-eval",
|
| 263 |
"metadata": {},
|
| 264 |
"outputs": [],
|
| 265 |
-
"source":
|
|
|
|
|
|
|
| 266 |
},
|
| 267 |
{
|
| 268 |
"cell_type": "markdown",
|
| 269 |
"id": "md-export",
|
| 270 |
"metadata": {},
|
| 271 |
-
"source":
|
|
|
|
|
|
|
| 272 |
},
|
| 273 |
{
|
| 274 |
"cell_type": "code",
|
|
|
|
| 62 |
"metadata": {},
|
| 63 |
"outputs": [],
|
| 64 |
"source": [
|
| 65 |
+
"# ── Cell 3: CONFIGURATION — edit these before each run ───────────────────────\nimport os\n\n# ─── Language to train ───────────────────────────────────────────────────────\n# 'bam' = Bambara 'ful' = Fula\nTRAIN_LANG = 'bam'\n\n# ─── Model ───────────────────────────────────────────────────────────────────\nWHISPER_MODEL_ID = 'openai/whisper-small'\nTARGET_SR = 16_000\n\n# ─── HuggingFace repos ───────────────────────────────────────────────────────\nHF_USERNAME = 'ous-sow'\nFEEDBACK_REPO_ID = f'{HF_USERNAME}/sahel-agri-feedback'\nADAPTER_REPO_ID = f'{HF_USERNAME}/sahel-agri-adapters'\n\n# ─── Training hyper-parameters ───────────────────────────────────────────────\nMAX_STEPS = 4_000 # T4 ~45 min; set 8000 for a deeper run\nBATCH_SIZE = 16\nGRAD_ACCUM = 2 # effective batch = 32\nLEARNING_RATE = 1e-3\nWARMUP_STEPS = 200\nSAVE_STEPS = 500\nEVAL_STEPS = 500\nLOGGING_STEPS = 50\nMAX_WAXAL_TRAIN = 5_000 # cap WaxalNLP samples (streaming budget)\nCORRECTION_REPEAT= 3 # upsample user corrections Nx for emphasis\n\n# ─── Paths (Kaggle working dir) ───────────────────────────────────────────────\nWORKING_DIR = '/kaggle/working'\nOUTPUT_DIR = f'{WORKING_DIR}/adapter_{TRAIN_LANG}'\nDATA_DIR = f'{WORKING_DIR}/data'\nAUDIO_DIR = f'{WORKING_DIR}/audio_feedback'\n\nLANG_NAME = {'bam': 'bambara', 'ful': 'fula'}.get(TRAIN_LANG, TRAIN_LANG)\n\nprint(f'Language : {TRAIN_LANG} ({LANG_NAME})')\nprint(f'Model : {WHISPER_MODEL_ID}')\nprint(f'Output : {OUTPUT_DIR}')\nprint(f'Max steps : {MAX_STEPS}')"
|
| 66 |
]
|
| 67 |
},
|
| 68 |
{
|
|
|
|
| 141 |
"id": "cell-merge",
|
| 142 |
"metadata": {},
|
| 143 |
"outputs": [],
|
| 144 |
+
"source": [
|
| 145 |
+
"# -- Cell 12: Build & merge all datasets --------------------------------------\nfrom datasets import Dataset, Audio as HFAudio, concatenate_datasets\nfrom functools import partial\n\ntrain_ds = None # set here so Cell 12b can detect whether we succeeded\neval_ds = None\nall_parts = []\n\n# -- Part A: User corrections -------------------------------------------------\nif correction_records:\n print(f'Part A: {len(correction_records)} corrections x {CORRECTION_REPEAT}')\n rec_list = correction_records * CORRECTION_REPEAT\n corr_ds = Dataset.from_dict({\n 'audio': [r['local_audio'] for r in rec_list],\n 'transcription': [r.get('corrected_text') or r.get('transcription', '') for r in rec_list],\n })\n corr_ds = corr_ds.cast_column('audio', HFAudio(sampling_rate=TARGET_SR))\n corr_ds = corr_ds.map(\n partial(prepare_dataset, text_col='transcription'),\n remove_columns=corr_ds.column_names,\n )\n all_parts.append(corr_ds)\n print(f' -> {len(corr_ds)} samples')\nelse:\n print('Part A: no corrections -- skipping')\n\n# -- Part B: WaxalNLP ---------------------------------------------------------\nif waxal_ds is not None:\n print(f'Part B: materialising up to {MAX_WAXAL_TRAIN} WaxalNLP samples ...')\n waxal_rows = list(waxal_ds.take(MAX_WAXAL_TRAIN))\n waxal_local = Dataset.from_dict({\n 'audio': [r['audio'] for r in waxal_rows],\n 'transcription': [r.get(WAXAL_TEXT_COL, '') for r in waxal_rows],\n })\n waxal_local = waxal_local.cast_column('audio', HFAudio(sampling_rate=TARGET_SR))\n waxal_local = waxal_local.map(\n partial(prepare_dataset, text_col='transcription'),\n remove_columns=waxal_local.column_names,\n )\n all_parts.append(waxal_local)\n print(f' -> {len(waxal_local)} samples')\nelse:\n print('Part B: WaxalNLP not available -- skipping')\n\n# -- Part C: External datasets ------------------------------------------------\nfor ext_ds, text_col in external_datasets:\n ext_rows = list(ext_ds)\n if not ext_rows:\n continue\n ext_local = Dataset.from_dict({\n 'audio': [r['audio'] for r in ext_rows],\n 'transcription': [r.get(text_col, '') for r in ext_rows],\n })\n ext_local = ext_local.cast_column('audio', HFAudio(sampling_rate=TARGET_SR))\n ext_local = ext_local.map(\n partial(prepare_dataset, text_col='transcription'),\n remove_columns=ext_local.column_names,\n )\n all_parts.append(ext_local)\n print(f'Part C: {len(ext_local)} external samples')\n\n# -- Result -------------------------------------------------------------------\nprint(f'\\nData summary: {len(all_parts)} source(s) loaded')\n\nif not all_parts:\n print('No real data available for Bambara yet.')\n print('Cell 12b (below) will build a synthetic dataset so the full')\n print('training pipeline can be validated. Switch to TRAIN_LANG=\"ful\"')\n print('in Cell 3 for a real Fula training run using WaxalNLP.')\nelse:\n combined = concatenate_datasets(all_parts).shuffle(seed=42)\n n_eval = max(1, min(int(0.05 * len(combined)), 200))\n split = combined.train_test_split(test_size=n_eval)\n train_ds = split['train']\n eval_ds = split['test']\n print(f'Train: {len(train_ds)} Eval: {len(eval_ds)}')"
|
| 146 |
+
]
|
| 147 |
},
|
| 148 |
{
|
| 149 |
"cell_type": "code",
|
|
|
|
| 157 |
"cell_type": "markdown",
|
| 158 |
"id": "md-model",
|
| 159 |
"metadata": {},
|
| 160 |
+
"source": [
|
| 161 |
+
"---\n## Model Setup - Partial Freeze Fine-Tuning\n\nopenai/whisper-small is loaded in fp16. All parameters are frozen, then\nthe last 2 decoder layers + layer norm + output projection are unfrozen (~5%\ntrainable params). No PEFT/LoRA -- avoids PEFT/transformers 5.x\nincompatibility where input_ids is passed twice to WhisperDecoder.\n"
|
| 162 |
+
]
|
| 163 |
},
|
| 164 |
{
|
| 165 |
"cell_type": "code",
|
|
|
|
| 266 |
"id": "cell-eval",
|
| 267 |
"metadata": {},
|
| 268 |
"outputs": [],
|
| 269 |
+
"source": [
|
| 270 |
+
"# ── Cell 17: WER evaluation ───────────────────────────────────────────────────\nprint('Running full evaluation on eval split ...')\neval_results = trainer.evaluate()\n\nwer_score = eval_results.get('eval_wer', float('nan'))\nprint(f'\\n📊 Final WER : {wer_score:.1%}')\nprint(f' Eval loss : {eval_results.get(\"eval_loss\", float(\"nan\")):.4f}')\n\n# Show a few example transcriptions side-by-side\nimport random, torch\nprint('\\n── Sample predictions ───────────────────────────────')\nsamples = random.sample(range(len(eval_ds)), min(5, len(eval_ds)))\nfor idx in samples:\n item = eval_ds[idx]\n feats = torch.tensor(item['input_features']).unsqueeze(0).to(model.device)\n with torch.no_grad():\n pred_ids = model.generate(\n feats.half(),\n max_new_tokens=128,\n )\n pred_str = processor.tokenizer.batch_decode(pred_ids, skip_special_tokens=True)[0]\n labels = [t if t != -100 else processor.tokenizer.pad_token_id\n for t in item['labels']]\n ref_str = processor.tokenizer.decode(labels, skip_special_tokens=True)\n print(f' Ref : {ref_str}')\n print(f' Pred: {pred_str}')\n print()"
|
| 271 |
+
]
|
| 272 |
},
|
| 273 |
{
|
| 274 |
"cell_type": "markdown",
|
| 275 |
"id": "md-export",
|
| 276 |
"metadata": {},
|
| 277 |
+
"source": [
|
| 278 |
+
"---\n## Export — Push Fine-tuned Checkpoint to Hub\n\nThe adapter is pushed to `ous-sow/sahel-agri-adapters` under the path \n`adapters/{lang_name}/` with a Git tag like `v1.2-bambara`.\n\nThe version number is **auto-incremented** by reading existing tags on the repo\nso each training run gets a unique, traceable identifier."
|
| 279 |
+
]
|
| 280 |
},
|
| 281 |
{
|
| 282 |
"cell_type": "code",
|