{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":129271,"databundleVersionId":15506307,"isSourceIdPinned":false},{"sourceType":"modelInstanceVersion","sourceId":758136,"databundleVersionId":15783601,"modelInstanceId":579121,"modelId":591442,"isSourceIdPinned":false}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Run these cells until you reach the **Execution Note**.","metadata":{}},{"cell_type":"markdown","source":"## **Login to HuggingFace Hub**\n\nThis cell authenticates the session with the HuggingFace Hub using an access token, allowing gated models and private repositories to be downloaded.","metadata":{}},{"cell_type":"code","source":"from huggingface_hub import login\nlogin('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')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Define Fixed Dependency Constraints**\n\nThis cell creates a `constraints.txt` file with pinned versions of core scientific and PyTorch libraries to ensure reproducible training and avoid compatibility issues.","metadata":{}},{"cell_type":"code","source":"# Write constraints file\nwith open(\"/kaggle/working/constraints.txt\", \"w\") as f:\n    f.write(\"\"\"numpy==1.26.4\nscipy==1.11.4\nlightning==2.2.5\ntorch==2.3.1+cu121\ntorchaudio==2.3.1+cu121\ntorchvision==0.18.1+cu121\n\"\"\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Install PyTorch and Pyannote Stack with Constraints**\n\nThis cell installs NumPy, SciPy, the CUDA-enabled PyTorch stack, Lightning, and `pyannote.audio` using the predefined constraints file to maintain version compatibility and ensure stable diarization training.","metadata":{}},{"cell_type":"code","source":"# Install NumPy/SciPy\n!pip install --no-cache-dir --force-reinstall -c /kaggle/working/constraints.txt numpy scipy\n\n# Install torch stack\n!pip install -c /kaggle/working/constraints.txt \\\n  torch==2.3.1+cu121 torchaudio==2.3.1+cu121 torchvision==0.18.1+cu121 \\\n  --index-url https://download.pytorch.org/whl/cu121\n\n# Install lightning + pyannote under constraints\n!pip install -c /kaggle/working/constraints.txt lightning==2.2.5\n!pip install -c /kaggle/working/constraints.txt pyannote.audio==3.1.1","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Clone and Install Diarizers (No Dependency Overrides)**\n\nThis cell clones the HuggingFace `diarizers` repository into a separate directory and installs it in editable mode without modifying existing dependencies.","metadata":{}},{"cell_type":"code","source":"!git clone https://github.com/huggingface/diarizers.git hf_diarizers\n!pip install --no-deps -e /kaggle/working/hf_diarizers","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Install Audio Augmentation and Denoising Libraries**\n\nThis cell installs `audiomentations` and `denoiser` under the defined constraints to support data augmentation and optional speech enhancement during diarization training.","metadata":{}},{"cell_type":"code","source":"!pip install -c /kaggle/working/constraints.txt audiomentations","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -c /kaggle/working/constraints.txt denoiser","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Install Demucs and Fix Hydra Dependencies**\n\nThis cell installs `demucs` under the defined constraints and reinstalls compatible versions of `omegaconf` and `hydra-core` to preserve the expected module structure used by many audio and diarization repositories.","metadata":{}},{"cell_type":"code","source":"!pip install -c /kaggle/working/constraints.txt demucs","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip uninstall -y omegaconf hydra-core\n\n# Install versions that keep the old module layout expected by many audio repos\n!pip install -c /kaggle/working/constraints.txt --no-cache-dir --force-reinstall \"omegaconf==2.3.0\" \"hydra-core==1.3.2\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Execution Note**\n\n## Click **'Restart & Clear Cell Outputs'** and then start executing **only from the cells below**. **Do not** rerun the previous cells. .","metadata":{}},{"cell_type":"code","source":"import diarizers\nfrom diarizers.models import SegmentationModel","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-22T05:59:18.960178Z","iopub.execute_input":"2026-02-22T05:59:18.960445Z","iopub.status.idle":"2026-02-22T05:59:50.695442Z","shell.execute_reply.started":"2026-02-22T05:59:18.96042Z","shell.execute_reply":"2026-02-22T05:59:50.694873Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Verify Diarizers Installation**\n\nThis cell confirms that the `diarizers` package is correctly installed and imports the `SegmentationModel` to ensure the training environment is properly configured.","metadata":{}},{"cell_type":"code","source":"import diarizers\nprint(\"Loaded from:\", diarizers.__file__)\n\nfrom diarizers.models import SegmentationModel\nprint(\"OK:\", SegmentationModel)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-22T05:59:54.954241Z","iopub.execute_input":"2026-02-22T05:59:54.955034Z","iopub.status.idle":"2026-02-22T05:59:54.96046Z","shell.execute_reply.started":"2026-02-22T05:59:54.954995Z","shell.execute_reply":"2026-02-22T05:59:54.959484Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Setup Imports and Paths for Inference**\n\nThis cell loads the required libraries and defines the test audio directory, fine-tuned model path, and output CSV filename for running diarization inference.","metadata":{}},{"cell_type":"code","source":"import os\nimport sys\nimport json\nimport shutil\nimport pathlib\nimport subprocess\nimport torch\nimport torchaudio\nimport pandas as pd\nfrom tqdm import tqdm\nimport subprocess, sys, pathlib\n\nfrom pyannote.audio import Pipeline\nfrom pyannote.audio.pipelines.utils.hook import ProgressHook\n\nimport torch\nfrom torch.torch_version import TorchVersion\n\n\nTEST_DIR = \"/kaggle/input/competitions/dl-sprint-4-0-bengali-speaker-diarization-challenge/diarization/diarization/test/audio\"\nMODEL_PATH = \"/kaggle/input/models/arpitamallik23/823-olt-diarization-final-model/pytorch/default/1\"\nOUTPUT_CSV = \"diarization_final_submission.csv\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-22T05:59:58.054149Z","iopub.execute_input":"2026-02-22T05:59:58.054889Z","iopub.status.idle":"2026-02-22T05:59:58.060313Z","shell.execute_reply.started":"2026-02-22T05:59:58.054844Z","shell.execute_reply":"2026-02-22T05:59:58.05967Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Demucs Vocal Separation Utility**\n\nThis cell defines a helper function that runs Demucs (`htdemucs`) to extract the vocal stem from an input audio file, includes detailed error logging for debugging, and returns the path to the separated vocals file for downstream diarization inference.","metadata":{}},{"cell_type":"code","source":"# -------------------------\n# Demucs\n# -------------------------\n\ndemucs_out_dir = \"/kaggle/working/demucs_out\"\nos.makedirs(demucs_out_dir, exist_ok=True)\n\n\ndef demucs_two_stem_vocals(in_wav_path, demucs_out_dir=demucs_out_dir):\n    os.makedirs(demucs_out_dir, exist_ok=True)\n\n    cmd = [\n        sys.executable, \"-m\", \"demucs\",\n        \"-n\", \"htdemucs\",\n        \"--two-stems\", \"vocals\",\n        \"-o\", demucs_out_dir,\n        \"--filename\", \"{track}/{stem}.{ext}\", \n        in_wav_path\n    ]\n\n    # capture output so we can print error details\n    p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)\n\n    if p.returncode != 0:\n        print(\"\\nDEMUCS FAILED:\", in_wav_path)\n        print(\"CMD:\", \" \".join(cmd))\n        print(\"\\n--- STDOUT (tail) ---\\n\", p.stdout[-3000:])\n        print(\"\\n--- STDERR (tail) ---\\n\", p.stderr[-6000:])\n        raise RuntimeError(\"Demucs failed (see logs above).\")\n\n    track_name = pathlib.Path(in_wav_path).stem\n    vocals_path = f\"{demucs_out_dir}/htdemucs/{track_name}/vocals.wav\"\n\n    if not os.path.exists(vocals_path):\n        # sometimes demucs naming differs; list what it produced\n        produced_dir = f\"{demucs_out_dir}/htdemucs/{track_name}\"\n        print(\"Expected vocals not found. Produced files:\", produced_dir)\n        if os.path.exists(produced_dir):\n            print(os.listdir(produced_dir))\n        raise FileNotFoundError(f\"Missing expected output: {vocals_path}\")\n\n    return vocals_path","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-22T06:00:01.598436Z","iopub.execute_input":"2026-02-22T06:00:01.599047Z","iopub.status.idle":"2026-02-22T06:00:01.605445Z","shell.execute_reply.started":"2026-02-22T06:00:01.59901Z","shell.execute_reply":"2026-02-22T06:00:01.604696Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Run Diarization Inference and Generate Submission**\n\nThis cell loads the diarization pipeline, replaces its segmentation model with the fine-tuned checkpoint, runs inference over all test audio (optionally using Demucs vocal separation), and writes the final diarization results to the submission CSV.\n\n### remember to turn on the GPU.","metadata":{}},{"cell_type":"code","source":"# -------------------------\n# Make diarizers visible\n# -------------------------\nSRC = \"/kaggle/working/diarizers/src\"\nif SRC not in sys.path:\n    sys.path.insert(0, SRC)\n\nfor k in list(sys.modules.keys()):\n    if k == \"diarizers\" or k.startswith(\"diarizers.\"):\n        del sys.modules[k]\n\nfrom diarizers.models import SegmentationModel\n\ndevice = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n\n# -------------------------\n# Load pipeline\n# -------------------------\npipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\")\n\npipeline.to(device)\nprint(\"Pipeline loaded successfully on\", device)\n\nft_model = SegmentationModel.from_pretrained(MODEL_PATH)\nft_model = ft_model.to_pyannote_model().to(device)\npipeline._segmentation.model = ft_model\n\nresults = []\n\nfor filename in tqdm(sorted(os.listdir(TEST_DIR))):\n    if not filename.endswith(\".wav\"):\n        continue\n\n    file_path = os.path.join(TEST_DIR, filename)\n    file_id = os.path.splitext(filename)[0]\n\n    try:\n        vocals_path = demucs_two_stem_vocals(file_path)\n\n        waveform, sample_rate = torchaudio.load(vocals_path)\n        waveform = waveform.to(device)\n\n        with ProgressHook() as hook:\n            output = pipeline({\"waveform\": waveform, \"sample_rate\": sample_rate}, hook=hook)\n\n        annotation = output\n\n        segments = []\n        for seg, _, speaker in annotation.itertracks(yield_label=True):\n            segments.append({\n                \"start_time\": int(round(seg.start)),\n                \"end_time\": int(round(seg.end)),\n                \"speaker_id\": speaker\n            })\n\n        results.append({\"filename\": file_id, \"diarization\": json.dumps(segments)})\n\n    finally:\n        track_folder = f\"{demucs_out_dir}/htdemucs/{file_id}\"\n        if os.path.exists(track_folder):\n            shutil.rmtree(track_folder, ignore_errors=True)\n        if torch.cuda.is_available():\n            torch.cuda.empty_cache()\n\n\n# -------------------------\n# Submission\n# -------------------------\ndf_submission = pd.DataFrame(results)\ndf_submission.to_csv(OUTPUT_CSV, index=False)\nprint(\"Saved:\", OUTPUT_CSV)\ndf_submission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-22T06:00:13.520458Z","iopub.execute_input":"2026-02-22T06:00:13.520824Z","iopub.status.idle":"2026-02-22T07:11:31.942303Z","shell.execute_reply.started":"2026-02-22T06:00:13.52079Z","shell.execute_reply":"2026-02-22T07:11:31.941677Z"}},"outputs":[],"execution_count":null}]}