{ "cells": [ { "cell_type": "markdown", "id": "53760ec2-0a8d-4e0b-873f-8f4679350916", "metadata": {}, "source": [ "1. Loads the model with `AutoModel`\n", "2. Loads the custom feature extractor\n", "3. Loads the custom tokenizer\n", "4. Loads/resamples audio\n", "5. Extracts features\n", "6. Runs the encoder **once**\n", "7. Automatically identifies the language\n", "8. Builds the correct Canary prompt\n", "9. Generates the transcription\n", "10. Decodes the result" ] }, { "cell_type": "code", "execution_count": 1, "id": "f149fa33-8ce5-40a2-b456-4910541a3054", "metadata": {}, "outputs": [], "source": [ "import sys\n", "import torch\n", "import torchaudio\n", "from transformers import AutoModel, BitsAndBytesConfig" ] }, { "cell_type": "code", "execution_count": 2, "id": "d5fbe9bf-88c7-4f27-b39c-89c69319f2df", "metadata": {}, "outputs": [], "source": [ "MODEL_DIR = \"indic-transcribe-core-8bit-quant\"\n", "MAX_NEW_TOKENS = 256" ] }, { "cell_type": "code", "execution_count": 3, "id": "97d7adb0-800f-4493-be86-cf5e2a3ed77b", "metadata": {}, "outputs": [], "source": [ "sys.path.insert(0, MODEL_DIR)" ] }, { "cell_type": "code", "execution_count": 4, "id": "339d91f0-403c-4460-a561-0fe37d472186", "metadata": {}, "outputs": [], "source": [ "from feature_extraction_indic_canary import IndicCanaryFeatureExtractor\n", "from tokenization_indic_canary import IndicCanaryTokenizer\n", "from lid import lid_from_encoder_states" ] }, { "cell_type": "code", "execution_count": 5, "id": "233c4808-ff1c-4e7c-96a1-10d07e9bb52e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Device: cuda\n" ] } ], "source": [ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", "\n", "print(\"Device:\", device)" ] }, { "cell_type": "code", "execution_count": 6, "id": "d317c9d9-9138-4a61-91f6-8152dc1fecba", "metadata": {}, "outputs": [], "source": [ "# quant_config = BitsAndBytesConfig(\n", "# load_in_8bit=True,\n", "# llm_int8_skip_modules=[\n", "# \"model.encoder.pre_encode.out\",\n", "# \"lm_head\",\n", "# ],\n", "# )" ] }, { "cell_type": "code", "execution_count": 7, "id": "7d75c2c1-2825-4fec-9cbf-512d48452a4c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading model...\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "cf026cf5108340989e0c846b8316cf94", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Loading weights: 0%| | 0/1923 [00:00\n", "1.4606210589408875 GB\n" ] } ], "source": [ "print(type(model))\n", "print(model.get_memory_footprint() / 1024**3, \"GB\")" ] }, { "cell_type": "code", "execution_count": 10, "id": "9fd33ff5-2849-46c6-8666-2ed9ec222427", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "IndicCanaryFeatureExtractor()" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "feature_extractor = IndicCanaryFeatureExtractor.from_pretrained(\n", " MODEL_DIR,\n", " device=str(model.device),\n", ")\n", "\n", "feature_extractor.eval()" ] }, { "cell_type": "code", "execution_count": 11, "id": "bf5502dd-98cc-4cc5-a1b9-488fbc4bf1d5", "metadata": {}, "outputs": [], "source": [ "tokenizer = IndicCanaryTokenizer.from_pretrained(\n", " MODEL_DIR,\n", ")" ] }, { "cell_type": "code", "execution_count": 12, "id": "8a9faa74-63d8-411f-bba0-87f4ee1e7e9b", "metadata": {}, "outputs": [], "source": [ "AUDIO_FILE = \"telugu.wav\"" ] }, { "cell_type": "code", "execution_count": 13, "id": "6dfa6398-3da3-439c-bce7-e5383e81a3ef", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading audio: telugu.wav\n", "Original audio:\n", "Sample rate: 44100\n", "Shape: torch.Size([1, 253440])\n" ] } ], "source": [ "print(\"Loading audio:\", AUDIO_FILE)\n", "\n", "wav, sr = torchaudio.load(AUDIO_FILE)\n", "\n", "print(\"Original audio:\")\n", "print(\"Sample rate:\", sr)\n", "print(\"Shape:\", wav.shape)" ] }, { "cell_type": "code", "execution_count": 14, "id": "92e8412c-6b0c-4935-930b-cb13d09e690e", "metadata": {}, "outputs": [], "source": [ "# Convert stereo -> mono\n", "\n", "if wav.shape[0] > 1:\n", " wav = wav.mean(dim=0)\n", "else:\n", " wav = wav.squeeze(0)\n", "\n", "wav = wav.float()" ] }, { "cell_type": "code", "execution_count": 15, "id": "80239b15-a4d9-45cc-aeac-f15dfa4f2527", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Resampling 44100 Hz -> 16000 Hz\n" ] } ], "source": [ "# Resample using the model's exact resampler\n", "\n", "if sr != feature_extractor.sample_rate:\n", " print(\n", " f\"Resampling {sr} Hz -> \"\n", " f\"{feature_extractor.sample_rate} Hz\"\n", " )\n", "\n", "wav = feature_extractor.resample(\n", " wav,\n", " sr,\n", ")" ] }, { "cell_type": "code", "execution_count": 16, "id": "3d303cf7-9f97-4999-a88a-cced68f940d1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Audio duration: 5.75 seconds\n" ] } ], "source": [ "# Audio length\n", "\n", "num_samples = wav.shape[0]\n", "\n", "duration = num_samples / feature_extractor.sample_rate\n", "\n", "print(f\"Audio duration: {duration:.2f} seconds\")" ] }, { "cell_type": "code", "execution_count": 17, "id": "56548aed-e101-4e5b-9d02-9b10a580bb92", "metadata": {}, "outputs": [], "source": [ "# Pad short audio\n", "# The production wrapper pads audio shorter than 1 second to exactly 1 second, centered.\n", "\n", "MIN_AUDIO_SAMPLES = feature_extractor.sample_rate # 1 second\n", "\n", "if num_samples < MIN_AUDIO_SAMPLES:\n", "\n", " print(\"Audio shorter than 1 second; padding...\")\n", "\n", " batch = torch.zeros(\n", " 1,\n", " MIN_AUDIO_SAMPLES,\n", " dtype=torch.float32,\n", " )\n", "\n", " offset = round(\n", " (MIN_AUDIO_SAMPLES - num_samples) / 2\n", " )\n", "\n", " batch[\n", " 0,\n", " offset:offset + num_samples\n", " ] = wav\n", "\n", " sample_lens = torch.tensor(\n", " [MIN_AUDIO_SAMPLES],\n", " dtype=torch.long,\n", " )\n", "\n", "else:\n", "\n", " batch = wav.unsqueeze(0)\n", "\n", " sample_lens = torch.tensor(\n", " [num_samples],\n", " dtype=torch.long,\n", " )\n" ] }, { "cell_type": "code", "execution_count": 18, "id": "40e60841-b0fe-4756-8aaf-f0c1622bb023", "metadata": {}, "outputs": [], "source": [ "batch = batch.to(model.device)\n", "sample_lens = sample_lens.to(model.device)" ] }, { "cell_type": "code", "execution_count": 19, "id": "f67a6eff-07bc-4e80-ace7-6f892d0ac8b0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Extracting audio features...\n", "Input features: (1, 128, 575)\n", "Feature lengths: [575]\n" ] } ], "source": [ "print(\"Extracting audio features...\")\n", "\n", "with torch.inference_mode():\n", "\n", " input_features, feat_lens = feature_extractor(\n", " batch,\n", " sample_lens,\n", " )\n", "\n", "print(\n", " \"Input features:\",\n", " tuple(input_features.shape)\n", ")\n", "\n", "print(\n", " \"Feature lengths:\",\n", " feat_lens.tolist()\n", ")" ] }, { "cell_type": "code", "execution_count": 20, "id": "b3631904-c310-438a-887e-4627ed8487fa", "metadata": {}, "outputs": [], "source": [ "attention_mask = (\n", " torch.arange(\n", " input_features.size(2),\n", " device=model.device,\n", " )[None, :]\n", " < feat_lens[:, None]\n", ").long()" ] }, { "cell_type": "code", "execution_count": 21, "id": "cd37fe3a-7db7-419d-afa0-cc5501bae0e9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Running encoder...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/mani/anaconda3/envs/torch/lib/python3.10/site-packages/bitsandbytes/autograd/_functions.py:123: UserWarning: MatMul8bitLt: inputs will be cast from torch.float32 to float16 during quantization\n", " warnings.warn(f\"MatMul8bitLt: inputs will be cast from {A.dtype} to float16 during quantization\")\n" ] } ], "source": [ "# ENCODER\n", "\n", "# The same encoder output is used for:\n", "# 1. Language identification\n", "# 2. Transcription\n", "\n", "print(\"Running encoder...\")\n", "\n", "with torch.inference_mode():\n", "\n", " encoder_outputs = model.model.encoder(\n", " input_features,\n", " attention_mask=attention_mask,\n", " )" ] }, { "cell_type": "code", "execution_count": 22, "id": "fb30d3aa-34ab-4b59-b78b-70a1bdb1e4aa", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Detecting language...\n", "Language candidates:\n", " te : 1.0000\n", " sa : 0.0000\n", " kn : 0.0000\n", " en : 0.0000\n", " ml : 0.0000\n", "\n", "Detected language: te\n" ] } ], "source": [ "# LANGUAGE IDENTIFICATION\n", "\n", "print(\"Detecting language...\")\n", "\n", "with torch.inference_mode():\n", "\n", " top_languages = lid_from_encoder_states(\n", " model,\n", " encoder_outputs.last_hidden_state,\n", " encoder_outputs.lengths,\n", " tokenizer=tokenizer,\n", " topk=5,\n", " )\n", " \n", "print(\"Language candidates:\")\n", "\n", "for lang, probability in top_languages[0]:\n", "\n", " print(\n", " f\" {lang:>4} : \"\n", " f\"{probability:.4f}\"\n", " )\n", "\n", "\n", "\n", "language = top_languages[0][0][0]\n", "\n", "print()\n", "print(\"Detected language:\", language)" ] }, { "cell_type": "code", "execution_count": 23, "id": "58d16b1f-6274-457d-8d8e-69cef21f3e0d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Decoder prompt: [7, 4, 18, 187, 187, 5, 9, 11, 13, 15]\n" ] } ], "source": [ "prompt = tokenizer.encode_prompt(\n", " language,\n", " itn=False,\n", " romanized=False,\n", ")\n", "\n", "print(\"Decoder prompt:\", prompt)" ] }, { "cell_type": "code", "execution_count": 24, "id": "09d5e7dd-ece2-45ed-8bd4-41e404be4f15", "metadata": {}, "outputs": [], "source": [ "decoder_input_ids = torch.tensor(\n", " [prompt],\n", " dtype=torch.long,\n", " device=model.device,\n", ")" ] }, { "cell_type": "code", "execution_count": 25, "id": "8eec02a9-4f49-49f7-9933-e2471e38edde", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[transformers] The remote code model you are currently using seems to expect `cache_position`. This arg has been removed from the Transformers library, and will stop being created in `generate` even for remote code models in a future release. Please open a PR on the remote code hub repo to remove any usage of `cache_position`.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcribing... \n", "\n", "జీవితం ఒక అందమైన ప్రయాణం ప్రతిరోజు కొత్త అనుభవాన్ని ప్రతిక్షణం కొత్త అవకాశాన్ని తీసుకొస్తుంది\n" ] } ], "source": [ "# GENERATE TRANSCRIPTION\n", "\n", "# Use encoder_outputs so that the encoder isn't executed a second time.\n", "\n", "print(\"Transcribing... \\n\")\n", "\n", "with torch.inference_mode():\n", "\n", " output_ids = model.generate(\n", " encoder_outputs=encoder_outputs,\n", " attention_mask=attention_mask,\n", " decoder_input_ids=decoder_input_ids,\n", " # max_new_tokens=MAX_NEW_TOKENS,\n", " )\n", "\n", "generated_ids = tokenizer.strip_prompt_and_trim(\n", " output_ids[0].tolist(),\n", " prompt,\n", ")\n", "\n", "text = tokenizer.decode(\n", " generated_ids\n", ")\n", "\n", "print(text)" ] }, { "cell_type": "code", "execution_count": 26, "id": "13fbcb58-4e49-4bf7-bee1-5feabbaad49a", "metadata": {}, "outputs": [], "source": [ "torch.cuda.empty_cache()" ] }, { "cell_type": "code", "execution_count": null, "id": "87164ab3-6292-4ad9-b209-f1fd2ddba5a1", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "872a79d1-58c5-4252-958e-465b772719f0", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.18" } }, "nbformat": 4, "nbformat_minor": 5 }