diff --git a/pyannote/audio/tasks/segmentation/speaker_diarization.py b/pyannote/audio/tasks/segmentation/speaker_diarization.py index 1094672ed..047c3a5eb 100644 --- a/pyannote/audio/tasks/segmentation/speaker_diarization.py +++ b/pyannote/audio/tasks/segmentation/speaker_diarization.py @@ -446,6 +446,7 @@ def segmentation_loss( if self.weigh_by_cardinality else None ) + seg_loss = nll_loss( permutated_prediction, torch.argmax(target, dim=-1), @@ -548,6 +549,12 @@ def training_step(self, batch, batch_idx: int): warm_up_right = round(self.warm_up[1] / self.duration * num_frames) weight[:, num_frames - warm_up_right :] = 0.0 + latency = 0.1 # will be a parameter of the task (in s) + delay = int(np.floor(num_frames * latency / self.duration)) # round down + + prediction = prediction[:, delay:, :] + target = target[:, :num_frames-delay, :] + if self.specifications.powerset: multilabel = self.model.powerset.to_multilabel(prediction) permutated_target, _ = permutate(multilabel, target) diff --git a/pyannote/audio/torchmetrics/audio/diarization_error_rate.py b/pyannote/audio/torchmetrics/audio/diarization_error_rate.py index 70cdc052f..fe1e8752d 100644 --- a/pyannote/audio/torchmetrics/audio/diarization_error_rate.py +++ b/pyannote/audio/torchmetrics/audio/diarization_error_rate.py @@ -49,10 +49,11 @@ class DiarizationErrorRate(Metric): higher_is_better = False is_differentiable = False - def __init__(self, threshold: float = 0.5): + def __init__(self, threshold: float = 0.5, per_frame: bool = False): super().__init__() self.threshold = threshold + self.per_frame = per_frame self.add_state("false_alarm", default=torch.tensor(0.0), dist_reduce_fx="sum") self.add_state( @@ -85,14 +86,17 @@ def update( speech_total : torch.Tensor Diarization error rate components accumulated over the whole batch. """ - - false_alarm, missed_detection, speaker_confusion, speech_total = _der_update( + if self.per_frame: + self.false_alarm, self.missed_detection, self.speaker_confusion, self.speech_total = _der_update(preds, target, + per_frame = self.per_frame, threshold=self.threshold) + else: + false_alarm, missed_detection, speaker_confusion, speech_total = _der_update( preds, target, threshold=self.threshold - ) - self.false_alarm += false_alarm - self.missed_detection += missed_detection - self.speaker_confusion += speaker_confusion - self.speech_total += speech_total + ) + self.false_alarm += false_alarm + self.missed_detection += missed_detection + self.speaker_confusion += speaker_confusion + self.speech_total += speech_total def compute(self): return _der_compute( @@ -100,6 +104,7 @@ def compute(self): self.missed_detection, self.speaker_confusion, self.speech_total, + self.per_frame ) diff --git a/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py b/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py index 9502a527e..840e9df98 100644 --- a/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py +++ b/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py @@ -32,6 +32,7 @@ def _der_update( preds: torch.Tensor, target: torch.Tensor, + per_frame: bool = False, threshold: Union[torch.Tensor, float] = 0.5, ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """Compute components of diarization error rate @@ -53,7 +54,6 @@ def _der_update( speech_total : torch.Tensor Diarization error rate components accumulated over the whole batch. """ - # make threshold a (num_thresholds,) tensor scalar_threshold = isinstance(threshold, Number) if scalar_threshold: @@ -86,6 +86,9 @@ def _der_update( speaker_confusion = torch.sum((hypothesis != target) * hypothesis, 1) - false_alarm # (batch_size, num_frames, num_thresholds) + + if per_frame: + return torch.sum(false_alarm, 0)[:,0], torch.sum(missed_detection, 0)[:,0], torch.sum(speaker_confusion, 0)[:,0], 1.0 * torch.sum(target) false_alarm = torch.sum(torch.sum(false_alarm, 1), 0) missed_detection = torch.sum(torch.sum(missed_detection, 1), 0) @@ -107,6 +110,7 @@ def _der_compute( missed_detection: torch.Tensor, speaker_confusion: torch.Tensor, speech_total: torch.Tensor, + per_frame: bool = False, ) -> torch.Tensor: """Compute diarization error rate from its components @@ -123,7 +127,8 @@ def _der_compute( der : (num_thresholds, )-shaped torch.Tensor Diarization error rate. """ - + if per_frame: + return false_alarm, missed_detection, speaker_confusion, speech_total return (false_alarm + missed_detection + speaker_confusion) / (speech_total + 1e-8) diff --git a/pyannote/audio/utils/loss.py b/pyannote/audio/utils/loss.py index 2c55b26f3..c6f8a3db7 100644 --- a/pyannote/audio/utils/loss.py +++ b/pyannote/audio/utils/loss.py @@ -155,7 +155,7 @@ def nll_loss( num_classes = prediction.shape[2] losses = F.nll_loss( - prediction.view(-1, num_classes), + prediction.reshape(-1, num_classes), # (batch_size x num_frames, num_classes) target.view(-1), # (batch_size x num_frames, ) diff --git a/tutorials/Notebook_test.ipynb b/tutorials/Notebook_test.ipynb new file mode 100644 index 000000000..79204b1f0 --- /dev/null +++ b/tutorials/Notebook_test.ipynb @@ -0,0 +1,735 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Protocol" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'AMI.SpeakerDiarization.only_words' found in /home/brahou/pyannote-audio/tutorials/AMI-diarization-setup/pyannote/database.yml does not define the 'scope' of speaker labels (file, database, or global). Setting it to 'file'.\n", + "'AMI.SpeakerDiarization.word_and_vocalsounds' found in /home/brahou/pyannote-audio/tutorials/AMI-diarization-setup/pyannote/database.yml does not define the 'scope' of speaker labels (file, database, or global). Setting it to 'file'.\n" + ] + } + ], + "source": [ + "from pyannote.core import notebook, Segment\n", + "notebook.reset()\n", + "from pyannote.database import registry\n", + "registry.load_database(\"AMI-diarization-setup/pyannote/database.yml\")\n", + "from pyannote.database import FileFinder\n", + "protocol = registry.get_protocol('AMI.SpeakerDiarization.only_words', \n", + " preprocessors={\"audio\": FileFinder()})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/brahou/pyannote-audio/pyannote/audio/core/io.py:43: UserWarning: torchaudio._backend.set_audio_backend has been deprecated. With dispatcher enabled, this function is no-op. You can remove the function call.\n", + " torchaudio.set_audio_backend(\"soundfile\")\n", + "/home/brahou/anaconda3/lib/python3.11/site-packages/torch_audiomentations/utils/io.py:27: UserWarning: torchaudio._backend.set_audio_backend has been deprecated. With dispatcher enabled, this function is no-op. You can remove the function call.\n", + " torchaudio.set_audio_backend(\"soundfile\")\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Protocol AMI.SpeakerDiarization.only_words does not precompute the output of torchaudio.info(): adding a 'torchaudio.info' preprocessor for you to speed up dataloaders. See pyannote.database documentation on how to do that yourself.\n" + ] + } + ], + "source": [ + "from pyannote.audio.tasks import SpeakerDiarization\n", + "diarization_task = SpeakerDiarization(protocol, duration=5, batch_size=256, max_speakers_per_frame = 2,\n", + " max_speakers_per_chunk = 3, num_workers = 0)\n", + "\n", + "from pyannote.audio.models.segmentation import PyanNet\n", + "model = PyanNet(task=diarization_task, lstm = {\n", + " \"hidden_size\": 128,\n", + " \"num_layers\": 2,\n", + " \"bidirectional\": True,\n", + " \"monolithic\": True,\n", + " \"dropout\": 0.0,\n", + " })\n", + "#If you infer without training\n", + "model.setup(stage = 'fit')\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [], + "source": [ + "#batches = iter(model.train_dataloader())" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "#%timeit next(batches)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "#import pytorch_lightning as pl\n", + "#trainer = pl.Trainer(max_epochs=1,accelerator='gpu', devices=[0])\n", + "#trainer.fit(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "from pyannote.audio import Model\n", + "pretrained_model = Model.from_pretrained(\"pyannote/segmentation-3.0\", use_auth_token=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "#import torch\n", + "#model.load_state_dict(torch.load('model.pt'), strict = False)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from pyannote.audio import Inference\n", + "from pyannote.audio.torchmetrics import DiarizationErrorRate\n", + "import numpy as np\n", + "import torch\n", + "from rich.progress import Progress\n", + "\n", + "\n", + "def test_torchmetrics(model, files, latency):\n", + " with Progress() as progress:\n", + " main_task = progress.add_task(protocol.name, total=len(files))\n", + " file_task = progress.add_task(\"Processing\", total=1.0)\n", + " \n", + " def progress_hook(completed: int = None, total: int = None):\n", + " progress.update(file_task, completed=completed / total) \n", + "\n", + " inference = Inference(model)\n", + " metric = DiarizationErrorRate()\n", + " num_frames = model.example_output.num_frames\n", + " delay = int(np.floor(latency / model.example_output.frames.duration)) # round down\n", + " print(f\"delay : {delay:d} frame(s)\")\n", + "\n", + " # initialize error list\n", + " error=[]\n", + " for file in files:\n", + " progress.update(file_task, description=file[\"uri\"])\n", + " # calculate inference for current file\n", + " window_inference = inference(file)\n", + " hypothesis = torch.from_numpy(window_inference.data)\n", + "\n", + " # discretize reference annotation\n", + " annotation = file[\"annotation\"]\n", + " sliding_window = window_inference.sliding_window\n", + " support = Segment(sliding_window[0].start, sliding_window[hypothesis.size(0) - 1].end)\n", + " resolution = sliding_window.duration / num_frames\n", + " discretization = annotation.discretize(support, resolution=resolution)\n", + " max_num_speaker = len(annotation.labels())\n", + " reference = torch.zeros((hypothesis.size(0),hypothesis.size(1),max_num_speaker))\n", + " for i in range(hypothesis.size(0)):\n", + " reference_window = discretization.crop(sliding_window[i], mode=\"center\")\n", + " reference[i] = torch.from_numpy(np.array(reference_window.data))[:num_frames]\n", + "\n", + " # pad the hypothesis and permute the inputs (torchmetrics takes (num_chunks,num_speakers,num_frames))\n", + " if reference.size(2) > hypothesis.size(2):\n", + " hypothesis = torch.nn.functional.pad(hypothesis, (0, 1, 0, 0, 0, 0))\n", + " hypothesis = hypothesis.permute(0,2,1)\n", + " reference = reference.permute(0,2,1)\n", + " print(f\"hypothesis of size : {hypothesis[:,:,delay:].size()}\")\n", + " print(f\"reference of size : {reference[:,:,:num_frames-delay].size()}\")\n", + "\n", + " error.append(metric(hypothesis[:,:,delay:], reference[:,:,:num_frames-delay]))\n", + " print(f\"current error list : {error}\")\n", + " progress.advance(main_task)\n", + " return np.array(error).mean()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "from pyannote.audio import Inference\n", + "from pyannote.audio.torchmetrics import DiarizationErrorRate\n", + "import numpy as np\n", + "import torch\n", + "from rich.progress import Progress\n", + "\n", + "def test_torchmetrics_per_frame(model, files, latency):\n", + " \n", + " inference = Inference(model)\n", + " metric = DiarizationErrorRate(per_frame = True)\n", + " num_frames = model.example_output.num_frames\n", + " delay = int(np.floor(latency / model.example_output.frames.duration)) # round down\n", + " print(f\"delay : {delay:d} frame(s)\")\n", + " \n", + " # initialize error lists\n", + " error=[]\n", + " false_alarm_error=[]\n", + " missed_detection_error=[]\n", + " speaker_confusion_error=[]\n", + " \n", + " for file in files:\n", + " # calculate inference for current file\n", + " window_inference = inference(file)\n", + " hypothesis = torch.from_numpy(window_inference.data)\n", + " \n", + " # discretize reference annotation\n", + " annotation = file[\"annotation\"]\n", + " sliding_window = window_inference.sliding_window\n", + " support = Segment(sliding_window[0].start, sliding_window[hypothesis.size(0) - 1].end)\n", + " resolution = sliding_window.duration / num_frames\n", + " discretization = annotation.discretize(support, resolution=resolution)\n", + " max_num_speaker = len(annotation.labels())\n", + " reference = torch.zeros((hypothesis.size(0),hypothesis.size(1),max_num_speaker))\n", + " for i in range(hypothesis.size(0)):\n", + " reference_window = discretization.crop(sliding_window[i], mode=\"center\")\n", + " reference[i] = torch.from_numpy(np.array(reference_window.data))[:num_frames]\n", + " \n", + " # permute the inputs (torchmetrics takes (num_chunks,num_speakers,num_frames))\n", + " hypothesis = torch.nn.functional.pad(hypothesis, (0, 1, 0, 0, 0, 0))\n", + " hypothesis = hypothesis.permute(0,2,1)\n", + " reference = reference.permute(0,2,1)\n", + " print(f\"hypothesis of size : {hypothesis[:,:,delay:].size()}\")\n", + " print(f\"reference of size : {reference[:,:,:num_frames-delay].size()}\")\n", + " \n", + " # calculate the metrics\n", + " false_alarm, missed_detection, speaker_confusion, total_speech = metric(\n", + " hypothesis[:,:,delay:], reference[:,:,:num_frames-delay])\n", + " print(f\"DER for this file = {(false_alarm.sum() + missed_detection.sum() + speaker_confusion.sum()) / (total_speech + 1e-8)}\")\n", + " false_alarm_per_frame = false_alarm * num_frames / (total_speech + 1e-8)\n", + " missed_detection_per_frame = missed_detection * num_frames / (total_speech + 1e-8)\n", + " speaker_confusion_per_frame = speaker_confusion * num_frames / (total_speech + 1e-8)\n", + " der_per_frame = false_alarm_per_frame + missed_detection_per_frame + speaker_confusion_per_frame\n", + " \n", + " # append the list of errors with current file errors\n", + " error.append(np.array(der_per_frame))\n", + " false_alarm_error.append(np.array(false_alarm_per_frame))\n", + " missed_detection_error.append(np.array(missed_detection_per_frame))\n", + " speaker_confusion_error.append(np.array(speaker_confusion_per_frame))\n", + " \n", + " # calculate mean of all test files \n", + " error=np.array(error).mean(axis = 0)\n", + " false_alarm_error = np.array(false_alarm_error).mean(axis = 0)\n", + " missed_detection_error = np.array(missed_detection_error).mean(axis = 0)\n", + " speaker_confusion_error = np.array(speaker_confusion_error).mean(axis = 0)\n", + " \n", + " return error, false_alarm_error, missed_detection_error, speaker_confusion_error" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bbe7edda52ac4d1b9355fe13cf44820b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
delay : 0 frame(s)\n",
+       "
\n" + ], + "text/plain": [ + "delay : 0 frame(s)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
hypothesis of size : torch.Size([1669, 4, 293])\n",
+       "
\n" + ], + "text/plain": [ + "hypothesis of size : torch.Size([1669, 4, 293])\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
reference of size : torch.Size([1669, 4, 293])\n",
+       "
\n" + ], + "text/plain": [ + "reference of size : torch.Size([1669, 4, 293])\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
current error list : [tensor(0.2593)]\n",
+       "
\n" + ], + "text/plain": [ + "current error list : [tensor(0.2593)]\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Local DER = 25.9%\n" + ] + } + ], + "source": [ + "files = list(getattr(protocol, \"test\")())\n", + "latency = 0\n", + "der = test_torchmetrics(model, files, latency)\n", + "print(f\"Local DER = {abs(der) * 100:.1f}%\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "delay : 0 frame(s)\n", + "hypothesis of size : torch.Size([1669, 4, 293])\n", + "reference of size : torch.Size([1669, 4, 293])\n", + "DER for this file = 0.25927138328552246\n", + "hypothesis of size : torch.Size([4096, 4, 293])\n", + "reference of size : torch.Size([4096, 4, 293])\n", + "DER for this file = 0.15371479094028473\n", + "hypothesis of size : torch.Size([3633, 4, 293])\n", + "reference of size : torch.Size([3633, 4, 293])\n", + "DER for this file = 0.14838285744190216\n", + "hypothesis of size : torch.Size([3880, 4, 293])\n", + "reference of size : torch.Size([3880, 4, 293])\n", + "DER for this file = 0.24103473126888275\n", + "hypothesis of size : torch.Size([2090, 4, 293])\n", + "reference of size : torch.Size([2090, 4, 293])\n", + "DER for this file = 0.26910367608070374\n", + "hypothesis of size : torch.Size([4682, 4, 293])\n", + "reference of size : torch.Size([4682, 4, 293])\n", + "DER for this file = 0.19512279331684113\n", + "hypothesis of size : torch.Size([4660, 4, 293])\n", + "reference of size : torch.Size([4660, 4, 293])\n", + "DER for this file = 0.196478009223938\n", + "hypothesis of size : torch.Size([4436, 4, 293])\n", + "reference of size : torch.Size([4436, 4, 293])\n", + "DER for this file = 0.2791493833065033\n", + "hypothesis of size : torch.Size([3003, 4, 293])\n", + "reference of size : torch.Size([3003, 4, 293])\n", + "DER for this file = 0.21955639123916626\n", + "hypothesis of size : torch.Size([4412, 4, 293])\n", + "reference of size : torch.Size([4412, 4, 293])\n", + "DER for this file = 0.1819673478603363\n", + "hypothesis of size : torch.Size([5131, 4, 293])\n", + "reference of size : torch.Size([5131, 4, 293])\n", + "DER for this file = 0.20070508122444153\n", + "hypothesis of size : torch.Size([5228, 4, 293])\n", + "reference of size : torch.Size([5228, 4, 293])\n", + "DER for this file = 0.3011073172092438\n", + "hypothesis of size : torch.Size([4277, 4, 293])\n", + "reference of size : torch.Size([4277, 4, 293])\n", + "DER for this file = 0.32932376861572266\n", + "hypothesis of size : torch.Size([3565, 4, 293])\n", + "reference of size : torch.Size([3565, 4, 293])\n", + "DER for this file = 0.30412614345550537\n", + "hypothesis of size : torch.Size([5936, 4, 293])\n", + "reference of size : torch.Size([5936, 3, 293])\n", + "DER for this file = 0.2846376597881317\n", + "hypothesis of size : torch.Size([4411, 4, 293])\n", + "reference of size : torch.Size([4411, 4, 293])\n", + "DER for this file = 0.3492230176925659\n" + ] + }, + { + "data": { + "text/plain": [ + "array([0.33141226, 0.32828283, 0.3254712 , 0.32385397, 0.32102078,\n", + " 0.31781587, 0.31483144, 0.3118828 , 0.3095508 , 0.30769417,\n", + " 0.30492172, 0.30279967, 0.30185664, 0.3003403 , 0.29950818,\n", + " 0.2974546 , 0.29643768, 0.2952635 , 0.2943591 , 0.2934955 ,\n", + " 0.29226917, 0.29182842, 0.28979072, 0.28865463, 0.28763038,\n", + " 0.28585577, 0.2846649 , 0.2832142 , 0.28189656, 0.28114805,\n", + " 0.27901095, 0.27710798, 0.27613223, 0.27480465, 0.2739618 ,\n", + " 0.27200747, 0.2700129 , 0.26821354, 0.26670614, 0.2651845 ,\n", + " 0.2638062 , 0.26239705, 0.26102602, 0.25953332, 0.2591208 ,\n", + " 0.25828105, 0.2570774 , 0.2559183 , 0.25584063, 0.25441644,\n", + " 0.25364774, 0.2519333 , 0.2509564 , 0.25014085, 0.24833299,\n", + " 0.24697796, 0.24619237, 0.24567632, 0.24573608, 0.24532034,\n", + " 0.24451478, 0.24479821, 0.24377097, 0.24390468, 0.24280521,\n", + " 0.2421332 , 0.24140316, 0.24052833, 0.23971869, 0.23828493,\n", + " 0.23733024, 0.23671696, 0.23572822, 0.23477092, 0.23483257,\n", + " 0.23470238, 0.23381706, 0.23352832, 0.23248194, 0.23244005,\n", + " 0.23191895, 0.23056792, 0.23067129, 0.22970879, 0.22897042,\n", + " 0.22844109, 0.22814372, 0.2281976 , 0.22832845, 0.22790605,\n", + " 0.22724718, 0.22683671, 0.22714718, 0.22620751, 0.2261574 ,\n", + " 0.22560719, 0.22536096, 0.22467043, 0.22339903, 0.22351626,\n", + " 0.22290963, 0.2221011 , 0.221811 , 0.22127423, 0.22140059,\n", + " 0.22096576, 0.22094062, 0.21971132, 0.21941712, 0.21886246,\n", + " 0.21794213, 0.21799375, 0.21791717, 0.21776289, 0.21730742,\n", + " 0.21689726, 0.21737412, 0.21717627, 0.21763906, 0.21722978,\n", + " 0.21712679, 0.2172139 , 0.21662505, 0.2162188 , 0.21584177,\n", + " 0.21599226, 0.2156428 , 0.2144337 , 0.21447644, 0.21455246,\n", + " 0.21390632, 0.21364939, 0.21381284, 0.21428956, 0.21387157,\n", + " 0.21350878, 0.21355487, 0.2128605 , 0.21283644, 0.21259557,\n", + " 0.21243428, 0.21266854, 0.21199487, 0.21181758, 0.21200636,\n", + " 0.2116846 , 0.21187645, 0.21240513, 0.2130516 , 0.21303566,\n", + " 0.21281463, 0.21330939, 0.21278341, 0.21276967, 0.21349609,\n", + " 0.2140504 , 0.2140244 , 0.21345386, 0.21307206, 0.21299285,\n", + " 0.21363075, 0.21332927, 0.2138904 , 0.21424842, 0.21428452,\n", + " 0.2149067 , 0.21462873, 0.21488793, 0.21478772, 0.21447697,\n", + " 0.21527193, 0.2145139 , 0.2143711 , 0.21494722, 0.21588585,\n", + " 0.21638153, 0.2170032 , 0.21727371, 0.21760772, 0.21724796,\n", + " 0.2179234 , 0.21791705, 0.21777347, 0.2189023 , 0.220375 ,\n", + " 0.22009227, 0.21989672, 0.2195742 , 0.22005339, 0.22005624,\n", + " 0.2200972 , 0.22042753, 0.22141808, 0.22161743, 0.22222513,\n", + " 0.22201827, 0.22299126, 0.22290714, 0.22261173, 0.22326928,\n", + " 0.22358622, 0.22328378, 0.22379616, 0.22481851, 0.2259741 ,\n", + " 0.22653295, 0.22694038, 0.22720665, 0.22725053, 0.22805731,\n", + " 0.22841386, 0.22888723, 0.22907071, 0.23003177, 0.23025626,\n", + " 0.23097122, 0.23100737, 0.23167296, 0.23189557, 0.23287718,\n", + " 0.23242202, 0.23350279, 0.23474258, 0.23566872, 0.23595695,\n", + " 0.2362484 , 0.23680899, 0.23641714, 0.23713154, 0.23838924,\n", + " 0.23718446, 0.2376921 , 0.2394906 , 0.24025609, 0.24090442,\n", + " 0.24237992, 0.2427249 , 0.24297021, 0.24407573, 0.24501283,\n", + " 0.24509661, 0.24581507, 0.24699542, 0.24790806, 0.24876504,\n", + " 0.24916984, 0.24964936, 0.25082186, 0.25161406, 0.25240988,\n", + " 0.25344747, 0.2545621 , 0.2552997 , 0.2570173 , 0.25769967,\n", + " 0.2583722 , 0.25973082, 0.26096007, 0.26157868, 0.2620245 ,\n", + " 0.26331863, 0.2649801 , 0.26681465, 0.2678213 , 0.2693782 ,\n", + " 0.27037668, 0.27147996, 0.27291638, 0.27446246, 0.2756156 ,\n", + " 0.27669254, 0.27759477, 0.27955914, 0.2804497 , 0.2808544 ,\n", + " 0.2821845 , 0.28436345, 0.2855499 , 0.28686047, 0.28862983,\n", + " 0.29075706, 0.29199818, 0.2939653 , 0.2955644 , 0.2973317 ,\n", + " 0.29890612, 0.3008567 , 0.30361935, 0.30643216, 0.30874175,\n", + " 0.3112345 , 0.31372193, 0.3135783 ], dtype=float32)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "files = list(getattr(protocol, \"test\")())\n", + "latency = 0\n", + "error_per_frame, false_alarm, missed_detection, speaker_confusion = test_torchmetrics_per_frame(model, files, latency)\n", + "error_per_frame" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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wxEbG2t63L59+7m3T0RERERFg0k6gNatWyM2Ntb0/3fffYeYmBjT/9HR0QgODs5zfc7OzpDL5VlazaOiorK0rr8ImUyG1157LdeWdLVaDVtbW7MHERERERVvTNIBbN261azf9uTJk/Ho0SPT/3q9HpcvX85zfSqVCtWrV8f27dvNlm/fvh116tR58YD/RwiB0NBQeHh4FFidRERERGR5HDiKjGQ3t/+fx9ChQ9GzZ0/UqFEDtWvXxpw5cxAeHo5+/foByOiGcvfuXSxatMi0TmhoKICMwaEPHjxAaGgoVCqVqRV/3LhxqFWrFgIDAxEXF4cZM2YgNDQUv/766wvHS0RERETFB5P0QtKlSxdER0dj/PjxiIiIQMWKFbFp0yb4+PgAyLh50dNzpj85S8uJEyewdOlS+Pj4ICwsDAAQExODjz76CJGRkbCzs0PVqlWxb98+vP7660W2X0RERERU+CRREM3GL7nM/uMuLi4AABsbG5w5cwZ+fn4AgPv378PT07NA70ZqKXFxcbCzs0NsbGzB90/f+AVw7I+CrZOIiOhl0mkhUKF9gVdbqJ/fVCyxJR0Z3Vv69OkDtVoNAEhJSUG/fv1MNzN6sr86EREREVFhY5IOoHfv3mb/9+jRI0uZXr16FVU4RERERFTCMUkHMH/+fEuHQERERERkwikYiYiIiIiKGSbpRERERETFDJN0IiIiIqJihkk6EREREVExwySdiIiIiKiYYZJORERERFTMMEknIiIiIipmmKQTERERERUzTNKJiIiIiIoZJulERERERMUMk3QiIiIiomKGSToRERERUTHDJJ2IiIiIqJhhkk5EREREVMwwSSciIiIiKmaYpBMRERERFTNM0omIiIiIihkm6URERERExQyTdCIiIiKiYoZJOhERERFRMcMknYiIiIiomGGSTkRERERUzDBJJyIiIiIqZpikExEREREVM0zSiYiIiIiKGSbpRERERETFDJN0IiIiIqJihkk6EREREVExwySdiIiIiKiYYZJORERERFTMMEknIiIiIipmmKQTERERERUzTNKJiIiIiIoZJulERERERMUMk3QiIiIiomKGSToRERERUTHDJJ2IiIiIqJhhkk5EREREVMwwSSciIiIiKmaYpBeiWbNmwc/PDxqNBtWrV8f+/ftzLBsREYFu3bohKCgIMpkMgwcPzrbcP//8g+DgYKjVagQHB2PNmjWFFD0RERERWQqT9EKyYsUKDB48GCNGjMCpU6dQr149tGrVCuHh4dmWT01NhYuLC0aMGIGQkJBsyxw6dAhdunRBz549cfr0afTs2ROdO3fGkSNHCnNXiIiIiKiISUIIYekgXkU1a9ZEtWrVMHv2bNOy8uXLo3379pg0aVKu6zZs2BBVqlTBtGnTzJZ36dIFcXFx2Lx5s2lZy5Yt4eDggGXLluUprri4ONjZ2SE2Nha2trZ536G82PgFcOyPgq2TiIjoZdJpIVChfYFXW6if31QssSW9EKSlpeHEiRNo3ry52fLmzZvj4MGDz13voUOHstTZokWLF6qTiIiIiIofhaUDeBU9fPgQBoMBbm5uZsvd3NwQGRn53PVGRkbmu87U1FSkpqaa/o+Li3vu7RMRERFR0WBLeiGSJMnsfyFElmWFXeekSZNgZ2dnenh7e7/Q9omIiIio8DFJLwTOzs6Qy+VZWrijoqKytITnh7u7e77rHD58OGJjY02P27dvP/f2iYiIiKhoMEkvBCqVCtWrV8f27dvNlm/fvh116tR57npr166dpc5t27blWqdarYatra3Zg4iIiIiKN/ZJLyRDhw5Fz549UaNGDdSuXRtz5sxBeHg4+vXrByCjhfvu3btYtGiRaZ3Q0FAAQEJCAh48eIDQ0FCoVCoEBwcDAAYNGoT69etj8uTJaNeuHf7991/s2LEDBw4cKPL9IyIiIqLCwyS9kHTp0gXR0dEYP348IiIiULFiRWzatAk+Pj4AMm5e9PSc6VWrVjX9feLECSxduhQ+Pj4ICwsDANSpUwfLly/HyJEjMWrUKAQEBGDFihWoWbNmke0XERERERU+zpNewnCedCIiokLEedKpgLBPOhERERFRMcMknYiIiIiomGGSTkRERERUzDBJJyIiIiIqZpikExEREREVM0zSiYiIiIiKGSbpRERERETFDJN0IiIiIqJihkk6EREREVExwySdiIiIiKiYYZJORERERFTMMEknIiIiIipmmKQTERERERUzTNKJiIiIiIoZhaUDoFdLup0/vsBAnIi1QzuXCAzUL4D68RVLh0VERET0UmFLOhWo1Vad8e99V9xJUePX277omTwURq2TpcMiIiIieqkwSacCE6P2wOiwimbLjsbYYoz2awi5ykJREREREb18mKRTgVmY2gCpxqyn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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "frames = np.arange(error_per_frame.shape[0]) \n", + "\n", + "# Plot the stacked area plot\n", + "ax.plot(frames, error_per_frame, color=\"black\", label=\"Error rate\")\n", + "\n", + "ax.stackplot(frames, false_alarm, missed_detection, speaker_confusion, \n", + " labels=[\"Speaker confusion\", \"Missed detection\", \"False alarm\"])\n", + "\n", + "# Set axis labels and a title\n", + "ax.set_xlabel(\"Frames\")\n", + "ax.set_ylabel(\"Error rate\")\n", + "ax.set_title(\"Proportion of confusion, missed detection, and false alarm in the error rate (per frame)\")\n", + "ax.legend(loc='upper center')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.setup(stage = 'fit')\n", + "from pyannote.audio.pipelines import SpeakerDiarization\n", + "pipeline = SpeakerDiarization(model).instantiate({\n", + " \"segmentation\": {\n", + " \"min_duration_off\": 0.0,\n", + " },\n", + " \"clustering\": {\n", + " \"method\": \"centroid\",\n", + " \"min_cluster_size\": 2,\n", + " \"threshold\": 0.01,\n", + " },\n", + "})\n", + "files = list(getattr(protocol, \"test\")())\n", + "\n", + "from pyannote.audio.utils.preview import listen\n", + "listen(\"test_short.wav\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#from huggingface_hub import notebook_login\n", + "#notebook_login()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pyannote.audio import Pipeline\n", + "pretrained_pipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization\", use_auth_token=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "annotation = pipeline(\"test_short.wav\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(annotation.itertracks())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizing pipeline hyper-parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "W can try to optimize the hyper-parameters (that we chose manually above) on the validation set to get better performance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# to make things faster, we run the inference once and for all... \n", + "validation_files = list(protocol.development())\n", + "for file in validation_files:\n", + " file['osd'] = inference(file)\n", + "# ... and tell the pipeline to load OSD scores directly from files\n", + "pipeline = OverlappedSpeechDetectionPipeline(scores=\"osd\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pyannote.pipeline import Optimizer\n", + "optimizer = Optimizer(pipeline)\n", + "optimizer.tune(validation_files, n_iterations=200, show_progress=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There you go: better hyper-parameters that should lead to better results!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_pipeline = OverlappedSpeechDetectionPipeline(scores=inference).instantiate(optimizer.best_params)\n", + "optimized_pipeline(test_file).get_timeline()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pyannote.audio import Inference\n", + "from pyannote.audio.utils.metric import DiscreteDiarizationErrorRate\n", + "from pyannote.audio.utils.signal import binarize\n", + "from rich.progress import Progress\n", + "\n", + "#model.setup(stage = 'fit')\n", + "\n", + "def test_discrete(model, files): \n", + " inference = Inference(model)\n", + " metric = DiscreteDiarizationErrorRate()\n", + " for file in files[0:1]:\n", + " reference = file[\"annotation\"]\n", + " hypothesis = binarize(inference(file))\n", + " uem = file[\"annotated\"]\n", + " _ = metric(reference, hypothesis, uem=uem)\n", + " return metric\n", + " \n", + "files = list(getattr(protocol, \"train\")())\n", + "print(f\"Local DER = {abs(test_discrete(model, files)) * 100:.1f}%\")" + ] + } + ], + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}