{ "nbformat": 4, "nbformat_minor": 5, "metadata": { "colab": { "provenance": [], "gpuType": "T4" }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" }, "accelerator": "GPU" }, "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# PakUrdu-Conversational-ASR \u2014 full-quality inference\n", "\n", "Run the **full r14 model** (merged adapter, fp16) on a **free GPU** \u2014 nothing installs on your machine.\n", "\n", "**Setup (one click):** enable a GPU accelerator before running:\n", "- **Colab:** `Runtime \u2192 Change runtime type \u2192 T4 GPU`\n", "- **Kaggle:** `Settings \u2192 Accelerator \u2192 GPU T4 x2` (or P100)\n", "\n", "Then upload an Urdu audio clip (wav/mp3/m4a\u2026) and run the cells top to bottom.\n", "\n", "More: [model card](https://huggingface.co/KhiredNetworks/PakUrdu-Conversational-ASR) \u00b7 ", "[browser demo](https://huggingface.co/spaces/KhiredNetworks/PakUrdu-ASR-Demo) (runs on your device, no GPU needed) \u00b7 ", "[proof notebook](https://www.kaggle.com/code/adeelejaz8611/e1-sr-proof-r14-sr133) (re-derives the certified 7.96% WER end-to-end)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1 \u2014 Load the model (base + fine-tuned adapter, merged)\n", "\n", "Downloads ~1.6 GB once per session; takes a couple of minutes." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# One-time environment fix \u2014 some cloud images ship torchao 0.10, which peft's\n", "# import check rejects. torchao is only needed for torchao-quantized adapters\n", "# (not this one), so removing it is safe and instant.\n", "%pip uninstall -y -q torchao\n", "print(\"environment ok \u2014 continue below\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import torch, torchaudio\n", "from peft import PeftModel\n", "from transformers import WhisperForConditionalGeneration, WhisperProcessor\n", "\n", "BASE = \"openai/whisper-large-v3-turbo\"\n", "ADAPTER = \"KhiredNetworks/PakUrdu-Conversational-ASR\"\n", "\n", "processor = WhisperProcessor.from_pretrained(BASE)\n", "model = WhisperForConditionalGeneration.from_pretrained(BASE, torch_dtype=torch.float16)\n", "model = PeftModel.from_pretrained(model, ADAPTER).merge_and_unload().to(\"cuda\").eval()\n", "print(\"model ready \u2014 full fp16 r14 (merged adapter)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2 \u2014 Point it at your audio\n", "\n", "How to get your clip in:\n", "- **Colab:** folder icon (left) \u2192 Upload, or run `from google.colab import files; files.upload()`\n", "- **Kaggle:** `+ Add Input \u2192 Upload` (attach the clip as a dataset); the path looks like `/kaggle/input//clip.wav`\n", "\n", "Then set the path below." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "AUDIO_PATH = \"your_audio.wav\" # <- set this to your clip's path" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3 \u2014 Transcribe\n", "Greedy decode, `language=ur` (the intended configuration). Clips longer than 30 s are\n", "windowed (25 s windows, 1.5 s overlap) and stitched, so long audio works too." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "SR = 16000\n", "\n", "def merge_texts(parts):\n", " # drop the duplicated overlap words at each window seam\n", " out = []\n", " for p in parts:\n", " words = (p or \"\").strip().split()\n", " drop = 0\n", " for k in range(min(len(out), len(words), 12), 0, -1):\n", " if out[len(out) - k:] == words[:k]:\n", " drop = k\n", " break\n", " out.extend(words[drop:])\n", " return \" \".join(out)\n", "\n", "@torch.no_grad()\n", "def transcribe(path):\n", " speech, sr = torchaudio.load(path) # (channels, samples)\n", " speech = speech.mean(dim=0)\n", " if sr != SR:\n", " speech = torchaudio.functional.resample(speech, sr, SR)\n", " texts, start, CHUNK, OVERLAP = [], 0, 25 * SR, int(1.5 * SR)\n", " while start < len(speech):\n", " end = min(start + CHUNK, len(speech))\n", " feats = processor(speech[start:end].numpy(), sampling_rate=SR,\n", " return_tensors=\"pt\").input_features.half().to(\"cuda\")\n", " ids = model.generate(feats, language=\"ur\", task=\"transcribe\", do_sample=False)\n", " texts.append(processor.batch_decode(ids, skip_special_tokens=True)[0].strip())\n", " if end == len(speech):\n", " break\n", " start = end - OVERLAP\n", " return merge_texts(texts)\n", "\n", "print(transcribe(AUDIO_PATH))" ] } ] }