diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000..6f024c73b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,56 @@
+name: Bug report
+description: Report a bug in pyannote.audio
+body:
+
+- type: markdown
+ attributes:
+ value: |
+ When reporting bugs, please follow the guidelines in this template. This helps identify the problem precisely and thus enables contributors to fix it faster.
+ - Write a descriptive issue title above.
+ - The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
+ - Search [open](https://github.com/pyannote/pyannote-audio/issues) and [closed](https://github.com/pyannote/pyannote-audio/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
+ - Please always check if your issue is reproducible in the latest version – it may already have been fixed!
+ - If you use a custom build, please test if your issue is reproducible in official releases too.
+
+- type: textarea
+ attributes:
+ label: Tested versions
+ description: |
+ To properly fix a bug, we need to identify if the bug was recently introduced in the engine, or if it was always present.
+ - Please specify the pyannote.audio version you found the issue in, including the **Git commit hash** if using a development build.
+ - If you can, **please test earlier pyannote.audio versions** and, if applicable, newer versions (development branch). Mention whether the bug is reproducible or not in the versions you tested.
+ - The aim is for us to identify whether a bug is a **regression**, i.e. an issue that didn't exist in a previous version, but was introduced later on, breaking existing functionality. For example, if a bug is reproducible in 3.2 but not in 3.0, we would like you to test intermediate 3.1 to find which version is the first one where the issue can be reproduced.
+ placeholder: |
+ - Reproducible in: 3.1, 3.2, and later
+ - Not reproducible in: 3.0
+ validations:
+ required: true
+
+- type: input
+ attributes:
+ label: System information
+ description: |
+ - Specify the OS version, and when relevant hardware information.
+ - For issues that are likely OS-specific and/or GPU-related, please specify the GPU model and architecture.
+ - **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
+ placeholder: macOS 13.6 - pyannote.audio 3.1.1 - M1 Pro
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Issue description
+ description: |
+ Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
+ You can include audio, images or videos with drag and drop, and format code blocks or logs with ```
tags.
+ validations:
+ required: true
+
+- type: input
+ attributes:
+ label: Minimal reproduction example (MRE)
+ description: |
+ Having reproducible issues is a prerequisite for contributors to be able to solve them.
+ Include a link to minimal reproduction example using [this Google Colab notebook](https://colab.research.google.com/github/pyannote/pyannote-audio/blob/develop/tutorials/MRE_template.ipynb) as a starting point.
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..84f6ea55a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,15 @@
+blank_issues_enabled: false
+
+contact_links:
+
+ - name: Feature request
+ url: https://github.com/pyannote/pyannote-audio/discussions
+ about: Suggest an idea for this project.
+
+ - name: Consulting
+ url: https://herve.niderb.fr/consulting
+ about: Using pyannote.audio in production? Make the most of it thanks to our consulting services.
+
+ - name: Premium models
+ url: https://forms.office.com/e/GdqwVgkZ5C
+ about: We are considering selling premium models, extensions, or services around pyannote.audio.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 4ead48053..000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: ''
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context about the feature request here.
diff --git a/.github/workflows/new_issue.yml b/.github/workflows/new_issue.yml
deleted file mode 100644
index b8477dc16..000000000
--- a/.github/workflows/new_issue.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: issues
-on:
- issues:
- types: [opened]
-jobs:
- add-comment:
- runs-on: ubuntu-latest
- permissions:
- issues: write
- steps:
- - uses: actions/checkout@v3
- with:
- ref: develop
- - name: Install FAQtory
- run: pip install FAQtory
- - name: Run Suggest
- env:
- TITLE: ${{ github.event.issue.title }}
- run: faqtory suggest "$TITLE" > suggest.md
- - name: Read suggest.md
- id: suggest
- uses: juliangruber/read-file-action@v1
- with:
- path: ./suggest.md
- - name: Suggest FAQ
- uses: peter-evans/create-or-update-comment@a35cf36e5301d70b76f316e867e7788a55a31dae
- with:
- issue-number: ${{ github.event.issue.number }}
- body: ${{ steps.suggest.outputs.content }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 90a4302c6..e649027ae 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -30,4 +30,4 @@ jobs:
pip install -e .[dev,testing]
- name: Test with pytest
run: |
- pytest
+ pytest -k "not test_cli.py"
diff --git a/.github/workflows/test_cli.yml b/.github/workflows/test_cli.yml
new file mode 100644
index 000000000..731a4b5b6
--- /dev/null
+++ b/.github/workflows/test_cli.yml
@@ -0,0 +1,33 @@
+name: CLI tests
+
+on:
+ push:
+ branches: [develop]
+ pull_request:
+ branches: [develop]
+
+jobs:
+ build:
+ timeout-minutes: 20
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest]
+ python-version: ["3.10"]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install libsndfile
+ if: matrix.os == 'ubuntu-latest'
+ run: |
+ sudo apt-get update
+ sudo apt-get install libsndfile1
+ - name: Install pyannote.audio
+ run: |
+ pip install -e .[dev,testing,cli]
+ - name: Test with pytest
+ run: |
+ pytest tests/test_cli.py
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 549e46ad0..92c952bdc 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,7 +14,7 @@ repos:
# Sort imports
- repo: https://github.com/PyCQA/isort
- rev: 5.10.1
+ rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black"]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 777f41f38..ad88762c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,40 @@
# Changelog
+## Version 3.2.0 (2024-05-08)
+
+### New features
+
+- feat(task): add option to cache task training metadata to speed up training (with [@clement-pages](https://github.com/clement-pages/))
+- feat(model): add `receptive_field`, `num_frames` and `dimension` to models (with [@Bilal-Rahou](https://github.com/Bilal-Rahou))
+- feat(model): add `fbank_only` property to `WeSpeaker` models
+- feat(util): add `Powerset.permutation_mapping` to help with permutation in powerset space (with [@FrenchKrab](https://github.com/FrenchKrab))
+- feat(sample): add sample file at `pyannote.audio.sample.SAMPLE_FILE`
+- feat(metric): add `reduce` option to `diarization_error_rate` metric (with [@Bilal-Rahou](https://github.com/Bilal-Rahou))
+- feat(pipeline): add `Waveform` and `SampleRate` preprocessors
+
+### Fixes
+
+- fix(task): fix random generators and their reproducibility (with [@FrenchKrab](https://github.com/FrenchKrab))
+- fix(task): fix estimation of training set size (with [@FrenchKrab](https://github.com/FrenchKrab))
+- fix(hook): fix `torch.Tensor` support in `ArtifactHook`
+- fix(doc): fix typo in `Powerset` docstring (with [@lukasstorck](https://github.com/lukasstorck))
+
+### Improvements
+
+- improve(metric): add support for number of speakers mismatch in `diarization_error_rate` metric
+- improve(pipeline): track both `Model` and `nn.Module` attributes in `Pipeline.to(device)`
+- improve(io): switch to `torchaudio >= 2.2.0`
+- improve(doc): update tutorials (with [@clement-pages](https://github.com/clement-pages/))
+
+## Breaking changes
+
+- BREAKING(model): get rid of `Model.example_output` in favor of `num_frames` method, `receptive_field` property, and `dimension` property
+- BREAKING(task): custom tasks need to be updated (see "Add your own task" tutorial)
+
+## Community contributions
+
+- community: add tutorial for offline use of `pyannote/speaker-diarization-3.1` (by [@simonottenhauskenbun](https://github.com/simonottenhauskenbun))
+
## Version 3.1.1 (2023-12-01)
### TL;DR
diff --git a/MANIFEST.in b/MANIFEST.in
index 16909925f..45ad7d6af 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,6 @@
recursive-include pyannote *.py
recursive-include pyannote *.yaml
+recursive-include pyannote *.wav
+recursive-include pyannote *.rttm
global-exclude *.pyc
global-exclude __pycache__
diff --git a/README.md b/README.md
index 49b976a1f..e1326816a 100644
--- a/README.md
+++ b/README.md
@@ -70,26 +70,30 @@ for turn, _, speaker in diarization.itertracks(yield_label=True):
- Videos
- [Introduction to speaker diarization](https://umotion.univ-lemans.fr/video/9513-speech-segmentation-and-speaker-diarization/) / JSALT 2023 summer school / 90 min
- [Speaker segmentation model](https://www.youtube.com/watch?v=wDH2rvkjymY) / Interspeech 2021 / 3 min
- - [First releaase of pyannote.audio](https://www.youtube.com/watch?v=37R_R82lfwA) / ICASSP 2020 / 8 min
+ - [First release of pyannote.audio](https://www.youtube.com/watch?v=37R_R82lfwA) / ICASSP 2020 / 8 min
+- Community contributions (not maintained by the core team)
+ - 2024-04-05 > [Offline speaker diarization (speaker-diarization-3.1)](tutorials/community/offline_usage_speaker_diarization.ipynb) by [Simon Ottenhaus](https://github.com/simonottenhauskenbun)
## Benchmark
Out of the box, `pyannote.audio` speaker diarization [pipeline](https://hf.co/pyannote/speaker-diarization-3.1) v3.1 is expected to be much better (and faster) than v2.x.
Those numbers are diarization error rates (in %):
-| Benchmark | [v2.1](https://hf.co/pyannote/speaker-diarization-2.1) | [v3.1](https://hf.co/pyannote/speaker-diarization-3.1) | [Premium](https://forms.office.com/e/GdqwVgkZ5C) |
-| ---------------------- | ------------------------------------------------------ | ------------------------------------------------------ | ---------------------------------------------- |
-| AISHELL-4 | 14.1 | 12.3 | 11.9 |
-| AliMeeting (channel 1) | 27.4 | 24.5 | 22.5 |
-| AMI (IHM) | 18.9 | 18.8 | 16.6 |
-| AMI (SDM) | 27.1 | 22.6 | 20.9 |
-| AVA-AVD | 66.3 | 50.0 | 39.8 |
-| CALLHOME (part 2) | 31.6 | 28.4 | 22.2 |
-| DIHARD 3 (full) | 26.9 | 21.4 | 17.2 |
-| Ego4D (dev.) | 61.5 | 51.2 | 43.8 |
-| MSDWild | 32.8 | 25.4 | 19.8 |
-| REPERE (phase2) | 8.2 | 7.8 | 7.6 |
-| VoxConverse (v0.3) | 11.2 | 11.2 | 9.4 |
+| Benchmark | [v2.1](https://hf.co/pyannote/speaker-diarization-2.1) | [v3.1](https://hf.co/pyannote/speaker-diarization-3.1) | [Premium](https://forms.office.com/e/GdqwVgkZ5C) |
+| --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------ |
+| [AISHELL-4](https://arxiv.org/abs/2104.03603) | 14.1 | 12.2 | 11.9 |
+| [AliMeeting](https://www.openslr.org/119/) (channel 1) | 27.4 | 24.4 | 22.5 |
+| [AMI](https://groups.inf.ed.ac.uk/ami/corpus/) (IHM) | 18.9 | 18.8 | 16.6 |
+| [AMI](https://groups.inf.ed.ac.uk/ami/corpus/) (SDM) | 27.1 | 22.4 | 20.9 |
+| [AVA-AVD](https://arxiv.org/abs/2111.14448) | 66.3 | 50.0 | 39.8 |
+| [CALLHOME](https://catalog.ldc.upenn.edu/LDC2001S97) ([part 2](https://github.com/BUTSpeechFIT/CALLHOME_sublists/issues/1)) | 31.6 | 28.4 | 22.2 |
+| [DIHARD 3](https://catalog.ldc.upenn.edu/LDC2022S14) ([full](https://arxiv.org/abs/2012.01477)) | 26.9 | 21.7 | 17.2 |
+| [Earnings21](https://github.com/revdotcom/speech-datasets) | 17.0 | 9.4 | 9.0 |
+| [Ego4D](https://arxiv.org/abs/2110.07058) (dev.) | 61.5 | 51.2 | 43.8 |
+| [MSDWild](https://github.com/X-LANCE/MSDWILD) | 32.8 | 25.3 | 19.8 |
+| [RAMC](https://www.openslr.org/123/) | 22.5 | 22.2 | 18.4 |
+| [REPERE](https://www.islrn.org/resources/360-758-359-485-0/) (phase2) | 8.2 | 7.8 | 7.6 |
+| [VoxConverse](https://github.com/joonson/voxconverse) (v0.3) | 11.2 | 11.3 | 9.4 |
[Diarization error rate](http://pyannote.github.io/pyannote-metrics/reference.html#diarization) (in %)
diff --git a/pyannote/audio/augmentation/mix.py b/pyannote/audio/augmentation/mix.py
index a6fff49c0..c6e811280 100644
--- a/pyannote/audio/augmentation/mix.py
+++ b/pyannote/audio/augmentation/mix.py
@@ -60,10 +60,10 @@ def __init__(
max_snr_in_db: float = 5.0,
mode: str = "per_example",
p: float = 0.5,
- p_mode: str = None,
- sample_rate: int = None,
- target_rate: int = None,
- max_num_speakers: int = None,
+ p_mode: Optional[str] = None,
+ sample_rate: Optional[int] = None,
+ target_rate: Optional[int] = None,
+ max_num_speakers: Optional[int] = None,
output_type: str = "tensor",
):
super().__init__(
@@ -80,7 +80,7 @@ def __init__(
def randomize_parameters(
self,
- samples: Tensor = None,
+ samples: Optional[Tensor] = None,
sample_rate: Optional[int] = None,
targets: Optional[Tensor] = None,
target_rate: Optional[int] = None,
diff --git a/pyannote/audio/cli/evaluate.py b/pyannote/audio/cli/evaluate.py
index a5ab682c5..3eec5e3cc 100644
--- a/pyannote/audio/cli/evaluate.py
+++ b/pyannote/audio/cli/evaluate.py
@@ -25,7 +25,7 @@
import hydra
from omegaconf import DictConfig
-from pyannote.database import FileFinder, ProtocolFile, get_protocol
+from pyannote.database import FileFinder, ProtocolFile, registry
from rich.progress import Progress
from pyannote.audio import Inference, Model
@@ -41,8 +41,16 @@ def evaluate(cfg: DictConfig) -> Optional[float]:
(device,) = get_devices(needs=1)
model = Model.from_pretrained(cfg.model, device=device)
+ # load databases into registry if it was specified
+ if "registry" in cfg:
+ for database_yml in cfg.registry.split(","):
+ registry.load_database(database_yml)
+
# load evaluation files
- protocol = get_protocol(cfg.protocol, preprocessors={"audio": FileFinder()})
+ protocol = registry.get_protocol(
+ cfg.protocol, preprocessors={"audio": FileFinder()}
+ )
+
files = list(getattr(protocol, cfg.subset)())
# load evaluation metric
@@ -53,7 +61,7 @@ def evaluate(cfg: DictConfig) -> Optional[float]:
main_task = progress.add_task(protocol.name, total=len(files))
file_task = progress.add_task("Processing", total=1.0)
- def progress_hook(completed: int = None, total: int = None):
+ def progress_hook(completed: Optional[int] = None, total: Optional[int] = None):
progress.update(file_task, completed=completed / total)
inference = Inference(model, device=device)
@@ -65,8 +73,6 @@ def hypothesis(file: ProtocolFile):
warm_up=(warm_up, warm_up),
)
- metric = DiscreteDiarizationErrorRate()
-
for file in files:
progress.update(file_task, description=file["uri"])
reference = file["annotation"]
diff --git a/pyannote/audio/cli/evaluate_config/hydra/default.yaml b/pyannote/audio/cli/evaluate_config/hydra/default.yaml
index 95979432b..1aaebd1b9 100644
--- a/pyannote/audio/cli/evaluate_config/hydra/default.yaml
+++ b/pyannote/audio/cli/evaluate_config/hydra/default.yaml
@@ -22,7 +22,8 @@ help:
template: |-
${hydra.help.header}
- pyannote-audio-eval protocol={protocol_name}
+ pyannote-audio-eval registry={path_to_database.yml}
+ protocol={protocol_name}
subset={test | development | train}
model={path_to_pretrained_model}
warm_up={warm_up_duration_in_seconds}
diff --git a/pyannote/audio/cli/lr_schedulers/CosineAnnealingWarmRestarts.py b/pyannote/audio/cli/lr_schedulers/CosineAnnealingWarmRestarts.py
index d8e5f4b3c..3c270eba1 100644
--- a/pyannote/audio/cli/lr_schedulers/CosineAnnealingWarmRestarts.py
+++ b/pyannote/audio/cli/lr_schedulers/CosineAnnealingWarmRestarts.py
@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+from typing import Optional
from torch.optim import Optimizer
from torch.optim.lr_scheduler import (
@@ -32,7 +33,7 @@ def CosineAnnealingWarmRestarts(
min_lr: float = 1e-8,
max_lr: float = 1e-3,
patience: int = 1,
- num_batches_per_epoch: int = None,
+ num_batches_per_epoch: Optional[int] = None,
**kwargs,
):
"""Wrapper around CosineAnnealingWarmRestarts
diff --git a/pyannote/audio/cli/lr_schedulers/CyclicLR.py b/pyannote/audio/cli/lr_schedulers/CyclicLR.py
index cd7a7b730..cca4420b0 100644
--- a/pyannote/audio/cli/lr_schedulers/CyclicLR.py
+++ b/pyannote/audio/cli/lr_schedulers/CyclicLR.py
@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+from typing import Optional
from torch.optim import Optimizer
from torch.optim.lr_scheduler import CyclicLR as _CyclicLR
@@ -31,7 +32,7 @@ def CyclicLR(
max_lr: float = 1e-3,
mode: str = "triangular2",
patience: int = 50,
- num_batches_per_epoch: int = None,
+ num_batches_per_epoch: Optional[int] = None,
**kwargs,
):
"""Wrapper around CyclicLR learning rate scheduler
diff --git a/pyannote/audio/cli/train.py b/pyannote/audio/cli/train.py
index 74041554b..f052cd5b3 100644
--- a/pyannote/audio/cli/train.py
+++ b/pyannote/audio/cli/train.py
@@ -51,8 +51,9 @@ def train(cfg: DictConfig) -> Optional[float]:
seed_everything(seed=seed)
# load databases into registry
- for database_yml in cfg.registry.split(","):
- registry.load_database(database_yml)
+ if "registry" in cfg:
+ for database_yml in cfg.registry.split(","):
+ registry.load_database(database_yml)
# instantiate training protocol with optional preprocessors
preprocessors = {"audio": FileFinder(), "torchaudio.info": get_torchaudio_info}
@@ -75,9 +76,9 @@ def train(cfg: DictConfig) -> Optional[float]:
# instantiate model
fine_tuning = cfg.model["_target_"] == "pyannote.audio.cli.pretrained"
- model = instantiate(cfg.model)
- model.task = task
- model.setup(stage="fit")
+ model = instantiate(cfg.model, task=task)
+ model.prepare_data()
+ model.setup()
# validation metric to monitor (and its direction: min or max)
monitor, direction = task.val_monitor
@@ -146,7 +147,6 @@ def configure_optimizers(self):
# in case of fine-tuning, validate the initial model to make sure
# that we actually improve over the initial performance
if fine_tuning:
- model.setup(stage="fit")
trainer.validate(model)
# train the model
@@ -157,7 +157,9 @@ def configure_optimizers(self):
# return the best validation score
# this can be used for hyper-parameter optimization with Hydra sweepers
- if monitor is not None:
+ # this can only be done if the trainer is not in fast dev run mode, as
+ # checkpointing is disabled in this mode
+ if monitor is not None and not trainer.fast_dev_run:
best_monitor = float(checkpoint.best_model_score)
if direction == "min":
return best_monitor
diff --git a/pyannote/audio/cli/train_config/config.yaml b/pyannote/audio/cli/train_config/config.yaml
index d5b761cc9..d7ecd547a 100644
--- a/pyannote/audio/cli/train_config/config.yaml
+++ b/pyannote/audio/cli/train_config/config.yaml
@@ -1,4 +1,3 @@
-registry: ???
protocol: ???
defaults:
diff --git a/pyannote/audio/cli/train_config/trainer/default.yaml b/pyannote/audio/cli/train_config/trainer/default.yaml
index ac3a60ff4..f32031af1 100644
--- a/pyannote/audio/cli/train_config/trainer/default.yaml
+++ b/pyannote/audio/cli/train_config/trainer/default.yaml
@@ -30,6 +30,6 @@ precision: 32
profiler: null
reload_dataloaders_every_n_epochs: 0
use_distributed_sampler: True # TODO: check what this does exactly
-strategy: null
+strategy: auto
sync_batchnorm: False
val_check_interval: 1.0
diff --git a/pyannote/audio/core/callback.py b/pyannote/audio/core/callback.py
index 5ce522d57..0cc46845b 100644
--- a/pyannote/audio/core/callback.py
+++ b/pyannote/audio/core/callback.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from typing import List, Mapping, Text, Union
+from typing import List, Mapping, Optional, Text, Union
from pytorch_lightning import Callback, Trainer
from pytorch_lightning.utilities.model_summary import ModelSummary
@@ -67,7 +67,7 @@ class GraduallyUnfreeze(Callback):
def __init__(
self,
schedule: Union[Mapping[Text, int], List[Union[List[Text], Text]]] = None,
- epochs_per_stage: int = None,
+ epochs_per_stage: Optional[int] = None,
):
super().__init__()
diff --git a/pyannote/audio/core/inference.py b/pyannote/audio/core/inference.py
index dcf21868d..0c3e9b212 100644
--- a/pyannote/audio/core/inference.py
+++ b/pyannote/audio/core/inference.py
@@ -20,7 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-import math
import warnings
from pathlib import Path
from typing import Callable, List, Optional, Text, Tuple, Union
@@ -37,7 +36,6 @@
from pyannote.audio.core.model import Model, Specifications
from pyannote.audio.core.task import Resolution
from pyannote.audio.utils.multi_task import map_with_specifications
-from pyannote.audio.utils.permutation import mae_cost_func, permutate
from pyannote.audio.utils.powerset import Powerset
from pyannote.audio.utils.reproducibility import fix_reproducibility
@@ -86,12 +84,12 @@ def __init__(
self,
model: Union[Model, Text, Path],
window: Text = "sliding",
- duration: float = None,
- step: float = None,
+ duration: Optional[float] = None,
+ step: Optional[float] = None,
pre_aggregation_hook: Callable[[np.ndarray], np.ndarray] = None,
skip_aggregation: bool = False,
skip_conversion: bool = False,
- device: torch.device = None,
+ device: Optional[torch.device] = None,
batch_size: int = 32,
use_auth_token: Union[Text, None] = None,
):
@@ -263,16 +261,14 @@ def slide(
_, num_samples = waveform.shape
def __frames(
- example_output, specifications: Optional[Specifications] = None
+ receptive_field, specifications: Optional[Specifications] = None
) -> SlidingWindow:
if specifications.resolution == Resolution.CHUNK:
return SlidingWindow(start=0.0, duration=self.duration, step=self.step)
- return example_output.frames
+ return receptive_field
frames: Union[SlidingWindow, Tuple[SlidingWindow]] = map_with_specifications(
- self.model.specifications,
- __frames,
- self.model.example_output,
+ self.model.specifications, __frames, self.model.receptive_field
)
# prepare complete chunks
@@ -373,7 +369,7 @@ def __aggregate(
outputs,
SlidingWindow(start=0.0, duration=self.duration, step=self.step),
),
- frames=frames,
+ frames,
warm_up=self.warm_up,
hamming=True,
missing=0.0,
@@ -526,7 +522,7 @@ def __first_sample(outputs: np.ndarray, **kwargs) -> np.ndarray:
@staticmethod
def aggregate(
scores: SlidingWindowFeature,
- frames: SlidingWindow = None,
+ frames: SlidingWindow,
warm_up: Tuple[float, float] = (0.0, 0.0),
epsilon: float = 1e-12,
hamming: bool = False,
@@ -539,10 +535,8 @@ def aggregate(
----------
scores : SlidingWindowFeature
Raw (unaggregated) scores. Shape is (num_chunks, num_frames_per_chunk, num_classes).
- frames : SlidingWindow, optional
- Frames resolution. Defaults to estimate it automatically based on `scores` shape
- and chunk size. Providing the exact frame resolution (when known) leads to better
- temporal precision.
+ frames : SlidingWindow
+ Frames resolution.
warm_up : (float, float) tuple, optional
Left/right warm up duration (in seconds).
missing : float, optional
@@ -559,15 +553,11 @@ def aggregate(
num_chunks, num_frames_per_chunk, num_classes = scores.data.shape
chunks = scores.sliding_window
- if frames is None:
- duration = step = chunks.duration / num_frames_per_chunk
- frames = SlidingWindow(start=chunks.start, duration=duration, step=step)
- else:
- frames = SlidingWindow(
- start=chunks.start,
- duration=frames.duration,
- step=frames.step,
- )
+ frames = SlidingWindow(
+ start=chunks.start,
+ duration=frames.duration,
+ step=frames.step,
+ )
masks = 1 - np.isnan(scores)
scores.data = np.nan_to_num(scores.data, copy=True, nan=0.0)
@@ -602,6 +592,7 @@ def aggregate(
scores.sliding_window.start
+ scores.sliding_window.duration
+ (num_chunks - 1) * scores.sliding_window.step
+ + 0.5 * frames.duration
)
+ 1
)
@@ -627,7 +618,8 @@ def aggregate(
# score ~ (num_frames_per_chunk, num_classes)-shaped np.ndarray
# mask ~ (num_frames_per_chunk, num_classes)-shaped np.ndarray
- start_frame = frames.closest_frame(chunk.start)
+ start_frame = frames.closest_frame(chunk.start + 0.5 * frames.duration)
+
aggregated_output[start_frame : start_frame + num_frames_per_chunk] += (
score * mask * hamming_window * warm_up_window
)
@@ -698,134 +690,3 @@ def trim(
)
return SlidingWindowFeature(new_data, new_chunks)
-
- @staticmethod
- def stitch(
- activations: SlidingWindowFeature,
- frames: SlidingWindow = None,
- lookahead: Optional[Tuple[int, int]] = None,
- cost_func: Callable[[torch.Tensor, torch.Tensor], torch.Tensor] = None,
- match_func: Callable[[np.ndarray, np.ndarray, float], bool] = None,
- ) -> SlidingWindowFeature:
- """
-
- Parameters
- ----------
- activations : SlidingWindowFeature
- (num_chunks, num_frames, num_classes)-shaped scores.
- frames : SlidingWindow, optional
- Frames resolution. Defaults to estimate it automatically based on `activations`
- shape and chunk size. Providing the exact frame resolution (when known) leads to better
- temporal precision.
- lookahead : (int, int) tuple
- Number of past and future adjacent chunks to use for stitching.
- Defaults to (k, k) with k = chunk_duration / chunk_step - 1
- cost_func : callable
- Cost function used to find the optimal mapping between two chunks.
- Expects two (num_frames, num_classes) torch.tensor as input
- and returns cost as a (num_classes, ) torch.tensor
- Defaults to mean absolute error (utils.permutations.mae_cost_func)
- match_func : callable
- Function used to decide whether two speakers mapped by the optimal
- mapping actually are a match.
- Expects two (num_frames, ) np.ndarray and the cost (from cost_func)
- and returns a boolean. Defaults to always returning True.
- """
-
- num_chunks, num_frames, num_classes = activations.data.shape
-
- chunks: SlidingWindow = activations.sliding_window
-
- if frames is None:
- duration = step = chunks.duration / num_frames
- frames = SlidingWindow(start=chunks.start, duration=duration, step=step)
- else:
- frames = SlidingWindow(
- start=chunks.start,
- duration=frames.duration,
- step=frames.step,
- )
-
- max_lookahead = math.floor(chunks.duration / chunks.step - 1)
- if lookahead is None:
- lookahead = 2 * (max_lookahead,)
-
- assert all(L <= max_lookahead for L in lookahead)
-
- if cost_func is None:
- cost_func = mae_cost_func
-
- if match_func is None:
-
- def always_match(this: np.ndarray, that: np.ndarray, cost: float):
- return True
-
- match_func = always_match
-
- stitches = []
- for C, (chunk, activation) in enumerate(activations):
- local_stitch = np.NAN * np.zeros(
- (sum(lookahead) + 1, num_frames, num_classes)
- )
-
- for c in range(
- max(0, C - lookahead[0]), min(num_chunks, C + lookahead[1] + 1)
- ):
- # extract common temporal support
- shift = round((C - c) * num_frames * chunks.step / chunks.duration)
-
- if shift < 0:
- shift = -shift
- this_activations = activation[shift:]
- that_activations = activations[c, : num_frames - shift]
- else:
- this_activations = activation[: num_frames - shift]
- that_activations = activations[c, shift:]
-
- # find the optimal one-to-one mapping
- _, (permutation,), (cost,) = permutate(
- this_activations[np.newaxis],
- that_activations,
- cost_func=cost_func,
- return_cost=True,
- )
-
- for this, that in enumerate(permutation):
- # only stitch under certain condiditions
- matching = (c == C) or (
- match_func(
- this_activations[:, this],
- that_activations[:, that],
- cost[this, that],
- )
- )
-
- if matching:
- local_stitch[c - C + lookahead[0], :, this] = activations[
- c, :, that
- ]
-
- # TODO: do not lookahead further once a mismatch is found
-
- stitched_chunks = SlidingWindow(
- start=chunk.start - lookahead[0] * chunks.step,
- duration=chunks.duration,
- step=chunks.step,
- )
-
- local_stitch = Inference.aggregate(
- SlidingWindowFeature(local_stitch, stitched_chunks),
- frames=frames,
- hamming=True,
- )
-
- stitches.append(local_stitch.data)
-
- stitches = np.stack(stitches)
- stitched_chunks = SlidingWindow(
- start=chunks.start - lookahead[0] * chunks.step,
- duration=chunks.duration + sum(lookahead) * chunks.step,
- step=chunks.step,
- )
-
- return SlidingWindowFeature(stitches, stitched_chunks)
diff --git a/pyannote/audio/core/io.py b/pyannote/audio/core/io.py
index 0a44e75ea..8fafe69d3 100644
--- a/pyannote/audio/core/io.py
+++ b/pyannote/audio/core/io.py
@@ -40,8 +40,6 @@
from pyannote.core import Segment
from torch import Tensor
-torchaudio.set_audio_backend("soundfile")
-
AudioFile = Union[Text, Path, IOBase, Mapping]
AudioFileDocString = """
@@ -253,7 +251,9 @@ def get_duration(self, file: AudioFile) -> float:
return frames / sample_rate
- def get_num_samples(self, duration: float, sample_rate: int = None) -> int:
+ def get_num_samples(
+ self, duration: float, sample_rate: Optional[int] = None
+ ) -> int:
"""Deterministic number of samples from duration and sample rate"""
sample_rate = sample_rate or self.sample_rate
diff --git a/pyannote/audio/core/model.py b/pyannote/audio/core/model.py
index bedb7f6c4..8af802293 100644
--- a/pyannote/audio/core/model.py
+++ b/pyannote/audio/core/model.py
@@ -46,7 +46,6 @@
from pyannote.audio.core.io import Audio
from pyannote.audio.core.task import (
Problem,
- Resolution,
Specifications,
Task,
UnknownSpecificationsError,
@@ -112,10 +111,6 @@ def task(self) -> Task:
def task(self, task: Task):
# reset (cached) properties when task changes
del self.specifications
- try:
- del self.example_output
- except AttributeError:
- pass
self._task = task
def build(self):
@@ -136,15 +131,7 @@ def specifications(self) -> Union[Specifications, Tuple[Specifications]]:
) from e
else:
- try:
- specifications = self.task.specifications
-
- except AttributeError as e:
- raise UnknownSpecificationsError(
- "Task specifications are not available. This is most likely because they depend on "
- "the content of the training subset. Use `model.task.setup()` to go over the training "
- "subset and fix this, or let lightning trainer do that for you in `trainer.fit(model)`."
- ) from e
+ specifications = self.task.specifications
return specifications
@@ -188,38 +175,35 @@ def example_input_array(self) -> torch.Tensor:
return self.__example_input_array()
@cached_property
- def example_output(self) -> Union[Output, Tuple[Output]]:
- """Example output"""
- example_input_array = self.__example_input_array()
- with torch.inference_mode():
- example_output = self(example_input_array)
-
- def __example_output(
- example_output: torch.Tensor,
- specifications: Specifications = None,
- ) -> Output:
- if specifications.resolution == Resolution.FRAME:
- _, num_frames, dimension = example_output.shape
- frame_duration = specifications.duration / num_frames
- frames = SlidingWindow(step=frame_duration, duration=frame_duration)
- else:
- _, dimension = example_output.shape
- num_frames = None
- frames = None
-
- return Output(
- num_frames=num_frames,
- dimension=dimension,
- frames=frames,
- )
+ def receptive_field(self) -> SlidingWindow:
+ """(Internal) frames"""
- return map_with_specifications(
- self.specifications, __example_output, example_output
+ receptive_field_size = self.receptive_field_size(num_frames=1)
+ receptive_field_step = (
+ self.receptive_field_size(num_frames=2) - receptive_field_size
+ )
+ receptive_field_start = (
+ self.receptive_field_center(frame=0) - (receptive_field_size - 1) / 2
+ )
+ return SlidingWindow(
+ start=receptive_field_start / self.hparams.sample_rate,
+ duration=receptive_field_size / self.hparams.sample_rate,
+ step=receptive_field_step / self.hparams.sample_rate,
)
+ def prepare_data(self):
+ self.task.prepare_data()
+
def setup(self, stage=None):
if stage == "fit":
- self.task.setup_metadata()
+ # let the task know about the trainer (e.g for broadcasting
+ # cache path between multi-GPU training processes).
+ self.task.trainer = self.trainer
+
+ # setup the task if defined (only on training and validation stages,
+ # but not for basic inference)
+ if self.task:
+ self.task.setup(stage)
# list of layers before adding task-dependent layers
before = set((name, id(module)) for name, module in self.named_modules())
@@ -252,7 +236,7 @@ def setup(self, stage=None):
module.to(self.device)
# add (trainable) loss function (e.g. ArcFace has its own set of trainable weights)
- if stage == "fit":
+ if self.task:
# let task know about the model
self.task.model = self
# setup custom loss function
@@ -260,9 +244,6 @@ def setup(self, stage=None):
# setup custom validation metrics
self.task.setup_validation_metric()
- # cache for later (and to avoid later CUDA error with multiprocessing)
- _ = self.example_output
-
# list of layers after adding task-dependent layers
after = set((name, id(module)) for name, module in self.named_modules())
@@ -331,7 +312,9 @@ def default_activation(self) -> Union[nn.Module, Tuple[nn.Module]]:
Activation.
"""
- def __default_activation(specifications: Specifications = None) -> nn.Module:
+ def __default_activation(
+ specifications: Optional[Specifications] = None,
+ ) -> nn.Module:
if specifications.problem == Problem.BINARY_CLASSIFICATION:
return nn.Sigmoid()
@@ -468,9 +451,8 @@ def __by_name(
if isinstance(modules, str):
modules = [modules]
- for name, module in ModelSummary(self, max_depth=-1).named_modules:
- if name not in modules:
- continue
+ for name in modules:
+ module = getattr(self, name)
for parameter in module.parameters(recurse=True):
parameter.requires_grad = requires_grad
diff --git a/pyannote/audio/core/pipeline.py b/pyannote/audio/core/pipeline.py
index f844d584f..24e266abf 100644
--- a/pyannote/audio/core/pipeline.py
+++ b/pyannote/audio/core/pipeline.py
@@ -29,6 +29,7 @@
from typing import Callable, Dict, List, Optional, Text, Union
import torch
+import torch.nn as nn
import yaml
from huggingface_hub import hf_hub_download
from huggingface_hub.utils import RepositoryNotFoundError
@@ -232,7 +233,7 @@ def remove_from(*dicts):
_models = self.__dict__.get("_models")
_inferences = self.__dict__.get("_inferences")
- if isinstance(value, Model):
+ if isinstance(value, nn.Module):
if _models is None:
msg = "cannot assign models before Pipeline.__init__() call"
raise AttributeError(msg)
diff --git a/pyannote/audio/core/task.py b/pyannote/audio/core/task.py
index 1edfbc35c..0a61e2a6f 100644
--- a/pyannote/audio/core/task.py
+++ b/pyannote/audio/core/task.py
@@ -23,19 +23,25 @@
from __future__ import annotations
+import itertools
import multiprocessing
import sys
import warnings
+from collections import defaultdict
from dataclasses import dataclass
from enum import Enum
from functools import cached_property, partial
from numbers import Number
+from pathlib import Path
+from tempfile import mkstemp
from typing import Dict, List, Literal, Optional, Sequence, Text, Tuple, Union
+import numpy as np
import pytorch_lightning as pl
import scipy.special
import torch
from pyannote.database import Protocol
+from pyannote.database.protocol.protocol import Scope, Subset
from torch.utils.data import DataLoader, Dataset, IterableDataset
from torch_audiomentations import Identity
from torch_audiomentations.core.transforms_interface import BaseWaveformTransform
@@ -44,6 +50,9 @@
from pyannote.audio.utils.loss import binary_cross_entropy, nll_loss
from pyannote.audio.utils.protocol import check_protocol
+Subsets = list(Subset.__args__)
+Scopes = list(Scope.__args__)
+
# Type of machine learning problem
class Problem(Enum):
@@ -151,6 +160,31 @@ def __len__(self):
return self.task.val__len__()
+def get_dtype(value: int) -> str:
+ """Return the most suitable type for storing the
+ value passed in parameter in memory.
+
+ Parameters
+ ----------
+ value: int
+ value whose type is best suited to storage in memory
+
+ Returns
+ -------
+ str:
+ numpy formatted type
+ (see https://numpy.org/doc/stable/reference/arrays.dtypes.html)
+ """
+ # signe byte (8 bits), signed short (16 bits), signed int (32 bits):
+ types_list = [(127, "b"), (32_768, "i2"), (2_147_483_648, "i")]
+ filtered_list = [
+ (max_val, type) for max_val, type in types_list if max_val > abs(value)
+ ]
+ if not filtered_list:
+ return "i8" # signed long (64 bits)
+ return filtered_list[0][1]
+
+
class Task(pl.LightningDataModule):
"""Base task class
@@ -169,6 +203,13 @@ class Task(pl.LightningDataModule):
----------
protocol : Protocol
pyannote.database protocol
+ cache : str, optional
+ As (meta-)data preparation might take a very long time for large datasets,
+ it can be cached to disk for later (and faster!) re-use.
+ When `cache` does not exist, `Task.prepare_data()` generates training
+ and validation metadata from `protocol` and save them to disk.
+ When `cache` exists, `Task.prepare_data()` is skipped and (meta)-data
+ are loaded from disk. Defaults to a temporary path.
duration : float, optional
Chunks duration in seconds. Defaults to two seconds (2.).
min_duration : float, optional
@@ -201,18 +242,20 @@ class Task(pl.LightningDataModule):
----------
specifications : Specifications or tuple of Specifications
Task specifications (available after `Task.setup` has been called.)
+
"""
def __init__(
self,
protocol: Protocol,
+ cache: Optional[Union[str, None]] = None,
duration: float = 2.0,
- min_duration: float = None,
+ min_duration: Optional[float] = None,
warm_up: Union[float, Tuple[float, float]] = 0.0,
batch_size: int = 32,
- num_workers: int = None,
+ num_workers: Optional[int] = None,
pin_memory: bool = False,
- augmentation: BaseWaveformTransform = None,
+ augmentation: Optional[BaseWaveformTransform] = None,
metric: Union[Metric, Sequence[Metric], Dict[str, Metric]] = None,
):
super().__init__()
@@ -221,8 +264,16 @@ def __init__(
self.protocol, checks = check_protocol(protocol)
self.has_validation = checks["has_validation"]
self.has_scope = checks["has_scope"]
+ if not self.has_scope:
+ raise ValueError(
+ "Protocol must provide 'scope' information (e.g. 'file', 'database', or 'global')."
+ )
+
self.has_classes = checks["has_classes"]
+ # metadata cache
+ self.cache = Path(cache) if cache else cache
+
# batching
self.duration = duration
self.min_duration = duration if min_duration is None else min_duration
@@ -255,24 +306,351 @@ def __init__(
self._metric = metric
def prepare_data(self):
- """Use this to download and prepare data
-
- This is where we might end up downloading datasets
- and transform them so that they are ready to be used
- with pyannote.database. but for now, the API assume
- that we directly provide a pyannote.database.Protocol.
+ """Use this to prepare data from task protocol
Notes
-----
- Called only once.
+ Called only once on the main process (and only on it), for global_rank 0.
+
+ After this method is called, the task should have a `prepared_data` attribute
+ with the following dictionary structure:
+
+ prepared_data = {
+ 'protocol': name of the protocol
+ 'audio-path': array of N paths to audio
+ 'audio-metadata': array of N audio infos such as audio subset, scope and database
+ 'audio-info': array of N audio torchaudio.info struct
+ 'audio-encoding': array of N audio encodings
+ 'audio-annotated': array of N annotated duration (usually equals file duration but might be shorter if file is not fully annotated)
+ 'annotations-regions': array of M annotated regions
+ 'annotations-segments': array of M' annotated segments
+ 'metadata-values': dict of lists of values for subset, scope and database
+ 'metadata-`database-name`-labels': array of `database-name` labels. Each database with "database" scope labels has it own array.
+ 'metadata-labels': array of global scope labels
+ }
+
+ """
+
+ if self.cache:
+ # check if cache exists and is not empty:
+ if self.cache.exists() and self.cache.stat().st_size > 0:
+ # data was already created, nothing to do
+ return
+ # create parent directory if needed
+ self.cache.parent.mkdir(parents=True, exist_ok=True)
+ else:
+ # if no cache was provided by user, create a temporary file
+ # in system directory used for temp files
+ self.cache = Path(mkstemp()[1])
+
+ # list of possible values for each metadata key
+ # (will become .prepared_data[""])
+ metadata_unique_values = defaultdict(list)
+ metadata_unique_values["subset"] = Subsets
+ metadata_unique_values["scope"] = Scopes
+
+ audios = list() # list of path to audio files
+ audio_infos = list()
+ audio_encodings = list()
+ metadata = list() # list of metadata
+
+ annotated_duration = list() # total duration of annotated regions (per file)
+ annotated_regions = list() # annotated regions
+ annotations = list() # actual annotations
+ unique_labels = list()
+ database_unique_labels = {}
+
+ if self.has_validation:
+ files_iter = itertools.chain(
+ self.protocol.train(), self.protocol.development()
+ )
+ else:
+ files_iter = self.protocol.train()
+
+ for file_id, file in enumerate(files_iter):
+ # gather metadata and update metadata_unique_values so that each metadatum
+ # (e.g. source database or label) is represented by an integer.
+ metadatum = dict()
+
+ # keep track of source database and subset (train, development, or test)
+ if file["database"] not in metadata_unique_values["database"]:
+ metadata_unique_values["database"].append(file["database"])
+ metadatum["database"] = metadata_unique_values["database"].index(
+ file["database"]
+ )
+ metadatum["subset"] = Subsets.index(file["subset"])
+
+ # keep track of label scope (file, database, or global)
+ metadatum["scope"] = Scopes.index(file["scope"])
+
+ remaining_metadata_keys = set(file) - set(
+ [
+ "uri",
+ "database",
+ "subset",
+ "audio",
+ "torchaudio.info",
+ "scope",
+ "classes",
+ "annotation",
+ "annotated",
+ ]
+ )
+
+ # keep track of any other (integer or string) metadata provided by the protocol
+ # (e.g. a "domain" key for domain-adversarial training)
+ for key in remaining_metadata_keys:
+ value = file[key]
+
+ if isinstance(value, str):
+ if value not in metadata_unique_values[key]:
+ metadata_unique_values[key].append(value)
+ metadatum[key] = metadata_unique_values[key].index(value)
+
+ elif isinstance(value, int):
+ metadatum[key] = value
+
+ else:
+ warnings.warn(
+ f"Ignoring '{key}' metadata because of its type ({type(value)}). Only str and int are supported for now.",
+ category=UserWarning,
+ )
+
+ metadata.append(metadatum)
+
+ # reset list of file-scoped labels
+ file_unique_labels = list()
+
+ # path to audio file
+ audios.append(str(file["audio"]))
+
+ # audio info
+ audio_info = file["torchaudio.info"]
+ audio_infos.append(
+ (
+ audio_info.sample_rate, # sample rate
+ audio_info.num_frames, # number of frames
+ audio_info.num_channels, # number of channels
+ audio_info.bits_per_sample, # bits per sample
+ )
+ )
+ audio_encodings.append(audio_info.encoding) # encoding
+
+ # annotated regions and duration
+ _annotated_duration = 0.0
+ for segment in file["annotated"]:
+ # skip annotated regions that are shorter than training chunk duration
+ if segment.duration < self.duration:
+ continue
+
+ # append annotated region
+ annotated_region = (
+ file_id,
+ segment.duration,
+ segment.start,
+ )
+ annotated_regions.append(annotated_region)
+
+ # increment annotated duration
+ _annotated_duration += segment.duration
+
+ # append annotated duration
+ annotated_duration.append(_annotated_duration)
+
+ # annotations
+ for segment, _, label in file["annotation"].itertracks(yield_label=True):
+ # "scope" is provided by speaker diarization protocols to indicate
+ # whether speaker labels are local to the file ('file'), consistent across
+ # all files in a database ('database'), or globally consistent ('global')
+
+ # 0 = 'file' / 1 = 'database' / 2 = 'global'
+ scope = Scopes.index(file["scope"])
+
+ # update list of file-scope labels
+ if label not in file_unique_labels:
+ file_unique_labels.append(label)
+ # and convert label to its (file-scope) index
+ file_label_idx = file_unique_labels.index(label)
+
+ database_label_idx = global_label_idx = -1
+
+ if scope > 0: # 'database' or 'global'
+ # update list of database-scope labels
+ database = file["database"]
+ if database not in database_unique_labels:
+ database_unique_labels[database] = []
+ if label not in database_unique_labels[database]:
+ database_unique_labels[database].append(label)
+
+ # and convert label to its (database-scope) index
+ database_label_idx = database_unique_labels[database].index(label)
+
+ if scope > 1: # 'global'
+ # update list of global-scope labels
+ if label not in unique_labels:
+ unique_labels.append(label)
+ # and convert label to its (global-scope) index
+ global_label_idx = unique_labels.index(label)
+
+ annotations.append(
+ (
+ file_id, # index of file
+ segment.start, # start time
+ segment.end, # end time
+ file_label_idx, # file-scope label index
+ database_label_idx, # database-scope label index
+ global_label_idx, # global-scope index
+ )
+ )
+
+ # since not all metadata keys are present in all files, fallback to -1 when a key is missing
+ metadata = [
+ tuple(metadatum.get(key, -1) for key in metadata_unique_values)
+ for metadatum in metadata
+ ]
+ metadata_dtype = [
+ (key, get_dtype(max(m[i] for m in metadata)))
+ for i, key in enumerate(metadata_unique_values)
+ ]
+
+ # turn list of files metadata into a single numpy array
+ # TODO: improve using https://github.com/pytorch/pytorch/issues/13246#issuecomment-617140519
+ info_dtype = [
+ (
+ "sample_rate",
+ get_dtype(max(ai[0] for ai in audio_infos)),
+ ),
+ (
+ "num_frames",
+ get_dtype(max(ai[1] for ai in audio_infos)),
+ ),
+ ("num_channels", "B"),
+ ("bits_per_sample", "B"),
+ ]
+
+ # turn list of annotated regions into a single numpy array
+ region_dtype = [
+ (
+ "file_id",
+ get_dtype(max(ar[0] for ar in annotated_regions)),
+ ),
+ ("duration", "f"),
+ ("start", "f"),
+ ]
+
+ # turn list of annotations into a single numpy array
+ segment_dtype = [
+ (
+ "file_id",
+ get_dtype(max(a[0] for a in annotations)),
+ ),
+ ("start", "f"),
+ ("end", "f"),
+ ("file_label_idx", get_dtype(max(a[3] for a in annotations))),
+ ("database_label_idx", get_dtype(max(a[4] for a in annotations))),
+ ("global_label_idx", get_dtype(max(a[5] for a in annotations))),
+ ]
+
+ # save all protocol data in a dict
+ prepared_data = {}
+
+ # keep track of protocol name
+ prepared_data["protocol"] = self.protocol.name
+
+ prepared_data["audio-path"] = np.array(audios, dtype=np.str_)
+ audios.clear()
+
+ prepared_data["audio-metadata"] = np.array(metadata, dtype=metadata_dtype)
+ metadata.clear()
+
+ prepared_data["audio-info"] = np.array(audio_infos, dtype=info_dtype)
+ audio_infos.clear()
+
+ prepared_data["audio-encoding"] = np.array(audio_encodings, dtype=np.str_)
+ audio_encodings.clear()
+
+ prepared_data["audio-annotated"] = np.array(annotated_duration)
+ annotated_duration.clear()
+
+ prepared_data["annotations-regions"] = np.array(
+ annotated_regions, dtype=region_dtype
+ )
+ annotated_regions.clear()
+
+ prepared_data["annotations-segments"] = np.array(
+ annotations, dtype=segment_dtype
+ )
+ annotations.clear()
+
+ prepared_data["metadata-values"] = metadata_unique_values
+
+ for database, labels in database_unique_labels.items():
+ prepared_data[f"metadata-{database}-labels"] = np.array(
+ labels, dtype=np.str_
+ )
+ database_unique_labels.clear()
+
+ prepared_data["metadata-labels"] = np.array(unique_labels, dtype=np.str_)
+ unique_labels.clear()
+
+ self.prepare_validation(prepared_data)
+ self.post_prepare_data(prepared_data)
+
+ # save prepared data on the disk
+ with open(self.cache, "wb") as cache_file:
+ np.savez_compressed(cache_file, **prepared_data)
+
+ def post_prepare_data(self, prepared_data: Dict):
+ """Method for completing `prepared_data` with task-specific data.
+ For instance, for a classification task, this could be a list of
+ possible classes.
+
+ Parameters
+ ----------
+ prepared_data: dict
+ dictionnary containing protocol data prepared by
+ `prepare_data()`
+ Note
+ ----
+ This method does not return anything. Thus, user have to directly modify
+ `prepared_data`, for updates to be taken into account
"""
pass
+ def setup(self, stage=None):
+ """Setup data cached by prepare_data into the task on each device"""
+
+ # send cache path on all processes used for the training,
+ # allowing them to access the cache generated by prepare_data
+ if stage == "fit":
+ self.cache = self.trainer.strategy.broadcast(self.cache)
+
+ try:
+ with open(self.cache, "rb") as cache_file:
+ self.prepared_data = dict(np.load(cache_file, allow_pickle=True))
+ except FileNotFoundError:
+ print(
+ "Cached data for protocol not found. Ensure that prepare_data() was called",
+ " and executed correctly or/and that the path to the task cache is correct.",
+ )
+ raise
+
+ # checks that the task current protocol matches the cached protocol
+ if self.protocol.name != self.prepared_data["protocol"]:
+ raise ValueError(
+ f"Protocol specified for the task ({self.protocol.name}) "
+ f"does not correspond to the cached one ({self.prepared_data['protocol']})"
+ )
+
@property
def specifications(self) -> Union[Specifications, Tuple[Specifications]]:
# setup metadata on-demand the first time specifications are requested and missing
if not hasattr(self, "_specifications"):
- self.setup_metadata()
+ raise UnknownSpecificationsError(
+ "Task specifications are not available. This is most likely because they depend on "
+ "the content of the training subset. Use `task.prepare_data()` and `task.setup()` "
+ "to go over the training subset and fix this, or let lightning trainer do that for you in `trainer.fit(model)`."
+ )
return self._specifications
@specifications.setter
@@ -281,29 +659,6 @@ def specifications(
):
self._specifications = specifications
- @property
- def has_setup_metadata(self):
- return getattr(self, "_has_setup_metadata", False)
-
- @has_setup_metadata.setter
- def has_setup_metadata(self, value: bool):
- self._has_setup_metadata = value
-
- def setup_metadata(self):
- """Called at the beginning of training at the very beginning of Model.setup(stage="fit")
-
- Notes
- -----
- This hook is called on every process when using DDP.
-
- If `specifications` attribute has not been set in `__init__`,
- `setup` is your last chance to set it.
- """
-
- if not self.has_setup_metadata:
- self.setup()
- self.has_setup_metadata = True
-
def setup_loss_func(self):
pass
diff --git a/pyannote/audio/models/blocks/pooling.py b/pyannote/audio/models/blocks/pooling.py
index 22d736a03..dc31bea8e 100644
--- a/pyannote/audio/models/blocks/pooling.py
+++ b/pyannote/audio/models/blocks/pooling.py
@@ -26,53 +26,53 @@
import torch
import torch.nn as nn
import torch.nn.functional as F
-from einops import rearrange
-class StatsPool(nn.Module):
- """Statistics pooling
+def _pool(sequences: torch.Tensor, weights: torch.Tensor) -> torch.Tensor:
+ """Helper function to compute statistics pooling
- Compute temporal mean and (unbiased) standard deviation
- and returns their concatenation.
+ Assumes that weights are already interpolated to match the number of frames
+ in sequences and that they encode the activation of only one speaker.
- Reference
- ---------
- https://en.wikipedia.org/wiki/Weighted_arithmetic_mean
+ Parameters
+ ----------
+ sequences : (batch, features, frames) torch.Tensor
+ Sequences of features.
+ weights : (batch, frames) torch.Tensor
+ (Already interpolated) weights.
+ Returns
+ -------
+ output : (batch, 2 * features) torch.Tensor
+ Concatenation of mean and (unbiased) standard deviation.
"""
- def _pool(self, sequences: torch.Tensor, weights: torch.Tensor) -> torch.Tensor:
- """Helper function to compute statistics pooling
+ weights = weights.unsqueeze(dim=1)
+ # (batch, 1, frames)
- Assumes that weights are already interpolated to match the number of frames
- in sequences and that they encode the activation of only one speaker.
+ v1 = weights.sum(dim=2) + 1e-8
+ mean = torch.sum(sequences * weights, dim=2) / v1
- Parameters
- ----------
- sequences : (batch, features, frames) torch.Tensor
- Sequences of features.
- weights : (batch, frames) torch.Tensor
- (Already interpolated) weights.
+ dx2 = torch.square(sequences - mean.unsqueeze(2))
+ v2 = torch.square(weights).sum(dim=2)
- Returns
- -------
- output : (batch, 2 * features) torch.Tensor
- Concatenation of mean and (unbiased) standard deviation.
- """
+ var = torch.sum(dx2 * weights, dim=2) / (v1 - v2 / v1 + 1e-8)
+ std = torch.sqrt(var)
- weights = weights.unsqueeze(dim=1)
- # (batch, 1, frames)
+ return torch.cat([mean, std], dim=1)
- v1 = weights.sum(dim=2) + 1e-8
- mean = torch.sum(sequences * weights, dim=2) / v1
- dx2 = torch.square(sequences - mean.unsqueeze(2))
- v2 = torch.square(weights).sum(dim=2)
+class StatsPool(nn.Module):
+ """Statistics pooling
- var = torch.sum(dx2 * weights, dim=2) / (v1 - v2 / v1 + 1e-8)
- std = torch.sqrt(var)
+ Compute temporal mean and (unbiased) standard deviation
+ and returns their concatenation.
- return torch.cat([mean, std], dim=1)
+ Reference
+ ---------
+ https://en.wikipedia.org/wiki/Weighted_arithmetic_mean
+
+ """
def forward(
self, sequences: torch.Tensor, weights: Optional[torch.Tensor] = None
@@ -112,17 +112,20 @@ def forward(
has_speaker_dimension = True
# interpolate weights if needed
- _, _, num_frames = sequences.shape
- _, _, num_weights = weights.shape
+ _, _, num_frames = sequences.size()
+ _, num_speakers, num_weights = weights.size()
if num_frames != num_weights:
warnings.warn(
f"Mismatch between frames ({num_frames}) and weights ({num_weights}) numbers."
)
weights = F.interpolate(weights, size=num_frames, mode="nearest")
- output = rearrange(
- torch.vmap(self._pool, in_dims=(None, 1))(sequences, weights),
- "speakers batch features -> batch speakers features",
+ output = torch.stack(
+ [
+ _pool(sequences, weights[:, speaker, :])
+ for speaker in range(num_speakers)
+ ],
+ dim=1,
)
if not has_speaker_dimension:
diff --git a/pyannote/audio/models/blocks/sincnet.py b/pyannote/audio/models/blocks/sincnet.py
index 65bd6e57f..2a085201c 100644
--- a/pyannote/audio/models/blocks/sincnet.py
+++ b/pyannote/audio/models/blocks/sincnet.py
@@ -1,6 +1,6 @@
# The MIT License (MIT)
#
-# Copyright (c) 2019-2020 CNRS
+# Copyright (c) 2019- CNRS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,22 +23,30 @@
# AUTHOR
# Hervé Bredin - http://herve.niderb.fr
+from functools import lru_cache
import torch
import torch.nn as nn
import torch.nn.functional as F
from asteroid_filterbanks import Encoder, ParamSincFB
+from pyannote.audio.utils.receptive_field import (
+ multi_conv_num_frames,
+ multi_conv_receptive_field_center,
+ multi_conv_receptive_field_size,
+)
+
class SincNet(nn.Module):
def __init__(self, sample_rate: int = 16000, stride: int = 1):
super().__init__()
if sample_rate != 16000:
- raise NotImplementedError("PyanNet only supports 16kHz audio for now.")
+ raise NotImplementedError("SincNet only supports 16kHz audio for now.")
# TODO: add support for other sample rate. it should be enough to multiply
# kernel_size by (sample_rate / 16000). but this needs to be double-checked.
+ self.sample_rate = sample_rate
self.stride = stride
self.wav_norm1d = nn.InstanceNorm1d(1, affine=True)
@@ -70,6 +78,88 @@ def __init__(self, sample_rate: int = 16000, stride: int = 1):
self.pool1d.append(nn.MaxPool1d(3, stride=3, padding=0, dilation=1))
self.norm1d.append(nn.InstanceNorm1d(60, affine=True))
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples.
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames.
+ """
+
+ kernel_size = [251, 3, 5, 3, 5, 3]
+ stride = [self.stride, 3, 1, 3, 1, 3]
+ padding = [0, 0, 0, 0, 0, 0]
+ dilation = [1, 1, 1, 1, 1, 1]
+
+ return multi_conv_num_frames(
+ num_samples,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ dilation=dilation,
+ )
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ kernel_size = [251, 3, 5, 3, 5, 3]
+ stride = [self.stride, 3, 1, 3, 1, 3]
+ padding = [0, 0, 0, 0, 0, 0]
+ dilation = [1, 1, 1, 1, 1, 1]
+
+ return multi_conv_receptive_field_size(
+ num_frames,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ dilation=dilation,
+ )
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ kernel_size = [251, 3, 5, 3, 5, 3]
+ stride = [self.stride, 3, 1, 3, 1, 3]
+ padding = [0, 0, 0, 0, 0, 0]
+ dilation = [1, 1, 1, 1, 1, 1]
+
+ return multi_conv_receptive_field_center(
+ frame,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ dilation=dilation,
+ )
+
def forward(self, waveforms: torch.Tensor) -> torch.Tensor:
"""Pass forward
@@ -83,7 +173,6 @@ def forward(self, waveforms: torch.Tensor) -> torch.Tensor:
for c, (conv1d, pool1d, norm1d) in enumerate(
zip(self.conv1d, self.pool1d, self.norm1d)
):
-
outputs = conv1d(outputs)
# https://github.com/mravanelli/SincNet/issues/4
diff --git a/pyannote/audio/models/embedding/debug.py b/pyannote/audio/models/embedding/debug.py
index 11b3def30..b09283908 100644
--- a/pyannote/audio/models/embedding/debug.py
+++ b/pyannote/audio/models/embedding/debug.py
@@ -1,6 +1,6 @@
# MIT License
#
-# Copyright (c) 2020 CNRS
+# Copyright (c) 2020- CNRS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
# SOFTWARE.
+from functools import lru_cache
from typing import Optional
import torch
@@ -39,7 +40,6 @@ def __init__(
num_channels: int = 1,
task: Optional[Task] = None,
):
-
super().__init__(sample_rate=sample_rate, num_channels=num_channels, task=task)
self.mfcc = MFCC(
@@ -58,6 +58,81 @@ def __init__(
bidirectional=True,
)
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames for a given number of input samples
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames
+
+ Source
+ ------
+ https://pytorch.org/docs/stable/generated/torch.stft.html#torch.stft
+
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ center = self.mfcc.MelSpectrogram.spectrogram.center
+
+ if center:
+ return 1 + num_samples // hop_length
+ else:
+ return 1 + (num_samples - n_fft) // hop_length
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ return n_fft + (num_frames - 1) * hop_length
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ center = self.mfcc.MelSpectrogram.spectrogram.center
+
+ if center:
+ return frame * hop_length
+ else:
+ return frame * hop_length + n_fft // 2
+
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
+ return 64
+
def forward(self, waveforms: torch.Tensor) -> torch.Tensor:
"""
diff --git a/pyannote/audio/models/embedding/wespeaker/__init__.py b/pyannote/audio/models/embedding/wespeaker/__init__.py
index 603a88c64..be51196c1 100644
--- a/pyannote/audio/models/embedding/wespeaker/__init__.py
+++ b/pyannote/audio/models/embedding/wespeaker/__init__.py
@@ -21,29 +21,52 @@
# SOFTWARE.
-from functools import partial
+from functools import lru_cache, partial
from typing import Optional
import torch
+import torch.nn.functional as F
import torchaudio.compliance.kaldi as kaldi
from pyannote.audio.core.model import Model
from pyannote.audio.core.task import Task
+from pyannote.audio.utils.receptive_field import (
+ conv1d_num_frames,
+ conv1d_receptive_field_center,
+ conv1d_receptive_field_size,
+)
from .resnet import ResNet34, ResNet152, ResNet221, ResNet293
class BaseWeSpeakerResNet(Model):
+ """Base class for WeSpeaker's ResNet models
+
+ Parameters
+ ----------
+ fbank_centering_span : float, optional
+ Span of the fbank centering window (in seconds).
+ Defaults (None) to use whole input.
+
+ See also
+ --------
+ torchaudio.compliance.kaldi.fbank
+
+ """
+
def __init__(
self,
sample_rate: int = 16000,
num_channels: int = 1,
num_mel_bins: int = 80,
- frame_length: int = 25,
- frame_shift: int = 10,
+ frame_length: float = 25.0, # in milliseconds
+ frame_shift: float = 10.0, # in milliseconds
+ round_to_power_of_two: bool = True,
+ snip_edges: bool = True,
dither: float = 0.0,
window_type: str = "hamming",
use_energy: bool = False,
+ fbank_centering_span: Optional[float] = None,
task: Optional[Task] = None,
):
super().__init__(sample_rate=sample_rate, num_channels=num_channels, task=task)
@@ -55,21 +78,38 @@ def __init__(
"frame_length",
"frame_shift",
"dither",
+ "round_to_power_of_two",
+ "snip_edges",
"window_type",
"use_energy",
+ "fbank_centering_span",
)
self._fbank = partial(
kaldi.fbank,
num_mel_bins=self.hparams.num_mel_bins,
frame_length=self.hparams.frame_length,
+ round_to_power_of_two=self.hparams.round_to_power_of_two,
frame_shift=self.hparams.frame_shift,
+ snip_edges=self.hparams.snip_edges,
dither=self.hparams.dither,
sample_frequency=self.hparams.sample_rate,
window_type=self.hparams.window_type,
use_energy=self.hparams.use_energy,
)
+ @property
+ def fbank_only(self) -> bool:
+ """Whether to only extract fbank features"""
+ return getattr(self, "_fbank_only", False)
+
+ @fbank_only.setter
+ def fbank_only(self, value: bool):
+ if hasattr(self, "receptive_field"):
+ del self.receptive_field
+
+ self._fbank_only = value
+
def compute_fbank(self, waveforms: torch.Tensor) -> torch.Tensor:
"""Extract fbank features
@@ -80,6 +120,7 @@ def compute_fbank(self, waveforms: torch.Tensor) -> torch.Tensor:
Returns
-------
fbank : (batch_size, num_frames, num_mel_bins)
+ fbank features
Source: https://github.com/wenet-e2e/wespeaker/blob/45941e7cba2c3ea99e232d02bedf617fc71b0dad/wespeaker/bin/infer_onnx.py#L30C1-L50
"""
@@ -93,19 +134,209 @@ def compute_fbank(self, waveforms: torch.Tensor) -> torch.Tensor:
features = torch.vmap(self._fbank)(waveforms.to(fft_device)).to(device)
- return features - torch.mean(features, dim=1, keepdim=True)
+ # center features with global average
+ if self.hparams.fbank_centering_span is None:
+ return features - torch.mean(features, dim=1, keepdim=True)
+
+ # center features with running average
+ window_size = int(self.hparams.sample_rate * self.hparams.frame_length * 0.001)
+ step_size = int(self.hparams.sample_rate * self.hparams.frame_shift * 0.001)
+ kernel_size = conv1d_num_frames(
+ num_samples=int(
+ self.hparams.fbank_centering_span * self.hparams.sample_rate
+ ),
+ kernel_size=window_size,
+ stride=step_size,
+ padding=0,
+ dilation=1,
+ )
+ return features - F.avg_pool1d(
+ features.transpose(1, 2),
+ kernel_size=2 * (kernel_size // 2) + 1,
+ stride=1,
+ padding=kernel_size // 2,
+ count_include_pad=False,
+ ).transpose(1, 2)
+
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
+
+ if self.fbank_only:
+ return self.hparams.num_mel_bins
+
+ return self.resnet.embed_dim
+
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples.
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames.
+ """
+ window_size = int(self.hparams.sample_rate * self.hparams.frame_length * 0.001)
+ step_size = int(self.hparams.sample_rate * self.hparams.frame_shift * 0.001)
+
+ # TODO: take round_to_power_of_two and snip_edges into account
+
+ num_frames = conv1d_num_frames(
+ num_samples=num_samples,
+ kernel_size=window_size,
+ stride=step_size,
+ padding=0,
+ dilation=1,
+ )
+
+ if self.fbank_only:
+ return num_frames
+
+ return self.resnet.num_frames(num_frames)
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ receptive_field_size = num_frames
+
+ if not self.fbank_only:
+ receptive_field_size = self.resnet.receptive_field_size(
+ receptive_field_size
+ )
+
+ window_size = int(self.hparams.sample_rate * self.hparams.frame_length * 0.001)
+ step_size = int(self.hparams.sample_rate * self.hparams.frame_shift * 0.001)
+
+ return conv1d_receptive_field_size(
+ num_frames=receptive_field_size,
+ kernel_size=window_size,
+ stride=step_size,
+ padding=0,
+ dilation=1,
+ )
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+ receptive_field_center = frame
+
+ if not self.fbank_only:
+ receptive_field_center = self.resnet.receptive_field_center(
+ frame=receptive_field_center
+ )
+
+ window_size = int(self.hparams.sample_rate * self.hparams.frame_length * 0.001)
+ step_size = int(self.hparams.sample_rate * self.hparams.frame_shift * 0.001)
+ return conv1d_receptive_field_center(
+ frame=receptive_field_center,
+ kernel_size=window_size,
+ stride=step_size,
+ padding=0,
+ dilation=1,
+ )
def forward(
- self, waveforms: torch.Tensor, weights: torch.Tensor = None
+ self, waveforms: torch.Tensor, weights: Optional[torch.Tensor] = None
) -> torch.Tensor:
+ """Extract speaker embeddings
+
+ Parameters
+ ----------
+ waveforms : torch.Tensor
+ Batch of waveforms with shape (batch, channel, sample)
+ weights : (batch, frames) or (batch, speakers, frames) torch.Tensor, optional
+ Batch of weights passed to statistics pooling layer.
+
+ Returns
+ -------
+ embeddings : (batch, dimension) or (batch, speakers, dimension) torch.Tensor
+ Batch of embeddings.
"""
+ fbank = self.compute_fbank(waveforms)
+ if self.fbank_only:
+ return fbank
+
+ return self.resnet(fbank, weights=weights)[1]
+
+ def forward_frames(self, waveforms: torch.Tensor) -> torch.Tensor:
+ """Extract frame-wise embeddings
+
Parameters
----------
waveforms : torch.Tensor
Batch of waveforms with shape (batch, channel, sample)
- weights : torch.Tensor, optional
- Batch of weights with shape (batch, frame).
+
+ Returns
+ -------
+ embeddings : (batch, ..., embedding_frames) torch.Tensor
+ Batch of frame-wise embeddings.
+ """
+ fbank = self.compute_fbank(waveforms)
+ return self.resnet.forward_frames(fbank)
+
+ def forward_embedding(
+ self, frames: torch.Tensor, weights: torch.Tensor = None
+ ) -> torch.Tensor:
+ """Extract speaker embeddings from frame-wise embeddings
+
+ Parameters
+ ----------
+ frames : torch.Tensor
+ Batch of frames with shape (batch, ..., embedding_frames).
+ weights : (batch, frames) or (batch, speakers, frames) torch.Tensor, optional
+ Batch of weights passed to statistics pooling layer.
+
+ Returns
+ -------
+ embeddings : (batch, dimension) or (batch, speakers, dimension) torch.Tensor
+ Batch of embeddings.
+
+ """
+ return self.resnet.forward_embedding(frames, weights=weights)[1]
+
+ def forward(
+ self, waveforms: torch.Tensor, weights: Optional[torch.Tensor] = None
+ ) -> torch.Tensor:
+ """Extract speaker embeddings
+
+ Parameters
+ ----------
+ waveforms : torch.Tensor
+ Batch of waveforms with shape (batch, channel, sample)
+ weights : (batch, frames) or (batch, speakers, frames) torch.Tensor, optional
+ Batch of weights passed to statistics pooling layer.
+
+ Returns
+ -------
+ embeddings : (batch, dimension) or (batch, speakers, dimension) torch.Tensor
+ Batch of embeddings.
"""
fbank = self.compute_fbank(waveforms)
diff --git a/pyannote/audio/models/embedding/wespeaker/resnet.py b/pyannote/audio/models/embedding/wespeaker/resnet.py
index 54f95fa8b..4c9d5a5f0 100644
--- a/pyannote/audio/models/embedding/wespeaker/resnet.py
+++ b/pyannote/audio/models/embedding/wespeaker/resnet.py
@@ -15,12 +15,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from functools import lru_cache
+from typing import Optional
+
import torch
import torch.nn as nn
import torch.nn.functional as F
from einops import rearrange
from pyannote.audio.models.blocks.pooling import StatsPool
+from pyannote.audio.utils.receptive_field import (
+ conv1d_num_frames,
+ conv1d_receptive_field_center,
+ conv1d_receptive_field_size,
+ multi_conv_num_frames,
+ multi_conv_receptive_field_center,
+ multi_conv_receptive_field_size,
+)
class TSTP(nn.Module):
@@ -35,7 +46,7 @@ def __init__(self, in_dim=0, **kwargs):
self.in_dim = in_dim
self.stats_pool = StatsPool()
- def forward(self, features, weights: torch.Tensor = None):
+ def forward(self, features, weights: Optional[torch.Tensor] = None):
"""
Parameters
@@ -75,6 +86,7 @@ class BasicBlock(nn.Module):
def __init__(self, in_planes, planes, stride=1):
super(BasicBlock, self).__init__()
+ self.stride = stride
self.conv1 = nn.Conv2d(
in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False
)
@@ -97,6 +109,34 @@ def __init__(self, in_planes, planes, stride=1):
nn.BatchNorm2d(self.expansion * planes),
)
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ return multi_conv_num_frames(
+ num_samples,
+ kernel_size=[3, 3],
+ stride=[self.stride, 1],
+ padding=[1, 1],
+ dilation=[1, 1],
+ )
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ return multi_conv_receptive_field_size(
+ num_frames,
+ kernel_size=[3, 3],
+ stride=[self.stride, 1],
+ padding=[1, 1],
+ dilation=[1, 1],
+ )
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ return multi_conv_receptive_field_center(
+ frame,
+ kernel_size=[3, 3],
+ stride=[self.stride, 1],
+ padding=[1, 1],
+ dilation=[1, 1],
+ )
+
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
@@ -110,6 +150,7 @@ class Bottleneck(nn.Module):
def __init__(self, in_planes, planes, stride=1):
super(Bottleneck, self).__init__()
+ self.stride = stride
self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(
@@ -134,6 +175,34 @@ def __init__(self, in_planes, planes, stride=1):
nn.BatchNorm2d(self.expansion * planes),
)
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ return multi_conv_num_frames(
+ num_samples,
+ kernel_size=[1, 3, 1],
+ stride=[1, self.stride, 1],
+ padding=[0, 1, 0],
+ dilation=[1, 1, 1],
+ )
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ return multi_conv_receptive_field_size(
+ num_frames,
+ kernel_size=[1, 3, 1],
+ stride=[1, self.stride, 1],
+ padding=[0, 1, 0],
+ dilation=[1, 1, 1],
+ )
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ return multi_conv_receptive_field_center(
+ frame,
+ kernel_size=[1, 3, 1],
+ stride=[1, self.stride, 1],
+ padding=[0, 1, 0],
+ dilation=[1, 1, 1],
+ )
+
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = F.relu(self.bn2(self.conv2(out)))
@@ -190,12 +259,149 @@ def _make_layer(self, block, planes, num_blocks, stride):
self.in_planes = planes * block.expansion
return nn.Sequential(*layers)
- def forward(self, x: torch.Tensor, weights: torch.Tensor = None):
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples.
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames.
+ """
+
+ num_frames = num_samples
+ num_frames = conv1d_num_frames(
+ num_frames, kernel_size=3, stride=1, padding=1, dilation=1
+ )
+ for layers in [self.layer1, self.layer2, self.layer3, self.layer4]:
+ for layer in layers:
+ num_frames = layer.num_frames(num_frames)
+
+ return num_frames
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
"""
+ receptive_field_size = num_frames
+ for layers in reversed([self.layer1, self.layer2, self.layer3, self.layer4]):
+ for layer in reversed(layers):
+ receptive_field_size = layer.receptive_field_size(receptive_field_size)
+
+ receptive_field_size = conv1d_receptive_field_size(
+ num_frames=receptive_field_size,
+ kernel_size=3,
+ stride=1,
+ padding=1,
+ dilation=1,
+ )
+
+ return receptive_field_size
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
Parameters
----------
- x : (batch, frames, features) torch.Tensor
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ receptive_field_center = frame
+ for layers in reversed([self.layer1, self.layer2, self.layer3, self.layer4]):
+ for layer in reversed(layers):
+ receptive_field_center = layer.receptive_field_center(
+ frame=receptive_field_center
+ )
+
+ receptive_field_center = conv1d_receptive_field_center(
+ frame=receptive_field_center,
+ kernel_size=3,
+ stride=1,
+ padding=1,
+ dilation=1,
+ )
+
+ return receptive_field_center
+
+ def forward_frames(self, fbank: torch.Tensor) -> torch.Tensor:
+ """Extract frame-wise embeddings
+
+ Parameters
+ ----------
+ fbanks : (batch, frames, features) torch.Tensor
+ Batch of fbank features
+
+ Returns
+ -------
+ embeddings : (batch, ..., embedding_frames) torch.Tensor
+ Batch of frame-wise embeddings.
+
+ """
+ fbank = fbank.permute(0, 2, 1) # (B,T,F) => (B,F,T)
+ fbank = fbank.unsqueeze_(1)
+ out = F.relu(self.bn1(self.conv1(fbank)))
+ out = self.layer1(out)
+ out = self.layer2(out)
+ out = self.layer3(out)
+ out = self.layer4(out)
+ return out
+
+ def forward_embedding(
+ self, frames: torch.Tensor, weights: torch.Tensor = None
+ ) -> torch.Tensor:
+ """Extract speaker embeddings
+
+ Parameters
+ ----------
+ frames : torch.Tensor
+ Batch of frames with shape (batch, ..., embedding_frames).
+ weights : (batch, frames) or (batch, speakers, frames) torch.Tensor, optional
+ Batch of weights passed to statistics pooling layer.
+
+ Returns
+ -------
+ embeddings : (batch, dimension) or (batch, speakers, dimension) torch.Tensor
+ Batch of embeddings.
+ """
+
+ stats = self.pool(frames, weights=weights)
+
+ embed_a = self.seg_1(stats)
+ if self.two_emb_layer:
+ out = F.relu(embed_a)
+ out = self.seg_bn_1(out)
+ embed_b = self.seg_2(out)
+ return embed_a, embed_b
+ else:
+ return torch.tensor(0.0), embed_a
+
+ def forward(self, fbank: torch.Tensor, weights: Optional[torch.Tensor] = None):
+ """Extract speaker embeddings
+
+ Parameters
+ ----------
+ fbank : (batch, frames, features) torch.Tensor
Batch of features
weights : (batch, frames) torch.Tensor, optional
Batch of weights
@@ -204,10 +410,9 @@ def forward(self, x: torch.Tensor, weights: torch.Tensor = None):
-------
embedding : (batch, embedding_dim) torch.Tensor
"""
- x = x.permute(0, 2, 1) # (B,T,F) => (B,F,T)
-
- x = x.unsqueeze_(1)
- out = F.relu(self.bn1(self.conv1(x)))
+ fbank = fbank.permute(0, 2, 1) # (B,T,F) => (B,F,T)
+ fbank = fbank.unsqueeze_(1)
+ out = F.relu(self.bn1(self.conv1(fbank)))
out = self.layer1(out)
out = self.layer2(out)
out = self.layer3(out)
diff --git a/pyannote/audio/models/embedding/xvector.py b/pyannote/audio/models/embedding/xvector.py
index 975f0a991..3161876e3 100644
--- a/pyannote/audio/models/embedding/xvector.py
+++ b/pyannote/audio/models/embedding/xvector.py
@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+from functools import lru_cache
from typing import Optional
import torch
@@ -31,17 +32,21 @@
from pyannote.audio.models.blocks.pooling import StatsPool
from pyannote.audio.models.blocks.sincnet import SincNet
from pyannote.audio.utils.params import merge_dict
+from pyannote.audio.utils.receptive_field import (
+ multi_conv_num_frames,
+ multi_conv_receptive_field_center,
+ multi_conv_receptive_field_size,
+)
class XVectorMFCC(Model):
-
MFCC_DEFAULTS = {"n_mfcc": 40, "dct_type": 2, "norm": "ortho", "log_mels": False}
def __init__(
self,
sample_rate: int = 16000,
num_channels: int = 1,
- mfcc: dict = None,
+ mfcc: Optional[dict] = None,
dimension: int = 512,
task: Optional[Task] = None,
):
@@ -57,11 +62,13 @@ def __init__(
self.tdnns = nn.ModuleList()
in_channel = self.hparams.mfcc["n_mfcc"]
out_channels = [512, 512, 512, 512, 1500]
- kernel_sizes = [5, 3, 3, 1, 1]
- dilations = [1, 2, 3, 1, 1]
+ self.kernel_size = [5, 3, 3, 1, 1]
+ self.dilation = [1, 2, 3, 1, 1]
+ self.padding = [0, 0, 0, 0, 0]
+ self.stride = [1, 1, 1, 1, 1]
for out_channel, kernel_size, dilation in zip(
- out_channels, kernel_sizes, dilations
+ out_channels, self.kernel_size, self.dilation
):
self.tdnns.extend(
[
@@ -81,8 +88,102 @@ def __init__(
self.embedding = nn.Linear(in_channel * 2, self.hparams.dimension)
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
+ return self.hparams.dimension
+
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples.
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames.
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ center = self.mfcc.MelSpectrogram.spectrogram.center
+
+ if center:
+ num_frames = 1 + num_samples // hop_length
+ else:
+ num_frames = 1 + (num_samples - n_fft) // hop_length
+
+ return multi_conv_num_frames(
+ num_frames,
+ kernel_size=self.kernel_size,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ )
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ receptive_field_size = multi_conv_receptive_field_size(
+ num_frames,
+ kernel_size=self.kernel_size,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ )
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ return n_fft + (receptive_field_size - 1) * hop_length
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ receptive_field_center = multi_conv_receptive_field_center(
+ frame,
+ kernel_size=self.kernel_size,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ )
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ center = self.mfcc.MelSpectrogram.spectrogram.center
+
+ if center:
+ return receptive_field_center * hop_length
+ else:
+ return receptive_field_center * hop_length + n_fft // 2
+
def forward(
- self, waveforms: torch.Tensor, weights: torch.Tensor = None
+ self, waveforms: torch.Tensor, weights: Optional[torch.Tensor] = None
) -> torch.Tensor:
"""
@@ -102,14 +203,13 @@ def forward(
class XVectorSincNet(Model):
-
SINCNET_DEFAULTS = {"stride": 10}
def __init__(
self,
sample_rate: int = 16000,
num_channels: int = 1,
- sincnet: dict = None,
+ sincnet: Optional[dict] = None,
dimension: int = 512,
task: Optional[Task] = None,
):
@@ -125,11 +225,13 @@ def __init__(
self.tdnns = nn.ModuleList()
out_channels = [512, 512, 512, 512, 1500]
- kernel_sizes = [5, 3, 3, 1, 1]
- dilations = [1, 2, 3, 1, 1]
+ self.kernel_size = [5, 3, 3, 1, 1]
+ self.dilation = [1, 2, 3, 1, 1]
+ self.padding = [0, 0, 0, 0, 0]
+ self.stride = [1, 1, 1, 1, 1]
for out_channel, kernel_size, dilation in zip(
- out_channels, kernel_sizes, dilations
+ out_channels, self.kernel_size, self.dilation
):
self.tdnns.extend(
[
@@ -149,8 +251,86 @@ def __init__(
self.embedding = nn.Linear(in_channel * 2, self.hparams.dimension)
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
+ return self.hparams.dimension
+
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples.
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames.
+ """
+
+ num_frames = self.sincnet.num_frames(num_samples)
+
+ return multi_conv_num_frames(
+ num_frames,
+ kernel_size=self.kernel_size,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ )
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ receptive_field_size = multi_conv_receptive_field_size(
+ num_frames,
+ kernel_size=self.kernel_size,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ )
+
+ return self.sincnet.receptive_field_size(num_frames=receptive_field_size)
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ receptive_field_center = multi_conv_receptive_field_center(
+ frame,
+ kernel_size=self.kernel_size,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ )
+
+ return self.sincnet.receptive_field_center(frame=receptive_field_center)
+
def forward(
- self, waveforms: torch.Tensor, weights: torch.Tensor = None
+ self, waveforms: torch.Tensor, weights: Optional[torch.Tensor] = None
) -> torch.Tensor:
"""
diff --git a/pyannote/audio/models/segmentation/PyanNet.py b/pyannote/audio/models/segmentation/PyanNet.py
index 5af3734b1..3481b40c6 100644
--- a/pyannote/audio/models/segmentation/PyanNet.py
+++ b/pyannote/audio/models/segmentation/PyanNet.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-
+from functools import lru_cache
from typing import Optional
import torch
@@ -73,9 +73,9 @@ class PyanNet(Model):
def __init__(
self,
- sincnet: dict = None,
- lstm: dict = None,
- linear: dict = None,
+ sincnet: Optional[dict] = None,
+ lstm: Optional[dict] = None,
+ linear: Optional[dict] = None,
sample_rate: int = 16000,
num_channels: int = 1,
task: Optional[Task] = None,
@@ -138,6 +138,17 @@ def __init__(
]
)
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
+ if isinstance(self.specifications, tuple):
+ raise ValueError("PyanNet does not support multi-tasking.")
+
+ if self.specifications.powerset:
+ return self.specifications.num_powerset_classes
+ else:
+ return len(self.specifications.classes)
+
def build(self):
if self.hparams.linear["num_layers"] > 0:
in_features = self.hparams.linear["hidden_size"]
@@ -146,16 +157,56 @@ def build(self):
2 if self.hparams.lstm["bidirectional"] else 1
)
- if isinstance(self.specifications, tuple):
- raise ValueError("PyanNet does not support multi-tasking.")
+ self.classifier = nn.Linear(in_features, self.dimension)
+ self.activation = self.default_activation()
- if self.specifications.powerset:
- out_features = self.specifications.num_powerset_classes
- else:
- out_features = len(self.specifications.classes)
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames for a given number of input samples
- self.classifier = nn.Linear(in_features, out_features)
- self.activation = self.default_activation()
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames
+ """
+
+ return self.sincnet.num_frames(num_samples)
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+ return self.sincnet.receptive_field_size(num_frames=num_frames)
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ return self.sincnet.receptive_field_center(frame=frame)
def forward(self, waveforms: torch.Tensor) -> torch.Tensor:
"""Pass forward
diff --git a/pyannote/audio/models/segmentation/SSeRiouSS.py b/pyannote/audio/models/segmentation/SSeRiouSS.py
index 7cd545177..b96464ab3 100644
--- a/pyannote/audio/models/segmentation/SSeRiouSS.py
+++ b/pyannote/audio/models/segmentation/SSeRiouSS.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-
+from functools import lru_cache
from typing import Optional, Union
import torch
@@ -32,6 +32,11 @@
from pyannote.audio.core.model import Model
from pyannote.audio.core.task import Task
from pyannote.audio.utils.params import merge_dict
+from pyannote.audio.utils.receptive_field import (
+ conv1d_num_frames,
+ conv1d_receptive_field_center,
+ conv1d_receptive_field_size,
+)
class SSeRiouSS(Model):
@@ -77,8 +82,8 @@ def __init__(
self,
wav2vec: Union[dict, str] = None,
wav2vec_layer: int = -1,
- lstm: dict = None,
- linear: dict = None,
+ lstm: Optional[dict] = None,
+ linear: Optional[dict] = None,
sample_rate: int = 16000,
num_channels: int = 1,
task: Optional[Task] = None,
@@ -144,9 +149,12 @@ def __init__(
self.lstm = nn.ModuleList(
[
nn.LSTM(
- wav2vec_dim
- if i == 0
- else lstm["hidden_size"] * (2 if lstm["bidirectional"] else 1),
+ (
+ wav2vec_dim
+ if i == 0
+ else lstm["hidden_size"]
+ * (2 if lstm["bidirectional"] else 1)
+ ),
**one_layer_lstm,
)
for i in range(num_layers)
@@ -172,6 +180,17 @@ def __init__(
]
)
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
+ if isinstance(self.specifications, tuple):
+ raise ValueError("SSeRiouSS does not support multi-tasking.")
+
+ if self.specifications.powerset:
+ return self.specifications.num_powerset_classes
+ else:
+ return len(self.specifications.classes)
+
def build(self):
if self.hparams.linear["num_layers"] > 0:
in_features = self.hparams.linear["hidden_size"]
@@ -180,16 +199,84 @@ def build(self):
2 if self.hparams.lstm["bidirectional"] else 1
)
- if isinstance(self.specifications, tuple):
- raise ValueError("SSeRiouSS model does not support multi-tasking.")
+ self.classifier = nn.Linear(in_features, self.dimension)
+ self.activation = self.default_activation()
- if self.specifications.powerset:
- out_features = self.specifications.num_powerset_classes
- else:
- out_features = len(self.specifications.classes)
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames
- self.classifier = nn.Linear(in_features, out_features)
- self.activation = self.default_activation()
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples.
+
+ Returns
+ -------
+ num_frames : int
+ Number of output frames.
+ """
+
+ num_frames = num_samples
+ for conv_layer in self.wav2vec.feature_extractor.conv_layers:
+ num_frames = conv1d_num_frames(
+ num_frames,
+ kernel_size=conv_layer.kernel_size,
+ stride=conv_layer.stride,
+ padding=conv_layer.conv.padding[0],
+ dilation=conv_layer.conv.dilation[0],
+ )
+
+ return num_frames
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ receptive_field_size = num_frames
+ for conv_layer in reversed(self.wav2vec.feature_extractor.conv_layers):
+ receptive_field_size = conv1d_receptive_field_size(
+ num_frames=receptive_field_size,
+ kernel_size=conv_layer.kernel_size,
+ stride=conv_layer.stride,
+ padding=conv_layer.conv.padding[0],
+ dilation=conv_layer.conv.dilation[0],
+ )
+ return receptive_field_size
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+ receptive_field_center = frame
+ for conv_layer in reversed(self.wav2vec.feature_extractor.conv_layers):
+ receptive_field_center = conv1d_receptive_field_center(
+ receptive_field_center,
+ kernel_size=conv_layer.kernel_size,
+ stride=conv_layer.stride,
+ padding=conv_layer.conv.padding[0],
+ dilation=conv_layer.conv.dilation[0],
+ )
+ return receptive_field_center
def forward(self, waveforms: torch.Tensor) -> torch.Tensor:
"""Pass forward
diff --git a/pyannote/audio/models/segmentation/debug.py b/pyannote/audio/models/segmentation/debug.py
index 89512320c..ccac612a9 100644
--- a/pyannote/audio/models/segmentation/debug.py
+++ b/pyannote/audio/models/segmentation/debug.py
@@ -21,6 +21,7 @@
# SOFTWARE.
+from functools import lru_cache
from typing import Optional
import torch
@@ -57,18 +58,91 @@ def __init__(
bidirectional=True,
)
- def build(self):
- # define task-dependent layers
+ @lru_cache
+ def num_frames(self, num_samples: int) -> int:
+ """Compute number of output frames for a given number of input samples
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of input samples
+ Returns
+ -------
+ num_frames : int
+ Number of output frames
+
+ Source
+ ------
+ https://pytorch.org/docs/stable/generated/torch.stft.html#torch.stft
+
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ center = self.mfcc.MelSpectrogram.spectrogram.center
+
+ if center:
+ return 1 + num_samples // hop_length
+ else:
+ return 1 + (num_samples - n_fft) // hop_length
+
+ def receptive_field_size(self, num_frames: int = 1) -> int:
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+
+ Returns
+ -------
+ receptive_field_size : int
+ Receptive field size.
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ return n_fft + (num_frames - 1) * hop_length
+
+ def receptive_field_center(self, frame: int = 0) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int, optional
+ Frame index
+
+ Returns
+ -------
+ receptive_field_center : int
+ Index of receptive field center.
+ """
+
+ hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length
+ n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft
+ center = self.mfcc.MelSpectrogram.spectrogram.center
+
+ if center:
+ return frame * hop_length
+ else:
+ return frame * hop_length + n_fft // 2
+
+ @property
+ def dimension(self) -> int:
+ """Dimension of output"""
if isinstance(self.specifications, tuple):
raise ValueError("SimpleSegmentationModel does not support multi-tasking.")
if self.specifications.powerset:
- out_features = self.specifications.num_powerset_classes
+ return self.specifications.num_powerset_classes
else:
- out_features = len(self.specifications.classes)
+ return len(self.specifications.classes)
+
+ def build(self):
+ # define task-dependent layers
- self.classifier = nn.Linear(32 * 2, out_features)
+ self.classifier = nn.Linear(32 * 2, self.dimension)
self.activation = self.default_activation()
def forward(self, waveforms: torch.Tensor) -> torch.Tensor:
diff --git a/pyannote/audio/pipelines/clustering.py b/pyannote/audio/pipelines/clustering.py
index 80098ea24..cd4b38935 100644
--- a/pyannote/audio/pipelines/clustering.py
+++ b/pyannote/audio/pipelines/clustering.py
@@ -25,7 +25,7 @@
import random
from enum import Enum
-from typing import Tuple
+from typing import Optional, Tuple
import numpy as np
from einops import rearrange
@@ -56,9 +56,9 @@ def __init__(
def set_num_clusters(
self,
num_embeddings: int,
- num_clusters: int = None,
- min_clusters: int = None,
- max_clusters: int = None,
+ num_clusters: Optional[int] = None,
+ min_clusters: Optional[int] = None,
+ max_clusters: Optional[int] = None,
):
min_clusters = num_clusters or min_clusters or 1
min_clusters = max(1, min(num_embeddings, min_clusters))
@@ -79,7 +79,7 @@ def set_num_clusters(
def filter_embeddings(
self,
embeddings: np.ndarray,
- segmentations: SlidingWindowFeature = None,
+ segmentations: Optional[SlidingWindowFeature] = None,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Filter NaN embeddings and downsample embeddings
@@ -205,10 +205,10 @@ def assign_embeddings(
def __call__(
self,
embeddings: np.ndarray,
- segmentations: SlidingWindowFeature = None,
- num_clusters: int = None,
- min_clusters: int = None,
- max_clusters: int = None,
+ segmentations: Optional[SlidingWindowFeature] = None,
+ num_clusters: Optional[int] = None,
+ min_clusters: Optional[int] = None,
+ max_clusters: Optional[int] = None,
**kwargs,
) -> np.ndarray:
"""Apply clustering
@@ -323,7 +323,7 @@ def cluster(
embeddings: np.ndarray,
min_clusters: int,
max_clusters: int,
- num_clusters: int = None,
+ num_clusters: Optional[int] = None,
):
"""
@@ -476,10 +476,10 @@ class OracleClustering(BaseClustering):
def __call__(
self,
- embeddings: np.ndarray = None,
- segmentations: SlidingWindowFeature = None,
- file: AudioFile = None,
- frames: SlidingWindow = None,
+ embeddings: Optional[np.ndarray] = None,
+ segmentations: Optional[SlidingWindowFeature] = None,
+ file: Optional[AudioFile] = None,
+ frames: Optional[SlidingWindow] = None,
**kwargs,
) -> np.ndarray:
"""Apply oracle clustering
diff --git a/pyannote/audio/pipelines/multilabel.py b/pyannote/audio/pipelines/multilabel.py
index 18693f14c..b35ebee7c 100644
--- a/pyannote/audio/pipelines/multilabel.py
+++ b/pyannote/audio/pipelines/multilabel.py
@@ -75,7 +75,7 @@ class MultiLabelSegmentation(Pipeline):
def __init__(
self,
- segmentation: PipelineModel = None,
+ segmentation: Optional[PipelineModel] = None,
fscore: bool = False,
share_min_duration: bool = False,
use_auth_token: Union[Text, None] = None,
diff --git a/pyannote/audio/pipelines/overlapped_speech_detection.py b/pyannote/audio/pipelines/overlapped_speech_detection.py
index 1c9790feb..1429e4299 100644
--- a/pyannote/audio/pipelines/overlapped_speech_detection.py
+++ b/pyannote/audio/pipelines/overlapped_speech_detection.py
@@ -128,7 +128,7 @@ def __init__(
# load model
model = get_model(segmentation, use_auth_token=use_auth_token)
- if model.example_output.dimension > 1:
+ if model.dimension > 1:
inference_kwargs["pre_aggregation_hook"] = lambda scores: np.partition(
scores, -2, axis=-1
)[:, :, -2, np.newaxis]
@@ -255,7 +255,7 @@ def compute_components(
_self,
reference: Annotation,
hypothesis: Annotation,
- uem: Timeline = None,
+ uem: Optional[Timeline] = None,
**kwargs,
) -> dict:
return super().compute_components(
diff --git a/pyannote/audio/pipelines/resegmentation.py b/pyannote/audio/pipelines/resegmentation.py
index d01e5d65f..85492f774 100644
--- a/pyannote/audio/pipelines/resegmentation.py
+++ b/pyannote/audio/pipelines/resegmentation.py
@@ -86,7 +86,7 @@ def __init__(
self,
segmentation: PipelineModel = "pyannote/segmentation",
diarization: Text = "diarization",
- der_variant: dict = None,
+ der_variant: Optional[dict] = None,
use_auth_token: Union[Text, None] = None,
):
super().__init__()
@@ -96,7 +96,6 @@ def __init__(
model: Model = get_model(segmentation, use_auth_token=use_auth_token)
self._segmentation = Inference(model)
- self._frames = self._segmentation.model.example_output.frames
self._audio = model.audio
@@ -137,7 +136,7 @@ def classes(self):
def apply(
self,
file: AudioFile,
- diarization: Annotation = None,
+ diarization: Optional[Annotation] = None,
hook: Optional[Callable] = None,
) -> Annotation:
"""Apply speaker diarization
@@ -193,8 +192,8 @@ def apply(
# estimate frame-level number of instantaneous speakers
count = self.speaker_count(
binarized_segmentations,
+ self._segmentation.model.receptive_field,
warm_up=(self.warm_up, self.warm_up),
- frames=self._frames,
)
hook("speaker_counting", count)
@@ -205,7 +204,7 @@ def apply(
support=Segment(
0.0, self._audio.get_duration(file) + self._segmentation.step
),
- resolution=self._frames,
+ resolution=self._segmentation.model.receptive_field,
)
hook("@resegmentation/original", diarization)
diff --git a/pyannote/audio/pipelines/speaker_diarization.py b/pyannote/audio/pipelines/speaker_diarization.py
index 354f6be7e..737cd1cb2 100644
--- a/pyannote/audio/pipelines/speaker_diarization.py
+++ b/pyannote/audio/pipelines/speaker_diarization.py
@@ -32,7 +32,7 @@
import numpy as np
import torch
from einops import rearrange
-from pyannote.core import Annotation, SlidingWindow, SlidingWindowFeature
+from pyannote.core import Annotation, SlidingWindowFeature
from pyannote.metrics.diarization import GreedyDiarizationErrorRate
from pyannote.pipeline.parameter import ParamDict, Uniform
@@ -121,7 +121,7 @@ def __init__(
clustering: str = "AgglomerativeClustering",
embedding_batch_size: int = 1,
segmentation_batch_size: int = 1,
- der_variant: dict = None,
+ der_variant: Optional[dict] = None,
use_auth_token: Union[Text, None] = None,
):
super().__init__()
@@ -147,7 +147,6 @@ def __init__(
skip_aggregation=True,
batch_size=segmentation_batch_size,
)
- self._frames: SlidingWindow = self._segmentation.model.example_output.frames
if self._segmentation.model.specifications.powerset:
self.segmentation = ParamDict(
@@ -428,9 +427,9 @@ def reconstruct(
def apply(
self,
file: AudioFile,
- num_speakers: int = None,
- min_speakers: int = None,
- max_speakers: int = None,
+ num_speakers: Optional[int] = None,
+ min_speakers: Optional[int] = None,
+ max_speakers: Optional[int] = None,
return_embeddings: bool = False,
hook: Optional[Callable] = None,
) -> Annotation:
@@ -493,7 +492,7 @@ def apply(
# estimate frame-level number of instantaneous speakers
count = self.speaker_count(
binarized_segmentations,
- frames=self._frames,
+ self._segmentation.model.receptive_field,
warm_up=(0.0, 0.0),
)
hook("speaker_counting", count)
@@ -527,7 +526,7 @@ def apply(
min_clusters=min_speakers,
max_clusters=max_speakers,
file=file, # <== for oracle clustering
- frames=self._frames, # <== for oracle clustering
+ frames=self._segmentation.model.receptive_field, # <== for oracle clustering
)
# hard_clusters: (num_chunks, num_speakers)
# centroids: (num_speakers, dimension)
@@ -538,15 +537,20 @@ def apply(
# detected number of speakers can still be out of bounds
# (specifically, lower than `min_speakers`), since there could be too few embeddings
# to make enough clusters with a given minimum cluster size.
- if num_different_speakers < min_speakers or num_different_speakers > max_speakers:
- warnings.warn(textwrap.dedent(
- f"""
+ if (
+ num_different_speakers < min_speakers
+ or num_different_speakers > max_speakers
+ ):
+ warnings.warn(
+ textwrap.dedent(
+ f"""
The detected number of speakers ({num_different_speakers}) is outside
the given bounds [{min_speakers}, {max_speakers}]. This can happen if the
given audio file is too short to contain {min_speakers} or more speakers.
Try to lower the desired minimal number of speakers.
"""
- ))
+ )
+ )
# during counting, we could possibly overcount the number of instantaneous
# speakers due to segmentation errors, so we cap the maximum instantaneous number
@@ -618,7 +622,9 @@ def apply(
# of clusters obtained from `clustering`. In this case, we append zero embeddings
# for extra speakers
if len(diarization.labels()) > centroids.shape[0]:
- centroids = np.pad(centroids, ((0, len(diarization.labels()) - centroids.shape[0]), (0, 0)))
+ centroids = np.pad(
+ centroids, ((0, len(diarization.labels()) - centroids.shape[0]), (0, 0))
+ )
# re-order centroids so that they match
# the order given by diarization.labels()
diff --git a/pyannote/audio/pipelines/speaker_verification.py b/pyannote/audio/pipelines/speaker_verification.py
index c870ea622..8c4139b6f 100644
--- a/pyannote/audio/pipelines/speaker_verification.py
+++ b/pyannote/audio/pipelines/speaker_verification.py
@@ -23,12 +23,11 @@
import warnings
from functools import cached_property
from pathlib import Path
-from typing import Text, Union
+from typing import Optional, Text, Union
import numpy as np
import torch
import torch.nn.functional as F
-import torchaudio
import torchaudio.compliance.kaldi as kaldi
from huggingface_hub import hf_hub_download
from huggingface_hub.utils import RepositoryNotFoundError
@@ -40,7 +39,6 @@
from pyannote.audio.core.model import CACHE_DIR
from pyannote.audio.pipelines.utils import PipelineModel, get_model
-backend = torchaudio.get_audio_backend()
try:
from speechbrain.pretrained import (
EncoderClassifier as SpeechBrain_EncoderClassifier,
@@ -49,8 +47,6 @@
SPEECHBRAIN_IS_AVAILABLE = True
except ImportError:
SPEECHBRAIN_IS_AVAILABLE = False
-finally:
- torchaudio.set_audio_backend(backend)
try:
from nemo.collections.asr.models import (
@@ -73,7 +69,7 @@ class NeMoPretrainedSpeakerEmbedding(BaseInference):
def __init__(
self,
embedding: Text = "nvidia/speakerverification_en_titanet_large",
- device: torch.device = None,
+ device: Optional[torch.device] = None,
):
if not NEMO_IS_AVAILABLE:
raise ImportError(
@@ -139,7 +135,7 @@ def min_num_samples(self) -> int:
return upper
def __call__(
- self, waveforms: torch.Tensor, masks: torch.Tensor = None
+ self, waveforms: torch.Tensor, masks: Optional[torch.Tensor] = None
) -> np.ndarray:
"""
@@ -238,7 +234,7 @@ class SpeechBrainPretrainedSpeakerEmbedding(BaseInference):
def __init__(
self,
embedding: Text = "speechbrain/spkrec-ecapa-voxceleb",
- device: torch.device = None,
+ device: Optional[torch.device] = None,
use_auth_token: Union[Text, None] = None,
):
if not SPEECHBRAIN_IS_AVAILABLE:
@@ -314,7 +310,7 @@ def min_num_samples(self) -> int:
return upper
def __call__(
- self, waveforms: torch.Tensor, masks: torch.Tensor = None
+ self, waveforms: torch.Tensor, masks: Optional[torch.Tensor] = None
) -> np.ndarray:
"""
@@ -414,7 +410,7 @@ class ONNXWeSpeakerPretrainedSpeakerEmbedding(BaseInference):
def __init__(
self,
embedding: Text = "hbredin/wespeaker-voxceleb-resnet34-LM",
- device: torch.device = None,
+ device: Optional[torch.device] = None,
):
if not ONNX_IS_AVAILABLE:
raise ImportError(
@@ -560,7 +556,7 @@ def compute_fbank(
return features - torch.mean(features, dim=1, keepdim=True)
def __call__(
- self, waveforms: torch.Tensor, masks: torch.Tensor = None
+ self, waveforms: torch.Tensor, masks: Optional[torch.Tensor] = None
) -> np.ndarray:
"""
@@ -645,7 +641,7 @@ class PyannoteAudioPretrainedSpeakerEmbedding(BaseInference):
def __init__(
self,
embedding: PipelineModel = "pyannote/embedding",
- device: torch.device = None,
+ device: Optional[torch.device] = None,
use_auth_token: Union[Text, None] = None,
):
super().__init__()
@@ -672,7 +668,7 @@ def sample_rate(self) -> int:
@cached_property
def dimension(self) -> int:
- return self.model_.example_output.dimension
+ return self.model_.dimension
@cached_property
def metric(self) -> str:
@@ -695,7 +691,7 @@ def min_num_samples(self) -> int:
return upper
def __call__(
- self, waveforms: torch.Tensor, masks: torch.Tensor = None
+ self, waveforms: torch.Tensor, masks: Optional[torch.Tensor] = None
) -> np.ndarray:
with torch.inference_mode():
if masks is None:
@@ -711,7 +707,7 @@ def __call__(
def PretrainedSpeakerEmbedding(
embedding: PipelineModel,
- device: torch.device = None,
+ device: Optional[torch.device] = None,
use_auth_token: Union[Text, None] = None,
):
"""Pretrained speaker embedding
@@ -801,7 +797,7 @@ class SpeakerEmbedding(Pipeline):
def __init__(
self,
embedding: PipelineModel = "pyannote/embedding",
- segmentation: PipelineModel = None,
+ segmentation: Optional[PipelineModel] = None,
use_auth_token: Union[Text, None] = None,
):
super().__init__()
@@ -848,7 +844,7 @@ def main(
protocol: str = "VoxCeleb.SpeakerVerification.VoxCeleb1",
subset: str = "test",
embedding: str = "pyannote/embedding",
- segmentation: str = None,
+ segmentation: Optional[str] = None,
):
import typer
from pyannote.database import FileFinder, get_protocol
diff --git a/pyannote/audio/pipelines/utils/diarization.py b/pyannote/audio/pipelines/utils/diarization.py
index 4a35f7049..5a0f8f675 100644
--- a/pyannote/audio/pipelines/utils/diarization.py
+++ b/pyannote/audio/pipelines/utils/diarization.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from typing import Dict, Mapping, Tuple, Union
+from typing import Dict, Mapping, Optional, Tuple, Union
import numpy as np
from pyannote.core import Annotation, SlidingWindow, SlidingWindowFeature
@@ -28,7 +28,7 @@
from pyannote.metrics.diarization import DiarizationErrorRate
from pyannote.audio.core.inference import Inference
-from pyannote.audio.utils.signal import Binarize, binarize
+from pyannote.audio.utils.signal import Binarize
# TODO: move to dedicated module
@@ -37,9 +37,9 @@ class SpeakerDiarizationMixin:
@staticmethod
def set_num_speakers(
- num_speakers: int = None,
- min_speakers: int = None,
- max_speakers: int = None,
+ num_speakers: Optional[int] = None,
+ min_speakers: Optional[int] = None,
+ max_speakers: Optional[int] = None,
):
"""Validate number of speakers
@@ -121,8 +121,8 @@ def optimal_mapping(
@staticmethod
def speaker_count(
binarized_segmentations: SlidingWindowFeature,
+ frames: SlidingWindow,
warm_up: Tuple[float, float] = (0.1, 0.1),
- frames: SlidingWindow = None,
) -> SlidingWindowFeature:
"""Estimate frame-level number of instantaneous speakers
@@ -133,7 +133,7 @@ def speaker_count(
warm_up : (float, float) tuple, optional
Left/right warm up ratio of chunk duration.
Defaults to (0.1, 0.1), i.e. 10% on both sides.
- frames : SlidingWindow, optional
+ frames : SlidingWindow
Frames resolution. Defaults to estimate it automatically based on
`segmentations` shape and chunk size. Providing the exact frame
resolution (when known) leads to better temporal precision.
@@ -147,7 +147,7 @@ def speaker_count(
trimmed = Inference.trim(binarized_segmentations, warm_up=warm_up)
count = Inference.aggregate(
np.sum(trimmed, axis=-1, keepdims=True),
- frames=frames,
+ frames,
hamming=False,
missing=0.0,
skip_average=False,
@@ -212,7 +212,7 @@ def to_diarization(
# TODO: investigate alternative aggregation
activations = Inference.aggregate(
segmentations,
- frames=count.sliding_window,
+ count.sliding_window,
hamming=False,
missing=0.0,
skip_average=True,
diff --git a/pyannote/audio/pipelines/utils/getter.py b/pyannote/audio/pipelines/utils/getter.py
index 4c589ad05..51040d1c4 100644
--- a/pyannote/audio/pipelines/utils/getter.py
+++ b/pyannote/audio/pipelines/utils/getter.py
@@ -21,7 +21,7 @@
# SOFTWARE.
import itertools
-from typing import Mapping, Text, Union
+from typing import Mapping, Optional, Text, Union
import torch
from torch_audiomentations.core.transforms_interface import BaseWaveformTransform
@@ -171,7 +171,7 @@ def get_augmentation(augmentation: PipelineAugmentation) -> BaseWaveformTransfor
)
-def get_devices(needs: int = None):
+def get_devices(needs: Optional[int] = None):
"""Get devices that can be used by the pipeline
Parameters
diff --git a/pyannote/audio/pipelines/utils/hook.py b/pyannote/audio/pipelines/utils/hook.py
index 2a675d1c9..db6972e2e 100644
--- a/pyannote/audio/pipelines/utils/hook.py
+++ b/pyannote/audio/pipelines/utils/hook.py
@@ -24,6 +24,7 @@
from copy import deepcopy
from typing import Any, Mapping, Optional, Text
+import torch
from rich.progress import (
BarColumn,
Progress,
@@ -75,6 +76,9 @@ def __call__(
):
return
+ if isinstance(step_artifact, torch.Tensor):
+ step_artifact = step_artifact.numpy(force=True)
+
file.setdefault(self.file_key, dict())[step_name] = deepcopy(step_artifact)
diff --git a/pyannote/audio/pipelines/utils/oracle.py b/pyannote/audio/pipelines/utils/oracle.py
index 44b4ded61..24401f752 100644
--- a/pyannote/audio/pipelines/utils/oracle.py
+++ b/pyannote/audio/pipelines/utils/oracle.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from typing import Union
+from typing import Optional, Union
import numpy as np
from pyannote.core import Annotation, Segment, SlidingWindow, SlidingWindowFeature
@@ -32,14 +32,14 @@ def oracle_segmentation(
file: AudioFile,
window: SlidingWindow,
frames: Union[SlidingWindow, float],
- num_speakers: int = None,
+ num_speakers: Optional[int] = None,
) -> SlidingWindowFeature:
"""Oracle speaker segmentation
Simulates inference based on an (imaginary) oracle segmentation model:
>>> oracle = Model.from_pretrained("oracle")
- >>> assert frames == oracle.example_output.frames
+ >>> assert frames == oracle.receptive_field
>>> inference = Inference(oracle, duration=window.duration, step=window.step, skip_aggregation=True)
>>> oracle_segmentation = inference(file)
diff --git a/pyannote/audio/pipelines/voice_activity_detection.py b/pyannote/audio/pipelines/voice_activity_detection.py
index f67489b64..39e529d89 100644
--- a/pyannote/audio/pipelines/voice_activity_detection.py
+++ b/pyannote/audio/pipelines/voice_activity_detection.py
@@ -284,7 +284,7 @@ class AdaptiveVoiceActivityDetection(Pipeline):
def __init__(
self,
segmentation: PipelineInference = "hbredin/VoiceActivityDetection-PyanNet-DIHARD",
- augmentation: PipelineAugmentation = None,
+ augmentation: Optional[PipelineAugmentation] = None,
fscore: bool = False,
):
super().__init__()
diff --git a/pyannote/audio/sample/__init__.py b/pyannote/audio/sample/__init__.py
new file mode 100644
index 000000000..85399af66
--- /dev/null
+++ b/pyannote/audio/sample/__init__.py
@@ -0,0 +1,56 @@
+# MIT License
+#
+# Copyright (c) 2024- CNRS
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+from pathlib import Path
+
+from pyannote.core import Annotation, Segment, Timeline
+from pyannote.database.util import load_rttm
+
+from pyannote.audio.core.io import Audio, AudioFile
+
+
+def _sample() -> AudioFile:
+ sample_wav = Path(__file__).parent / "sample.wav"
+ uri = "sample"
+
+ audio = Audio()
+ waveform, sample_rate = audio(sample_wav)
+
+ sample_rttm = Path(__file__).parent / "sample.rttm"
+
+ annotation: Annotation = load_rttm(sample_rttm)[uri]
+ duration = audio.get_duration(sample_wav)
+
+ annotated: Timeline = Timeline([Segment(0.0, duration)], uri=uri)
+
+ return {
+ "audio": sample_wav,
+ "uri": "sample",
+ "waveform": waveform,
+ "sample_rate": sample_rate,
+ "annotation": annotation,
+ "annotated": annotated,
+ }
+
+
+SAMPLE_FILE = _sample()
diff --git a/pyannote/audio/sample/sample.rttm b/pyannote/audio/sample/sample.rttm
new file mode 100644
index 000000000..7c6b378fe
--- /dev/null
+++ b/pyannote/audio/sample/sample.rttm
@@ -0,0 +1,10 @@
+SPEAKER sample 1 6.690 0.430 speaker90
+SPEAKER sample 1 7.550 0.800 speaker91
+SPEAKER sample 1 8.320 1.700 speaker90
+SPEAKER sample 1 9.920 1.110 speaker91
+SPEAKER sample 1 10.570 4.130 speaker90
+SPEAKER sample 1 14.490 3.430 speaker91
+SPEAKER sample 1 18.050 3.440 speaker90
+SPEAKER sample 1 18.150 0.440 speaker91
+SPEAKER sample 1 21.780 6.720 speaker91
+SPEAKER sample 1 27.850 2.150 speaker90
diff --git a/pyannote/audio/sample/sample.wav b/pyannote/audio/sample/sample.wav
new file mode 100644
index 000000000..150d49a69
Binary files /dev/null and b/pyannote/audio/sample/sample.wav differ
diff --git a/pyannote/audio/tasks/embedding/arcface.py b/pyannote/audio/tasks/embedding/arcface.py
index bb2cb1f6c..cb6401e2b 100644
--- a/pyannote/audio/tasks/embedding/arcface.py
+++ b/pyannote/audio/tasks/embedding/arcface.py
@@ -23,7 +23,7 @@
from __future__ import annotations
-from typing import Dict, Sequence, Union
+from typing import Dict, Optional, Sequence, Union
import pytorch_metric_learning.losses
from pyannote.database import Protocol
@@ -82,15 +82,15 @@ class SupervisedRepresentationLearningWithArcFace(
def __init__(
self,
protocol: Protocol,
- min_duration: float = None,
+ min_duration: Optional[float] = None,
duration: float = 2.0,
num_classes_per_batch: int = 32,
num_chunks_per_class: int = 1,
margin: float = 28.6,
scale: float = 64.0,
- num_workers: int = None,
+ num_workers: Optional[int] = None,
pin_memory: bool = False,
- augmentation: BaseWaveformTransform = None,
+ augmentation: Optional[BaseWaveformTransform] = None,
metric: Union[Metric, Sequence[Metric], Dict[str, Metric]] = None,
):
diff --git a/pyannote/audio/tasks/embedding/mixins.py b/pyannote/audio/tasks/embedding/mixins.py
index da164f04e..9b404f9cf 100644
--- a/pyannote/audio/tasks/embedding/mixins.py
+++ b/pyannote/audio/tasks/embedding/mixins.py
@@ -75,7 +75,7 @@ def batch_size(self) -> int:
def batch_size(self, batch_size: int):
self.batch_size_ = batch_size
- def setup(self):
+ def setup(self, stage=None):
# loop over the training set, remove annotated regions shorter than
# chunk duration, and keep track of the reference annotations, per class.
@@ -119,12 +119,6 @@ def setup(self):
classes=sorted(self._train),
)
- if not self.has_validation:
- return
-
- if isinstance(self.protocol, SpeakerVerificationProtocol):
- self._validation = list(self.protocol.development_trial())
-
def default_metric(
self,
) -> Union[Metric, Sequence[Metric], Dict[str, Metric]]:
@@ -145,7 +139,7 @@ def train__iter__(self):
"""
# create worker-specific random number generator
- rng = create_rng_for_worker(self.model.current_epoch)
+ rng = create_rng_for_worker(self.model)
classes = list(self.specifications.classes)
@@ -250,9 +244,13 @@ def training_step(self, batch, batch_idx: int):
return {"loss": loss}
+ def prepare_validation(self, prepared_dict: Dict):
+ if isinstance(self.protocol, SpeakerVerificationProtocol):
+ prepared_dict["validation"] = list(self.protocol.development_trial())
+
def val__getitem__(self, idx):
if isinstance(self.protocol, SpeakerVerificationProtocol):
- trial = self._validation[idx]
+ trial = self.prepared_data["validation"][idx]
data = dict()
for idx in [1, 2]:
@@ -281,7 +279,7 @@ def val__getitem__(self, idx):
def val__len__(self):
if isinstance(self.protocol, SpeakerVerificationProtocol):
- return len(self._validation)
+ return len(self.prepared_data["validation"])
elif isinstance(self.protocol, SpeakerDiarizationProtocol):
return 0
diff --git a/pyannote/audio/tasks/segmentation/mixins.py b/pyannote/audio/tasks/segmentation/mixins.py
index 018e8db70..be30828f0 100644
--- a/pyannote/audio/tasks/segmentation/mixins.py
+++ b/pyannote/audio/tasks/segmentation/mixins.py
@@ -23,44 +23,40 @@
import itertools
import math
import random
-import warnings
-from collections import defaultdict
from typing import Dict, Sequence, Union
import matplotlib.pyplot as plt
import numpy as np
import torch
-from pyannote.database.protocol import SegmentationProtocol, SpeakerDiarizationProtocol
from pyannote.database.protocol.protocol import Scope, Subset
from pytorch_lightning.loggers import MLFlowLogger, TensorBoardLogger
from torch.utils.data._utils.collate import default_collate
-from torchaudio.backend.common import AudioMetaData
+from torchaudio import AudioMetaData
from torchmetrics import Metric
from torchmetrics.classification import BinaryAUROC, MulticlassAUROC, MultilabelAUROC
-from pyannote.audio.core.task import Problem
+from pyannote.audio.core.task import Problem, Task, get_dtype
from pyannote.audio.utils.random import create_rng_for_worker
Subsets = list(Subset.__args__)
Scopes = list(Scope.__args__)
-class SegmentationTaskMixin:
+class SegmentationTask(Task):
"""Methods common to most segmentation tasks"""
def get_file(self, file_id):
file = dict()
- file["audio"] = str(self.audios[file_id], encoding="utf-8")
+ file["audio"] = self.prepared_data["audio-path"][file_id]
- _audio_info = self.audio_infos[file_id]
- _encoding = self.audio_encodings[file_id]
+ _audio_info = self.prepared_data["audio-info"][file_id]
+ encoding = self.prepared_data["audio-encoding"][file_id]
sample_rate = _audio_info["sample_rate"]
num_frames = _audio_info["num_frames"]
num_channels = _audio_info["num_channels"]
bits_per_sample = _audio_info["bits_per_sample"]
- encoding = str(_encoding, encoding="utf-8")
file["torchaudio.info"] = AudioMetaData(
sample_rate=sample_rate,
num_frames=num_frames,
@@ -71,319 +67,6 @@ def get_file(self, file_id):
return file
- def setup(self):
- """Setup"""
-
- # duration of training chunks
- # TODO: handle variable duration case
- duration = getattr(self, "duration", 0.0)
-
- # list of possible values for each metadata key
- metadata_unique_values = defaultdict(list)
-
- metadata_unique_values["subset"] = Subsets
-
- if isinstance(self.protocol, SpeakerDiarizationProtocol):
- metadata_unique_values["scope"] = Scopes
-
- elif isinstance(self.protocol, SegmentationProtocol):
- classes = getattr(self, "classes", list())
-
- # make sure classes attribute exists (and set to None if it did not exist)
- self.classes = getattr(self, "classes", None)
- if self.classes is None:
- classes = list()
- # metadata_unique_values["classes"] = list(classes)
-
- audios = list() # list of path to audio files
- audio_infos = list()
- audio_encodings = list()
- metadata = list() # list of metadata
-
- annotated_duration = list() # total duration of annotated regions (per file)
- annotated_regions = list() # annotated regions
- annotations = list() # actual annotations
- annotated_classes = list() # list of annotated classes (per file)
- unique_labels = list()
-
- if self.has_validation:
- files_iter = itertools.chain(
- self.protocol.train(), self.protocol.development()
- )
- else:
- files_iter = self.protocol.train()
-
- for file_id, file in enumerate(files_iter):
- # gather metadata and update metadata_unique_values so that each metadatum
- # (e.g. source database or label) is represented by an integer.
- metadatum = dict()
-
- # keep track of source database and subset (train, development, or test)
- if file["database"] not in metadata_unique_values["database"]:
- metadata_unique_values["database"].append(file["database"])
- metadatum["database"] = metadata_unique_values["database"].index(
- file["database"]
- )
- metadatum["subset"] = Subsets.index(file["subset"])
-
- # keep track of speaker label scope (file, database, or global) for speaker diarization protocols
- if isinstance(self.protocol, SpeakerDiarizationProtocol):
- metadatum["scope"] = Scopes.index(file["scope"])
-
- # keep track of list of classes for regular segmentation protocols
- # Different files may be annotated using a different set of classes
- # (e.g. one database for speech/music/noise, and another one for male/female/child)
- if isinstance(self.protocol, SegmentationProtocol):
- if "classes" in file:
- local_classes = file["classes"]
- else:
- local_classes = file["annotation"].labels()
-
- # if task was not initialized with a fixed list of classes,
- # we build it as the union of all classes found in files
- if self.classes is None:
- for klass in local_classes:
- if klass not in classes:
- classes.append(klass)
- annotated_classes.append(
- [classes.index(klass) for klass in local_classes]
- )
-
- # if task was initialized with a fixed list of classes,
- # we make sure that all files use a subset of these classes
- # if they don't, we issue a warning and ignore the extra classes
- else:
- extra_classes = set(local_classes) - set(self.classes)
- if extra_classes:
- warnings.warn(
- f"Ignoring extra classes ({', '.join(extra_classes)}) found for file {file['uri']} ({file['database']}). "
- )
- annotated_classes.append(
- [
- self.classes.index(klass)
- for klass in set(local_classes) & set(self.classes)
- ]
- )
-
- remaining_metadata_keys = set(file) - set(
- [
- "uri",
- "database",
- "subset",
- "audio",
- "torchaudio.info",
- "scope",
- "classes",
- "annotation",
- "annotated",
- ]
- )
-
- # keep track of any other (integer or string) metadata provided by the protocol
- # (e.g. a "domain" key for domain-adversarial training)
- for key in remaining_metadata_keys:
- value = file[key]
-
- if isinstance(value, str):
- if value not in metadata_unique_values[key]:
- metadata_unique_values[key].append(value)
- metadatum[key] = metadata_unique_values[key].index(value)
-
- elif isinstance(value, int):
- metadatum[key] = value
-
- else:
- warnings.warn(
- f"Ignoring '{key}' metadata because of its type ({type(value)}). Only str and int are supported for now.",
- category=UserWarning,
- )
-
- metadata.append(metadatum)
-
- database_unique_labels = list()
-
- # reset list of file-scoped labels
- file_unique_labels = list()
-
- # path to audio file
- audios.append(str(file["audio"]))
-
- # audio info
- audio_info = file["torchaudio.info"]
- audio_infos.append(
- (
- audio_info.sample_rate, # sample rate
- audio_info.num_frames, # number of frames
- audio_info.num_channels, # number of channels
- audio_info.bits_per_sample, # bits per sample
- )
- )
- audio_encodings.append(audio_info.encoding) # encoding
-
- # annotated regions and duration
- _annotated_duration = 0.0
- for segment in file["annotated"]:
- # skip annotated regions that are shorter than training chunk duration
- if segment.duration < duration:
- continue
-
- # append annotated region
- annotated_region = (
- file_id,
- segment.duration,
- segment.start,
- segment.end,
- )
- annotated_regions.append(annotated_region)
-
- # increment annotated duration
- _annotated_duration += segment.duration
-
- # append annotated duration
- annotated_duration.append(_annotated_duration)
-
- # annotations
- for segment, _, label in file["annotation"].itertracks(yield_label=True):
- # "scope" is provided by speaker diarization protocols to indicate
- # whether speaker labels are local to the file ('file'), consistent across
- # all files in a database ('database'), or globally consistent ('global')
-
- if "scope" in file:
- # 0 = 'file'
- # 1 = 'database'
- # 2 = 'global'
- scope = Scopes.index(file["scope"])
-
- # update list of file-scope labels
- if label not in file_unique_labels:
- file_unique_labels.append(label)
- # and convert label to its (file-scope) index
- file_label_idx = file_unique_labels.index(label)
-
- database_label_idx = global_label_idx = -1
-
- if scope > 0: # 'database' or 'global'
- # update list of database-scope labels
- if label not in database_unique_labels:
- database_unique_labels.append(label)
-
- # and convert label to its (database-scope) index
- database_label_idx = database_unique_labels.index(label)
-
- if scope > 1: # 'global'
- # update list of global-scope labels
- if label not in unique_labels:
- unique_labels.append(label)
- # and convert label to its (global-scope) index
- global_label_idx = unique_labels.index(label)
-
- # basic segmentation protocols do not provide "scope" information
- # as classes are global by definition
-
- else:
- try:
- file_label_idx = (
- database_label_idx
- ) = global_label_idx = classes.index(label)
- except ValueError:
- # skip labels that are not in the list of classes
- continue
-
- annotations.append(
- (
- file_id, # index of file
- segment.start, # start time
- segment.end, # end time
- file_label_idx, # file-scope label index
- database_label_idx, # database-scope label index
- global_label_idx, # global-scope index
- )
- )
-
- # since not all metadata keys are present in all files, fallback to -1 when a key is missing
- metadata = [
- tuple(metadatum.get(key, -1) for key in metadata_unique_values)
- for metadatum in metadata
- ]
- dtype = [(key, "i") for key in metadata_unique_values]
- self.metadata = np.array(metadata, dtype=dtype)
-
- # NOTE: read with str(self.audios[file_id], encoding='utf-8')
- self.audios = np.array(audios, dtype=np.string_)
-
- # turn list of files metadata into a single numpy array
- # TODO: improve using https://github.com/pytorch/pytorch/issues/13246#issuecomment-617140519
-
- dtype = [
- ("sample_rate", "i"),
- ("num_frames", "i"),
- ("num_channels", "i"),
- ("bits_per_sample", "i"),
- ]
- self.audio_infos = np.array(audio_infos, dtype=dtype)
- self.audio_encodings = np.array(audio_encodings, dtype=np.string_)
-
- self.annotated_duration = np.array(annotated_duration)
-
- # turn list of annotated regions into a single numpy array
- dtype = [("file_id", "i"), ("duration", "f"), ("start", "f"), ("end", "f")]
- self.annotated_regions = np.array(annotated_regions, dtype=dtype)
-
- # convert annotated_classes (which is a list of list of classes, one list of classes per file)
- # into a single (num_files x num_classes) numpy array:
- # * True indicates that this particular class was annotated for this particular file (though it may not be active in this file)
- # * False indicates that this particular class was not even annotated (i.e. its absence does not imply that it is not active in this file)
- if isinstance(self.protocol, SegmentationProtocol) and self.classes is None:
- self.classes = classes
- self.annotated_classes = np.zeros(
- (len(annotated_classes), len(self.classes)), dtype=np.bool_
- )
- for file_id, classes in enumerate(annotated_classes):
- self.annotated_classes[file_id, classes] = True
-
- # turn list of annotations into a single numpy array
- dtype = [
- ("file_id", "i"),
- ("start", "f"),
- ("end", "f"),
- ("file_label_idx", "i"),
- ("database_label_idx", "i"),
- ("global_label_idx", "i"),
- ]
- self.annotations = np.array(annotations, dtype=dtype)
-
- self.metadata_unique_values = metadata_unique_values
-
- if not self.has_validation:
- return
-
- validation_chunks = list()
-
- # obtain indexes of files in the validation subset
- validation_file_ids = np.where(
- self.metadata["subset"] == Subsets.index("development")
- )[0]
-
- # iterate over files in the validation subset
- for file_id in validation_file_ids:
- # get annotated regions in file
- annotated_regions = self.annotated_regions[
- self.annotated_regions["file_id"] == file_id
- ]
-
- # iterate over annotated regions
- for annotated_region in annotated_regions:
- # number of chunks in annotated region
- num_chunks = round(annotated_region["duration"] // duration)
-
- # iterate over chunks
- for c in range(num_chunks):
- start_time = annotated_region["start"] + c * duration
- validation_chunks.append((file_id, start_time, duration))
-
- dtype = [("file_id", "i"), ("start", "f"), ("duration", "f")]
- self.validation_chunks = np.array(validation_chunks, dtype=dtype)
-
def default_metric(
self,
) -> Union[Metric, Sequence[Metric], Dict[str, Metric]]:
@@ -419,14 +102,20 @@ def train__iter__helper(self, rng: random.Random, **filters):
"""
# indices of training files that matches domain filters
- training = self.metadata["subset"] == Subsets.index("train")
+ training = self.prepared_data["audio-metadata"]["subset"] == Subsets.index(
+ "train"
+ )
for key, value in filters.items():
- training &= self.metadata[key] == self.metadata_unique_values[key].index(value)
+ training &= self.prepared_data["audio-metadata"][key] == self.prepared_data[
+ "metadata"
+ ][key].index(value)
file_ids = np.where(training)[0]
# turn annotated duration into a probability distribution
- annotated_duration = self.annotated_duration[file_ids]
- prob_annotated_duration = annotated_duration / np.sum(annotated_duration)
+ annotated_duration = self.prepared_data["audio-annotated"][file_ids]
+ cum_prob_annotated_duration = np.cumsum(
+ annotated_duration / np.sum(annotated_duration)
+ )
duration = self.duration
@@ -434,28 +123,38 @@ def train__iter__helper(self, rng: random.Random, **filters):
while True:
# select one file at random (with probability proportional to its annotated duration)
- file_id = np.random.choice(file_ids, p=prob_annotated_duration)
+ file_id = file_ids[cum_prob_annotated_duration.searchsorted(rng.random())]
# generate `num_chunks_per_file` chunks from this file
for _ in range(num_chunks_per_file):
# find indices of annotated regions in this file
annotated_region_indices = np.where(
- self.annotated_regions["file_id"] == file_id
+ self.prepared_data["annotations-regions"]["file_id"] == file_id
)[0]
# turn annotated regions duration into a probability distribution
- prob_annotated_regions_duration = self.annotated_regions["duration"][
- annotated_region_indices
- ] / np.sum(self.annotated_regions["duration"][annotated_region_indices])
- # selected one annotated region at random (with probability proportional to its duration)
- annotated_region_index = np.random.choice(
- annotated_region_indices, p=prob_annotated_regions_duration
+ cum_prob_annotated_regions_duration = np.cumsum(
+ self.prepared_data["annotations-regions"]["duration"][
+ annotated_region_indices
+ ]
+ / np.sum(
+ self.prepared_data["annotations-regions"]["duration"][
+ annotated_region_indices
+ ]
+ )
)
+ # selected one annotated region at random (with probability proportional to its duration)
+ annotated_region_index = annotated_region_indices[
+ cum_prob_annotated_regions_duration.searchsorted(rng.random())
+ ]
+
# select one chunk at random in this annotated region
- _, _, start, end = self.annotated_regions[annotated_region_index]
- start_time = rng.uniform(start, end - duration)
+ _, region_duration, start = self.prepared_data["annotations-regions"][
+ annotated_region_index
+ ]
+ start_time = rng.uniform(start, start + region_duration - duration)
yield self.prepare_chunk(file_id, start_time, duration)
@@ -475,7 +174,7 @@ def train__iter__(self):
"""
# create worker-specific random number generator
- rng = create_rng_for_worker(self.model.current_epoch)
+ rng = create_rng_for_worker(self.model)
balance = getattr(self, "balance", None)
if balance is None:
@@ -485,7 +184,7 @@ def train__iter__(self):
# create a subchunk generator for each combination of "balance" keys
subchunks = dict()
for product in itertools.product(
- *[self.metadata_unique_values[key] for key in balance]
+ *[self.prepared_data["metadata"][key] for key in balance]
):
# we iterate on the cartesian product of the values in metadata_unique_values
# eg: for balance=["database", "split"], with 2 databases and 2 splits:
@@ -556,12 +255,52 @@ def collate_fn(self, batch, stage="train"):
def train__len__(self):
# Number of training samples in one epoch
+ train_file_ids = np.where(
+ self.prepared_data["audio-metadata"]["subset"] == Subsets.index("train")
+ )[0]
- duration = np.sum(self.annotated_duration)
+ duration = np.sum(self.prepared_data["audio-annotated"][train_file_ids])
return max(self.batch_size, math.ceil(duration / self.duration))
+ def prepare_validation(self, prepared_data: Dict):
+ validation_chunks = list()
+
+ # obtain indexes of files in the validation subset
+ validation_file_ids = np.where(
+ prepared_data["audio-metadata"]["subset"] == Subsets.index("development")
+ )[0]
+
+ # iterate over files in the validation subset
+ for file_id in validation_file_ids:
+ # get annotated regions in file
+ annotated_regions = prepared_data["annotations-regions"][
+ prepared_data["annotations-regions"]["file_id"] == file_id
+ ]
+
+ # iterate over annotated regions
+ for annotated_region in annotated_regions:
+ # number of chunks in annotated region
+ num_chunks = round(annotated_region["duration"] // self.duration)
+
+ # iterate over chunks
+ for c in range(num_chunks):
+ start_time = annotated_region["start"] + c * self.duration
+ validation_chunks.append((file_id, start_time, self.duration))
+
+ dtype = [
+ (
+ "file_id",
+ get_dtype(max(v[0] for v in validation_chunks)),
+ ),
+ ("start", "f"),
+ ("duration", "f"),
+ ]
+
+ prepared_data["validation"] = np.array(validation_chunks, dtype=dtype)
+ validation_chunks.clear()
+
def val__getitem__(self, idx):
- validation_chunk = self.validation_chunks[idx]
+ validation_chunk = self.prepared_data["validation"][idx]
return self.prepare_chunk(
validation_chunk["file_id"],
validation_chunk["start"],
@@ -569,7 +308,7 @@ def val__getitem__(self, idx):
)
def val__len__(self):
- return len(self.validation_chunks)
+ return len(self.prepared_data["validation"])
def validation_step(self, batch, batch_idx: int):
"""Compute validation area under the ROC curve
diff --git a/pyannote/audio/tasks/segmentation/multilabel.py b/pyannote/audio/tasks/segmentation/multilabel.py
index c1d58431a..9184121c4 100644
--- a/pyannote/audio/tasks/segmentation/multilabel.py
+++ b/pyannote/audio/tasks/segmentation/multilabel.py
@@ -20,6 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+import itertools
+import textwrap
from typing import Dict, List, Optional, Sequence, Text, Tuple, Union
import numpy as np
@@ -31,11 +33,11 @@
from torch_audiomentations.core.transforms_interface import BaseWaveformTransform
from torchmetrics import Metric
-from pyannote.audio.core.task import Problem, Resolution, Specifications, Task
-from pyannote.audio.tasks.segmentation.mixins import SegmentationTaskMixin
+from pyannote.audio.core.task import Problem, Resolution, Specifications
+from pyannote.audio.tasks.segmentation.mixins import SegmentationTask
-class MultiLabelSegmentation(SegmentationTaskMixin, Task):
+class MultiLabelSegmentation(SegmentationTask):
"""Generic multi-label segmentation
Multi-label segmentation is the process of detecting temporal intervals
@@ -47,7 +49,13 @@ class MultiLabelSegmentation(SegmentationTaskMixin, Task):
Parameters
----------
protocol : Protocol
- pyannote.database protocol
+ cache : str, optional
+ As (meta-)data preparation might take a very long time for large datasets,
+ it can be cached to disk for later (and faster!) re-use.
+ When `cache` does not exist, `Task.prepare_data()` generates training
+ and validation metadata from `protocol` and save them to disk.
+ When `cache` exists, `Task.prepare_data()` is skipped and (meta)-data
+ are loaded from disk. Defaults to a temporary path.
classes : List[str], optional
List of classes. Defaults to the list of classes available in the training set.
duration : float, optional
@@ -84,15 +92,16 @@ class MultiLabelSegmentation(SegmentationTaskMixin, Task):
def __init__(
self,
protocol: Protocol,
+ cache: Optional[Union[str, None]] = None,
classes: Optional[List[str]] = None,
duration: float = 2.0,
warm_up: Union[float, Tuple[float, float]] = 0.0,
- balance: Sequence[Text] = None,
- weight: Text = None,
+ balance: Optional[Sequence[Text]] = None,
+ weight: Optional[Text] = None,
batch_size: int = 32,
- num_workers: int = None,
+ num_workers: Optional[int] = None,
pin_memory: bool = False,
- augmentation: BaseWaveformTransform = None,
+ augmentation: Optional[BaseWaveformTransform] = None,
metric: Union[Metric, Sequence[Metric], Dict[str, Metric]] = None,
):
if not isinstance(protocol, SegmentationProtocol):
@@ -109,6 +118,7 @@ def __init__(
pin_memory=pin_memory,
augmentation=augmentation,
metric=metric,
+ cache=cache,
)
self.balance = balance
@@ -119,11 +129,114 @@ def __init__(
# classes should be detected. therefore, we postpone the definition of
# specifications to setup()
- def setup(self):
- super().setup()
+ def post_prepare_data(self, prepared_data: Dict):
+ # as different files may be annotated using a different set of classes
+ # (e.g. one database for speech/music/noise, and another one for
+ # male/female/child), we keep track of this information. this is used
+ # to know whether a missing class is considered a negative example (0) or
+ # simple an unknown example (-1)
+
+ if self.classes is None and not self.has_classes:
+ msg = textwrap.dedent(
+ """
+ Could not infer list of classes. Either provide a list of classes when
+ instantiating the task, or make sure that the training protocol provides
+ a 'classes' entry. See https://github.com/pyannote/pyannote-database#segmentation
+ for more details.
+ """
+ )
+
+ if self.has_validation:
+ files_iter = itertools.chain(
+ self.protocol.train(), self.protocol.development()
+ )
+ else:
+ files_iter = self.protocol.train()
+
+ if self.classes is None:
+ classes = list() # overall list of classes
+ annotated_classes = list() # list of annotated classes (per file)
+
+ for file in files_iter:
+ file_classes = file.get("classes", None)
+
+ if not file_classes:
+ msg = textwrap.dedent(
+ f"""
+ File "{file['uri']}" (from {file['database']} database) does not
+ provide a 'classes' entry. Please make sure the corresponding
+ training protocol provides a 'classes' entry for all files. See
+ https://github.com/pyannote/pyannote-database#segmentation for more
+ details.
+ """
+ )
+ raise ValueError(msg)
+
+ for klass in file_classes:
+ if klass not in classes:
+ classes.append(klass)
+ annotated_classes.append(
+ [classes.index(klass) for klass in file_classes]
+ )
+
+ prepared_data["classes-list"] = np.array(classes, dtype=np.str_)
+ self.classes = classes
+
+ else:
+ annotated_classes = list() # list of annotated classes (per file)
+ for file in files_iter:
+ file_classes = file.get("classes", None)
+
+ if not file_classes:
+ msg = textwrap.dedent(
+ f"""
+ File "{file['uri']}" (from {file['database']} database) does not
+ provide a 'classes' entry. Please make sure the corresponding
+ training protocol provides a 'classes' entry for all files. See
+ https://github.com/pyannote/pyannote-database#segmentation for more
+ details.
+ """
+ )
+ raise ValueError(msg)
+
+ extra_classes = set(file_classes) - set(self.classes)
+ if extra_classes:
+ msg = textwrap.dedent(
+ f"""
+ File "{file['uri']}" (from {file['database']} database) provides
+ extra classes ({', '.join(extra_classes)}) that are ignored.
+ """
+ )
+ print(msg)
+
+ annotated_classes.append(
+ [
+ self.classes.index(klass)
+ for klass in set(file_classes) & set(self.classes)
+ ]
+ )
+
+ prepared_data["classes-list"] = np.array(self.classes, dtype=np.str_)
+
+ # convert annotated_classes (which is a list of list of classes, one list of classes per file)
+ # into a single (num_files x num_classes) numpy array:
+ # * True indicates that this particular class was annotated for this particular file
+ # (though it may not be active in this file)
+ # * False indicates that this particular class was not even annotated (i.e. its absence
+ # does not imply that it is not active in this file)
+ annotated_classes_array = np.zeros(
+ (len(annotated_classes), len(self.classes)), dtype=np.bool_
+ )
+ for file_id, classes in enumerate(annotated_classes):
+ annotated_classes_array[file_id, classes] = True
+ prepared_data["classes-annotated"] = annotated_classes_array
+ annotated_classes.clear()
+
+ def setup(self, stage=None):
+ super().setup(stage)
self.specifications = Specifications(
- classes=self.classes,
+ classes=self.prepared_data["classes-list"],
problem=Problem.MULTI_LABEL_CLASSIFICATION,
resolution=Resolution.FRAME,
duration=self.duration,
@@ -169,7 +282,9 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
sample = dict()
sample["X"], _ = self.model.audio.crop(file, chunk, duration=duration)
# gather all annotations of current file
- annotations = self.annotations[self.annotations["file_id"] == file_id]
+ annotations = self.prepared_data["annotations-segments"][
+ self.prepared_data["annotations-segments"]["file_id"] == file_id
+ ]
# gather all annotations with non-empty intersection with current chunk
chunk_annotations = annotations[
@@ -177,26 +292,37 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
]
# discretize chunk annotations at model output resolution
- start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start
- start_idx = np.floor(start / self.model.example_output.frames.step).astype(int)
- end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start
- end_idx = np.ceil(end / self.model.example_output.frames.step).astype(int)
+ step = self.model.receptive_field.step
+ half = 0.5 * self.model.receptive_field.duration
+
+ start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start - half
+ start_idx = np.maximum(0, np.round(start / step)).astype(int)
+
+ end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start - half
+ end_idx = np.round(end / step).astype(int)
# frame-level targets (-1 for un-annotated classes)
+ num_frames = self.model.num_frames(
+ round(duration * self.model.hparams.sample_rate)
+ )
y = -np.ones(
- (self.model.example_output.num_frames, len(self.classes)), dtype=np.int8
+ (
+ num_frames,
+ len(self.prepared_data["classes-list"]),
+ ),
+ dtype=np.int8,
)
- y[:, self.annotated_classes[file_id]] = 0
+ y[:, self.prepared_data["classes-annotated"][file_id]] = 0
for start, end, label in zip(
start_idx, end_idx, chunk_annotations["global_label_idx"]
):
- y[start:end, label] = 1
+ y[start : end + 1, label] = 1
sample["y"] = SlidingWindowFeature(
- y, self.model.example_output.frames, labels=self.classes
+ y, self.model.receptive_field, labels=self.classes
)
- metadata = self.metadata[file_id]
+ metadata = self.prepared_data["audio-metadata"][file_id]
sample["meta"] = {key: metadata[key] for key in metadata.dtype.names}
sample["meta"]["file"] = file_id
diff --git a/pyannote/audio/tasks/segmentation/overlapped_speech_detection.py b/pyannote/audio/tasks/segmentation/overlapped_speech_detection.py
index 0b7209c5c..89d299a8d 100644
--- a/pyannote/audio/tasks/segmentation/overlapped_speech_detection.py
+++ b/pyannote/audio/tasks/segmentation/overlapped_speech_detection.py
@@ -21,7 +21,7 @@
# SOFTWARE.
-from typing import Dict, Sequence, Text, Tuple, Union
+from typing import Dict, Optional, Sequence, Text, Tuple, Union
import numpy as np
from pyannote.core import Segment, SlidingWindowFeature
@@ -29,11 +29,11 @@
from torch_audiomentations.core.transforms_interface import BaseWaveformTransform
from torchmetrics import Metric
-from pyannote.audio.core.task import Problem, Resolution, Specifications, Task
-from pyannote.audio.tasks.segmentation.mixins import SegmentationTaskMixin
+from pyannote.audio.core.task import Problem, Resolution, Specifications
+from pyannote.audio.tasks.segmentation.mixins import SegmentationTask
-class OverlappedSpeechDetection(SegmentationTaskMixin, Task):
+class OverlappedSpeechDetection(SegmentationTask):
"""Overlapped speech detection
Overlapped speech detection is the task of detecting regions where at least
@@ -51,6 +51,13 @@ class OverlappedSpeechDetection(SegmentationTaskMixin, Task):
----------
protocol : Protocol
pyannote.database protocol
+ cache : str, optional
+ As (meta-)data preparation might take a very long time for large datasets,
+ it can be cached to disk for later (and faster!) re-use.
+ When `cache` does not exist, `Task.prepare_data()` generates training
+ and validation metadata from `protocol` and save them to disk.
+ When `cache` exists, `Task.prepare_data()` is skipped and (meta)-data
+ are loaded from disk. Defaults to a temporary path.
duration : float, optional
Chunks duration. Defaults to 2s.
warm_up : float or (float, float), optional
@@ -66,11 +73,12 @@ class OverlappedSpeechDetection(SegmentationTaskMixin, Task):
overlap: dict, optional
Controls how artificial chunks with overlapping speech are generated:
- "probability" key is the probability of artificial overlapping chunks. Setting
- "probability" to 0.6 means that, on average, 40% of training chunks are "real"
- chunks, while 60% are artifical chunks made out of the (weighted) sum of two
- chunks. Defaults to 0.5.
+ "probability" to 0.6 means that, on average, 40% of training chunks are "real"
+ chunks, while 60% are artifical chunks made out of the (weighted) sum of two
+ chunks. Defaults to 0.5.
- "snr_min" and "snr_max" keys control the minimum and maximum signal-to-noise
- ratio between summed chunks, in dB. Default to 0.0 and 10.
+ ratio between summed chunks, in dB. Default to 0.0 and 10.
+
weight: str, optional
When provided, use this key to as frame-wise weight in loss function.
batch_size : int, optional
@@ -98,13 +106,14 @@ def __init__(
duration: float = 2.0,
warm_up: Union[float, Tuple[float, float]] = 0.0,
overlap: dict = OVERLAP_DEFAULTS,
- balance: Sequence[Text] = None,
- weight: Text = None,
+ balance: Optional[Sequence[Text]] = None,
+ weight: Optional[Text] = None,
batch_size: int = 32,
- num_workers: int = None,
+ num_workers: Optional[int] = None,
pin_memory: bool = False,
- augmentation: BaseWaveformTransform = None,
+ augmentation: Optional[BaseWaveformTransform] = None,
metric: Union[Metric, Sequence[Metric], Dict[str, Metric]] = None,
+ cache: Optional[Union[str, None]] = None,
):
super().__init__(
protocol,
@@ -115,6 +124,7 @@ def __init__(
pin_memory=pin_memory,
augmentation=augmentation,
metric=metric,
+ cache=cache,
)
self.specifications = Specifications(
@@ -163,7 +173,9 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
sample["X"], _ = self.model.audio.crop(file, chunk, duration=duration)
# gather all annotations of current file
- annotations = self.annotations[self.annotations["file_id"] == file_id]
+ annotations = self.prepared_data["annotations-segments"][
+ self.prepared_data["annotations-segments"]["file_id"] == file_id
+ ]
# gather all annotations with non-empty intersection with current chunk
chunk_annotations = annotations[
@@ -171,22 +183,29 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
]
# discretize chunk annotations at model output resolution
- start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start
- start_idx = np.floor(start / self.model.example_output.frames.step).astype(int)
- end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start
- end_idx = np.ceil(end / self.model.example_output.frames.step).astype(int)
+ step = self.model.receptive_field.step
+ half = 0.5 * self.model.receptive_field.duration
+
+ start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start - half
+ start_idx = np.maximum(0, np.round(start / step)).astype(int)
+
+ end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start - half
+ end_idx = np.round(end / step).astype(int)
# frame-level targets
- y = np.zeros((self.model.example_output.num_frames, 1), dtype=np.uint8)
+ num_frames = self.model.num_frames(
+ round(duration * self.model.hparams.sample_rate)
+ )
+ y = np.zeros((num_frames, 1), dtype=np.uint8)
for start, end in zip(start_idx, end_idx):
- y[start:end, 0] += 1
+ y[start : end + 1, 0] += 1
y = 1 * (y > 1)
sample["y"] = SlidingWindowFeature(
- y, self.model.example_output.frames, labels=["speech"]
+ y, self.model.receptive_field, labels=["speech"]
)
- metadata = self.metadata[file_id]
+ metadata = self.prepared_data["audio-metadata"][file_id]
sample["meta"] = {key: metadata[key] for key in metadata.dtype.names}
sample["meta"]["file"] = file_id
diff --git a/pyannote/audio/tasks/segmentation/speaker_diarization.py b/pyannote/audio/tasks/segmentation/speaker_diarization.py
index 1094672ed..8a091b1f7 100644
--- a/pyannote/audio/tasks/segmentation/speaker_diarization.py
+++ b/pyannote/audio/tasks/segmentation/speaker_diarization.py
@@ -23,7 +23,7 @@
import math
import warnings
from collections import Counter
-from typing import Dict, Literal, Sequence, Text, Tuple, Union
+from typing import Dict, Literal, Optional, Sequence, Text, Tuple, Union
import numpy as np
import torch
@@ -37,8 +37,8 @@
from torch_audiomentations.core.transforms_interface import BaseWaveformTransform
from torchmetrics import Metric
-from pyannote.audio.core.task import Problem, Resolution, Specifications, Task
-from pyannote.audio.tasks.segmentation.mixins import SegmentationTaskMixin
+from pyannote.audio.core.task import Problem, Resolution, Specifications
+from pyannote.audio.tasks.segmentation.mixins import SegmentationTask
from pyannote.audio.torchmetrics import (
DiarizationErrorRate,
FalseAlarmRate,
@@ -58,13 +58,20 @@
Scopes = list(Scope.__args__)
-class SpeakerDiarization(SegmentationTaskMixin, Task):
+class SpeakerDiarization(SegmentationTask):
"""Speaker diarization
Parameters
----------
protocol : SpeakerDiarizationProtocol
pyannote.database protocol
+ cache : str, optional
+ As (meta-)data preparation might take a very long time for large datasets,
+ it can be cached to disk for later (and faster!) re-use.
+ When `cache` does not exist, `Task.prepare_data()` generates training
+ and validation metadata from `protocol` and save them to disk.
+ When `cache` exists, `Task.prepare_data()` is skipped and (meta)-data
+ are loaded from disk. Defaults to a temporary path.
duration : float, optional
Chunks duration. Defaults to 2s.
max_speakers_per_chunk : int, optional
@@ -127,20 +134,23 @@ class SpeakerDiarization(SegmentationTaskMixin, Task):
def __init__(
self,
protocol: SpeakerDiarizationProtocol,
+ cache: Optional[Union[str, None]] = None,
duration: float = 2.0,
- max_speakers_per_chunk: int = None,
- max_speakers_per_frame: int = None,
+ max_speakers_per_chunk: Optional[int] = None,
+ max_speakers_per_frame: Optional[int] = None,
weigh_by_cardinality: bool = False,
warm_up: Union[float, Tuple[float, float]] = 0.0,
- balance: Sequence[Text] = None,
- weight: Text = None,
+ balance: Optional[Sequence[Text]] = None,
+ weight: Optional[Text] = None,
batch_size: int = 32,
- num_workers: int = None,
+ num_workers: Optional[int] = None,
pin_memory: bool = False,
- augmentation: BaseWaveformTransform = None,
+ augmentation: Optional[BaseWaveformTransform] = None,
vad_loss: Literal["bce", "mse"] = None,
metric: Union[Metric, Sequence[Metric], Dict[str, Metric]] = None,
- max_num_speakers: int = None, # deprecated in favor of `max_speakers_per_chunk``
+ max_num_speakers: Optional[
+ int
+ ] = None, # deprecated in favor of `max_speakers_per_chunk``
loss: Literal["bce", "mse"] = None, # deprecated
):
super().__init__(
@@ -152,6 +162,7 @@ def __init__(
pin_memory=pin_memory,
augmentation=augmentation,
metric=metric,
+ cache=cache,
)
if not isinstance(protocol, SpeakerDiarizationProtocol):
@@ -186,28 +197,34 @@ def __init__(
self.weight = weight
self.vad_loss = vad_loss
- def setup(self):
- super().setup()
+ def setup(self, stage=None):
+ super().setup(stage)
# estimate maximum number of speakers per chunk when not provided
if self.max_speakers_per_chunk is None:
- training = self.metadata["subset"] == Subsets.index("train")
+ training = self.prepared_data["audio-metadata"]["subset"] == Subsets.index(
+ "train"
+ )
num_unique_speakers = []
progress_description = f"Estimating maximum number of speakers per {self.duration:g}s chunk in the training set"
for file_id in track(
np.where(training)[0], description=progress_description
):
- annotations = self.annotations[
- np.where(self.annotations["file_id"] == file_id)[0]
+ annotations = self.prepared_data["annotations-segments"][
+ np.where(
+ self.prepared_data["annotations-segments"]["file_id"] == file_id
+ )[0]
]
- annotated_regions = self.annotated_regions[
- np.where(self.annotated_regions["file_id"] == file_id)[0]
+ annotated_regions = self.prepared_data["annotations-regions"][
+ np.where(
+ self.prepared_data["annotations-regions"]["file_id"] == file_id
+ )[0]
]
for region in annotated_regions:
# find annotations within current region
region_start = region["start"]
- region_end = region["end"]
+ region_end = region["start"] + region["duration"]
region_annotations = annotations[
np.where(
(annotations["start"] >= region_start)
@@ -318,7 +335,7 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
file = self.get_file(file_id)
# get label scope
- label_scope = Scopes[self.metadata[file_id]["scope"]]
+ label_scope = Scopes[self.prepared_data["audio-metadata"][file_id]["scope"]]
label_scope_key = f"{label_scope}_label_idx"
#
@@ -328,7 +345,9 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
sample["X"], _ = self.model.audio.crop(file, chunk, duration=duration)
# gather all annotations of current file
- annotations = self.annotations[self.annotations["file_id"] == file_id]
+ annotations = self.prepared_data["annotations-segments"][
+ self.prepared_data["annotations-segments"]["file_id"] == file_id
+ ]
# gather all annotations with non-empty intersection with current chunk
chunk_annotations = annotations[
@@ -336,10 +355,14 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
]
# discretize chunk annotations at model output resolution
- start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start
- start_idx = np.floor(start / self.model.example_output.frames.step).astype(int)
- end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start
- end_idx = np.ceil(end / self.model.example_output.frames.step).astype(int)
+ step = self.model.receptive_field.step
+ half = 0.5 * self.model.receptive_field.duration
+
+ start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start - half
+ start_idx = np.maximum(0, np.round(start / step)).astype(int)
+
+ end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start - half
+ end_idx = np.round(end / step).astype(int)
# get list and number of labels for current scope
labels = list(np.unique(chunk_annotations[label_scope_key]))
@@ -349,7 +372,10 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
pass
# initial frame-level targets
- y = np.zeros((self.model.example_output.num_frames, num_labels), dtype=np.uint8)
+ num_frames = self.model.num_frames(
+ round(duration * self.model.hparams.sample_rate)
+ )
+ y = np.zeros((num_frames, num_labels), dtype=np.uint8)
# map labels to indices
mapping = {label: idx for idx, label in enumerate(labels)}
@@ -358,13 +384,11 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
start_idx, end_idx, chunk_annotations[label_scope_key]
):
mapped_label = mapping[label]
- y[start:end, mapped_label] = 1
+ y[start : end + 1, mapped_label] = 1
- sample["y"] = SlidingWindowFeature(
- y, self.model.example_output.frames, labels=labels
- )
+ sample["y"] = SlidingWindowFeature(y, self.model.receptive_field, labels=labels)
- metadata = self.metadata[file_id]
+ metadata = self.prepared_data["audio-metadata"][file_id]
sample["meta"] = {key: metadata[key] for key in metadata.dtype.names}
sample["meta"]["file"] = file_id
@@ -420,7 +444,7 @@ def segmentation_loss(
self,
permutated_prediction: torch.Tensor,
target: torch.Tensor,
- weight: torch.Tensor = None,
+ weight: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Permutation-invariant segmentation loss
@@ -463,7 +487,7 @@ def voice_activity_detection_loss(
self,
permutated_prediction: torch.Tensor,
target: torch.Tensor,
- weight: torch.Tensor = None,
+ weight: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Voice activity detection loss
@@ -861,7 +885,7 @@ def main(protocol: str, subset: str = "test", model: str = "pyannote/segmentatio
main_task = progress.add_task(protocol.name, total=len(files))
file_task = progress.add_task("Processing", total=1.0)
- def progress_hook(completed: int = None, total: int = None):
+ def progress_hook(completed: Optional[int] = None, total: Optional[int] = None):
progress.update(file_task, completed=completed / total)
inference = Inference(model, device=device)
diff --git a/pyannote/audio/tasks/segmentation/voice_activity_detection.py b/pyannote/audio/tasks/segmentation/voice_activity_detection.py
index fd9eb8e75..e52613aeb 100644
--- a/pyannote/audio/tasks/segmentation/voice_activity_detection.py
+++ b/pyannote/audio/tasks/segmentation/voice_activity_detection.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from typing import Dict, Sequence, Text, Tuple, Union
+from typing import Dict, Optional, Sequence, Text, Tuple, Union
import numpy as np
from pyannote.core import Segment, SlidingWindowFeature
@@ -28,11 +28,11 @@
from torch_audiomentations.core.transforms_interface import BaseWaveformTransform
from torchmetrics import Metric
-from pyannote.audio.core.task import Problem, Resolution, Specifications, Task
-from pyannote.audio.tasks.segmentation.mixins import SegmentationTaskMixin
+from pyannote.audio.core.task import Problem, Resolution, Specifications
+from pyannote.audio.tasks.segmentation.mixins import SegmentationTask
-class VoiceActivityDetection(SegmentationTaskMixin, Task):
+class VoiceActivityDetection(SegmentationTask):
"""Voice activity detection
Voice activity detection (or VAD) is the task of detecting speech regions
@@ -45,6 +45,13 @@ class VoiceActivityDetection(SegmentationTaskMixin, Task):
----------
protocol : Protocol
pyannote.database protocol
+ cache : str, optional
+ As (meta-)data preparation might take a very long time for large datasets,
+ it can be cached to disk for later (and faster!) re-use.
+ When `cache` does not exist, `Task.prepare_data()` generates training
+ and validation metadata from `protocol` and save them to disk.
+ When `cache` exists, `Task.prepare_data()` is skipped and (meta)-data
+ are loaded from disk. Defaults to a temporary path.
duration : float, optional
Chunks duration. Defaults to 2s.
warm_up : float or (float, float), optional
@@ -79,14 +86,15 @@ class VoiceActivityDetection(SegmentationTaskMixin, Task):
def __init__(
self,
protocol: Protocol,
+ cache: Optional[Union[str, None]] = None,
duration: float = 2.0,
warm_up: Union[float, Tuple[float, float]] = 0.0,
- balance: Sequence[Text] = None,
- weight: Text = None,
+ balance: Optional[Sequence[Text]] = None,
+ weight: Optional[Text] = None,
batch_size: int = 32,
- num_workers: int = None,
+ num_workers: Optional[int] = None,
pin_memory: bool = False,
- augmentation: BaseWaveformTransform = None,
+ augmentation: Optional[BaseWaveformTransform] = None,
metric: Union[Metric, Sequence[Metric], Dict[str, Metric]] = None,
):
super().__init__(
@@ -98,6 +106,7 @@ def __init__(
pin_memory=pin_memory,
augmentation=augmentation,
metric=metric,
+ cache=cache,
)
self.balance = balance
@@ -145,7 +154,9 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
sample["X"], _ = self.model.audio.crop(file, chunk, duration=duration)
# gather all annotations of current file
- annotations = self.annotations[self.annotations["file_id"] == file_id]
+ annotations = self.prepared_data["annotations-segments"][
+ self.prepared_data["annotations-segments"]["file_id"] == file_id
+ ]
# gather all annotations with non-empty intersection with current chunk
chunk_annotations = annotations[
@@ -153,21 +164,28 @@ def prepare_chunk(self, file_id: int, start_time: float, duration: float):
]
# discretize chunk annotations at model output resolution
- start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start
- start_idx = np.floor(start / self.model.example_output.frames.step).astype(int)
- end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start
- end_idx = np.ceil(end / self.model.example_output.frames.step).astype(int)
+ step = self.model.receptive_field.step
+ half = 0.5 * self.model.receptive_field.duration
+
+ start = np.maximum(chunk_annotations["start"], chunk.start) - chunk.start - half
+ start_idx = np.maximum(0, np.round(start / step)).astype(int)
+
+ end = np.minimum(chunk_annotations["end"], chunk.end) - chunk.start - half
+ end_idx = np.round(end / step).astype(int)
# frame-level targets
- y = np.zeros((self.model.example_output.num_frames, 1), dtype=np.uint8)
+ num_frames = self.model.num_frames(
+ round(duration * self.model.hparams.sample_rate)
+ )
+ y = np.zeros((num_frames, 1), dtype=np.uint8)
for start, end in zip(start_idx, end_idx):
- y[start:end, 0] = 1
+ y[start : end + 1, 0] = 1
sample["y"] = SlidingWindowFeature(
- y, self.model.example_output.frames, labels=["speech"]
+ y, self.model.receptive_field, labels=["speech"]
)
- metadata = self.metadata[file_id]
+ metadata = self.prepared_data["audio-metadata"][file_id]
sample["meta"] = {key: metadata[key] for key in metadata.dtype.names}
sample["meta"]["file"] = file_id
diff --git a/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py b/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py
index 9502a527e..c401b70dd 100644
--- a/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py
+++ b/pyannote/audio/torchmetrics/functional/audio/diarization_error_rate.py
@@ -25,6 +25,7 @@
from typing import Optional, Tuple, Union
import torch
+import torch.nn.functional as F
from pyannote.audio.utils.permutation import permutate
@@ -33,6 +34,7 @@ def _der_update(
preds: torch.Tensor,
target: torch.Tensor,
threshold: Union[torch.Tensor, float] = 0.5,
+ reduce: str = "batch",
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
"""Compute components of diarization error rate
@@ -44,16 +46,41 @@ def _der_update(
(batch_size, num_speakers, num_frames)-shaped (0 or 1) targets.
threshold : float or torch.Tensor, optional
Threshold(s) used to binarize predictions. Defaults to 0.5.
+ reduce : {'batch', 'chunk', 'frame'}, optional
+ Reduction method. Defaults to 'batch'.
Returns
-------
- false_alarm : (num_thresholds, )-shaped torch.Tensor
- missed_detection : (num_thresholds, )-shaped torch.Tensor
- speaker_confusion : (num_thresholds, )-shaped torch.Tensor
- speech_total : torch.Tensor
- Diarization error rate components accumulated over the whole batch.
+ false_alarm : torch.Tensor
+ missed_detection : torch.Tensor
+ speaker_confusion : torch.Tensor
+ If `reduce` is 'batch', returns (num_thresholds, )-shaped tensors.
+ If `reduce` is 'chunk', returns (batch_size, num_thresholds)-shaped tensors.
+ If `reduce` is 'frame', returns (batch_size, num_frames, num_thresholds)-shaped tensors.
+ In case `threshold` is a float, the last dimension is removed from the output tensors.
+ speech_total : (...,)-shaped torch.Tensor torch.Tensor
+ If `reduce` is 'batch', returns a scalar.
+ If `reduce` is 'chunk', returns (batch_size,)-shaped tensor.
+ If `reduce` is 'frame', returns (batch_size, num_frames)-shaped tensor.
"""
+ prd_batch_size, prd_num_speakers, prd_num_frames = preds.shape
+ tgt_batch_size, tgt_num_speakers, tgt_num_frames = target.shape
+
+ if prd_batch_size != tgt_batch_size:
+ raise ValueError(f"Batch size mismatch: {prd_batch_size} != {tgt_batch_size}.")
+
+ if prd_num_frames != tgt_num_frames:
+ raise ValueError(
+ f"Number of frames mismatch: {prd_num_frames} != {tgt_num_frames}."
+ )
+
+ # pad number of speakers if necessary
+ if prd_num_speakers > tgt_num_speakers:
+ target = F.pad(target, (0, 0, 0, prd_num_speakers - tgt_num_speakers))
+ elif prd_num_speakers < tgt_num_speakers:
+ preds = F.pad(preds, (0, 0, 0, tgt_num_speakers - prd_num_speakers))
+
# make threshold a (num_thresholds,) tensor
scalar_threshold = isinstance(threshold, Number)
if scalar_threshold:
@@ -70,6 +97,9 @@ def _der_update(
hypothesis = (permutated_preds.unsqueeze(-1) > threshold).float()
# (batch_size, num_speakers, num_frames, num_thresholds)
+ speech_total = 1.0 * torch.sum(target, 1)
+ # (batch_size, num_frames)
+
target = target.unsqueeze(-1)
# (batch_size, num_speakers, num_frames, 1)
@@ -87,17 +117,47 @@ def _der_update(
speaker_confusion = torch.sum((hypothesis != target) * hypothesis, 1) - false_alarm
# (batch_size, num_frames, num_thresholds)
- false_alarm = torch.sum(torch.sum(false_alarm, 1), 0)
- missed_detection = torch.sum(torch.sum(missed_detection, 1), 0)
- speaker_confusion = torch.sum(torch.sum(speaker_confusion, 1), 0)
+ if reduce == "frame":
+ if scalar_threshold:
+ return (
+ false_alarm[:, :, 0],
+ missed_detection[:, :, 0],
+ speaker_confusion[:, :, 0],
+ speech_total,
+ )
+ return false_alarm, missed_detection, speaker_confusion, torch.sum(target, 1)
+
+ speech_total = torch.sum(speech_total, 1)
+ # (batch_size, )
+ false_alarm = torch.sum(false_alarm, 1)
+ missed_detection = torch.sum(missed_detection, 1)
+ speaker_confusion = torch.sum(speaker_confusion, 1)
+ # (batch_size, num_thresholds)
+
+ if reduce == "chunk":
+ if scalar_threshold:
+ return (
+ false_alarm[:, 0],
+ missed_detection[:, 0],
+ speaker_confusion[:, 0],
+ speech_total,
+ )
+ return false_alarm, missed_detection, speaker_confusion, speech_total
+
+ speech_total = torch.sum(speech_total, 0)
+ # scalar
+ false_alarm = torch.sum(false_alarm, 0)
+ missed_detection = torch.sum(missed_detection, 0)
+ speaker_confusion = torch.sum(speaker_confusion, 0)
# (num_thresholds, )
- speech_total = 1.0 * torch.sum(target)
-
if scalar_threshold:
- false_alarm = false_alarm[0]
- missed_detection = missed_detection[0]
- speaker_confusion = speaker_confusion[0]
+ return (
+ false_alarm[0],
+ missed_detection[0],
+ speaker_confusion[0],
+ speech_total,
+ )
return false_alarm, missed_detection, speaker_confusion, speech_total
@@ -131,6 +191,8 @@ def diarization_error_rate(
preds: torch.Tensor,
target: torch.Tensor,
threshold: Union[torch.Tensor, float] = 0.5,
+ reduce: str = "batch",
+ return_components: bool = False,
) -> torch.Tensor:
"""Compute diarization error rate
@@ -142,16 +204,32 @@ def diarization_error_rate(
(batch_size, num_speakers, num_frames)-shaped (0 or 1) targets.
threshold : float or torch.Tensor, optional
Threshold(s) used to binarize predictions. Defaults to 0.5.
+ reduce : {'batch', 'chunk', 'frame'}, optional
+ Reduction method. Defaults to 'batch'.
+ return_components : bool, optional
+ Return diarization error rate components as an additional tuple.
+ Defaults to False.
+
Returns
-------
- der : (num_thresholds, )-shaped torch.Tensor
- Aggregated diarization error rate
+ der : torch.Tensor
+ If `reduce` is 'batch', returns (num_thresholds, )-shaped tensors.
+ If `reduce` is 'chunk', returns (batch_size, num_thresholds)-shaped tensors.
+ If `reduce` is 'frame', returns (batch_size, num_frames, num_thresholds)-shaped tensors.
+ In case `threshold` is a float, the last dimension is removed from the output tensors.
+ components : (false_alarm, missed_detection, speaker_confusion, speech_total) tuple, optional
+ Same shape as `der`. Only returned when `return_components` is True.
+
"""
false_alarm, missed_detection, speaker_confusion, speech_total = _der_update(
- preds, target, threshold=threshold
+ preds, target, threshold=threshold, reduce=reduce
)
- return _der_compute(false_alarm, missed_detection, speaker_confusion, speech_total)
+
+ der = _der_compute(false_alarm, missed_detection, speaker_confusion, speech_total)
+ if return_components:
+ return der, (false_alarm, missed_detection, speaker_confusion, speech_total)
+ return der
def optimal_diarization_error_rate(
diff --git a/pyannote/audio/utils/loss.py b/pyannote/audio/utils/loss.py
index 2c55b26f3..55121a678 100644
--- a/pyannote/audio/utils/loss.py
+++ b/pyannote/audio/utils/loss.py
@@ -23,11 +23,13 @@
"""Frame-weighted versions of common loss functions"""
+from typing import Optional
+
import torch
import torch.nn.functional as F
-def interpolate(target: torch.Tensor, weight: torch.Tensor = None):
+def interpolate(target: torch.Tensor, weight: Optional[torch.Tensor] = None):
"""Interpolate weight to match target frame resolution
Parameters
@@ -55,7 +57,9 @@ def interpolate(target: torch.Tensor, weight: torch.Tensor = None):
def binary_cross_entropy(
- prediction: torch.Tensor, target: torch.Tensor, weight: torch.Tensor = None
+ prediction: torch.Tensor,
+ target: torch.Tensor,
+ weight: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Frame-weighted binary cross entropy
@@ -91,7 +95,9 @@ def binary_cross_entropy(
def mse_loss(
- prediction: torch.Tensor, target: torch.Tensor, weight: torch.Tensor = None
+ prediction: torch.Tensor,
+ target: torch.Tensor,
+ weight: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Frame-weighted mean-squared error loss
@@ -131,8 +137,8 @@ def mse_loss(
def nll_loss(
prediction: torch.Tensor,
target: torch.Tensor,
- class_weight: torch.Tensor = None,
- weight: torch.Tensor = None,
+ class_weight: Optional[torch.Tensor] = None,
+ weight: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Frame-weighted negative log-likelihood loss
diff --git a/pyannote/audio/utils/params.py b/pyannote/audio/utils/params.py
index 685e01653..f4ed42bcc 100644
--- a/pyannote/audio/utils/params.py
+++ b/pyannote/audio/utils/params.py
@@ -1,8 +1,10 @@
# TODO - make it depth-recursive
# TODO - switch to Omegaconf maybe?
+from typing import Optional
-def merge_dict(defaults: dict, custom: dict = None):
+
+def merge_dict(defaults: dict, custom: Optional[dict] = None):
params = dict(defaults)
if custom is not None:
params.update(custom)
diff --git a/pyannote/audio/utils/powerset.py b/pyannote/audio/utils/powerset.py
index b75221e48..23f921569 100644
--- a/pyannote/audio/utils/powerset.py
+++ b/pyannote/audio/utils/powerset.py
@@ -25,7 +25,8 @@
# Alexis PLAQUET
from functools import cached_property
-from itertools import combinations
+from itertools import combinations, permutations
+from typing import Dict, Tuple
import scipy.special
import torch
@@ -65,6 +66,27 @@ def num_powerset_classes(self) -> int:
)
def build_mapping(self) -> torch.Tensor:
+ """Compute powerset to regular mapping
+
+ Returns
+ -------
+ mapping : (num_powerset_classes, num_classes) torch.Tensor
+ mapping[i, j] == 1 if jth regular class is a member of ith powerset class
+ mapping[i, j] == 0 otherwise
+
+ Example
+ -------
+ With num_classes == 3 and max_set_size == 2, returns
+
+ [0, 0, 0] # none
+ [1, 0, 0] # class #1
+ [0, 1, 0] # class #2
+ [0, 0, 1] # class #3
+ [1, 1, 0] # classes #1 and #2
+ [1, 0, 1] # classes #1 and #3
+ [0, 1, 1] # classes #2 and #3
+
+ """
mapping = torch.zeros(self.num_powerset_classes, self.num_classes)
powerset_k = 0
for set_size in range(0, self.max_set_size + 1):
@@ -76,13 +98,7 @@ def build_mapping(self) -> torch.Tensor:
def build_cardinality(self) -> torch.Tensor:
"""Compute size of each powerset class"""
- cardinality = torch.zeros(self.num_powerset_classes)
- powerset_k = 0
- for set_size in range(0, self.max_set_size + 1):
- for _ in combinations(range(self.num_classes), set_size):
- cardinality[powerset_k] = set_size
- powerset_k += 1
- return cardinality
+ return torch.sum(self.mapping, dim=1)
def to_multilabel(self, powerset: torch.Tensor, soft: bool = False) -> torch.Tensor:
"""Convert predictions from powerset to multi-label
@@ -93,7 +109,7 @@ def to_multilabel(self, powerset: torch.Tensor, soft: bool = False) -> torch.Ten
Soft predictions in "powerset" space.
soft : bool, optional
Return soft multi-label predictions. Defaults to False (i.e. hard predictions)
- Assumes that `powerset` are "logits" (not "probabilities").
+ Assumes that `powerset` are "log probabilities".
Returns
-------
@@ -138,3 +154,76 @@ def to_powerset(self, multilabel: torch.Tensor) -> torch.Tensor:
torch.argmax(torch.matmul(multilabel, self.mapping.T), dim=-1),
num_classes=self.num_powerset_classes,
)
+
+ def _permutation_powerset(
+ self, multilabel_permutation: Tuple[int, ...]
+ ) -> Tuple[int, ...]:
+ """Helper function for `permutation_mapping` property
+
+ Takes a (num_classes,)-shaped permutation in multilabel space and returns
+ the corresponding (num_powerset_classes,)-shaped permutation in powerset space.
+ This does not cache anything and only works on one single permutation at a time.
+
+ Parameters
+ ----------
+ multilabel_permutation : tuple of int
+ Permutation in multilabel space.
+
+ Returns
+ -------
+ powerset_permutation : tuple of int
+ Permutation in powerset space.
+
+ Example
+ -------
+ >>> powerset = Powerset(3, 2)
+ >>> powerset._permutation_powerset((1, 0, 2))
+ # (0, 2, 1, 3, 4, 6, 5)
+
+ """
+
+ permutated_mapping: torch.Tensor = self.mapping[:, multilabel_permutation]
+
+ arange = torch.arange(
+ self.num_classes, device=self.mapping.device, dtype=torch.int
+ )
+ powers_of_two = (2**arange).tile((self.num_powerset_classes, 1))
+
+ # compute the encoding of the powerset classes in this 2**N space, before and after
+ # permutation of the columns (mapping cols=labels, mapping rows=powerset classes)
+ before = torch.sum(self.mapping * powers_of_two, dim=-1)
+ after = torch.sum(permutated_mapping * powers_of_two, dim=-1)
+
+ # find before-to-after permutation
+ powerset_permutation = (before[None] == after[:, None]).int().argmax(dim=0)
+
+ # return as tuple of indices
+ return tuple(powerset_permutation.tolist())
+
+ @cached_property
+ def permutation_mapping(self) -> Dict[Tuple[int, ...], Tuple[int, ...]]:
+ """Mapping between multilabel and powerset permutations
+
+ Example
+ -------
+ With num_classes == 3 and max_set_size == 2, returns
+
+ {
+ (0, 1, 2): (0, 1, 2, 3, 4, 5, 6),
+ (0, 2, 1): (0, 1, 3, 2, 5, 4, 6),
+ (1, 0, 2): (0, 2, 1, 3, 4, 6, 5),
+ (1, 2, 0): (0, 2, 3, 1, 6, 4, 5),
+ (2, 0, 1): (0, 3, 1, 2, 5, 6, 4),
+ (2, 1, 0): (0, 3, 2, 1, 6, 5, 4)
+ }
+ """
+ permutation_mapping = {}
+
+ for multilabel_permutation in permutations(
+ range(self.num_classes), self.num_classes
+ ):
+ permutation_mapping[
+ tuple(multilabel_permutation)
+ ] = self._permutation_powerset(multilabel_permutation)
+
+ return permutation_mapping
diff --git a/pyannote/audio/utils/preprocessors.py b/pyannote/audio/utils/preprocessors.py
index ce4685d1f..b26553bf9 100644
--- a/pyannote/audio/utils/preprocessors.py
+++ b/pyannote/audio/utils/preprocessors.py
@@ -27,12 +27,13 @@
# Hervé BREDIN - http://herve.niderb.fr
from functools import reduce
-from itertools import chain
from typing import Dict, List, Optional, Set
from pyannote.core import Annotation, Segment
from pyannote.database import ProtocolFile
+from pyannote.audio.core.io import Audio, get_torchaudio_info
+
class LowerTemporalResolution:
"""Artificially degrade temporal resolution of reference annotation
@@ -50,7 +51,6 @@ def __init__(self, resolution: float = 0.1):
self.resolution = resolution
def __call__(self, current_file: ProtocolFile) -> Annotation:
-
annotation = current_file["annotation"]
new_annotation = annotation.empty()
@@ -128,3 +128,17 @@ def __call__(self, current_file: ProtocolFile) -> Annotation:
derived[seg] = intersect_label
return derived
+
+
+class Waveform:
+ def __init__(self):
+ self._audio = Audio()
+
+ def __call__(self, file: ProtocolFile):
+ waveform, _ = self._audio(file)
+ return waveform
+
+
+class SampleRate:
+ def __call__(self, file: ProtocolFile):
+ return get_torchaudio_info(file).sample_rate
diff --git a/pyannote/audio/utils/preview.py b/pyannote/audio/utils/preview.py
index fcdf4d124..1a5ace08c 100644
--- a/pyannote/audio/utils/preview.py
+++ b/pyannote/audio/utils/preview.py
@@ -47,7 +47,7 @@
MOVIEPY_INSTALLED = False
-from typing import Mapping
+from typing import Mapping, Optional
import torch
from pyannote.core import (
@@ -64,7 +64,7 @@
from pyannote.audio.utils.signal import Binarize
-def listen(audio_file: AudioFile, segment: Segment = None) -> None:
+def listen(audio_file: AudioFile, segment: Optional[Segment] = None) -> None:
"""listen to audio
Allows playing of audio files. It will play the whole thing unless
@@ -91,7 +91,7 @@ def listen(audio_file: AudioFile, segment: Segment = None) -> None:
def preview(
audio_file: AudioFile,
- segment: Segment = None,
+ segment: Optional[Segment] = None,
zoom: float = 10.0,
video_fps: int = 5,
video_ext: str = "webm",
diff --git a/pyannote/audio/utils/random.py b/pyannote/audio/utils/random.py
index 97d50c362..0006ad612 100644
--- a/pyannote/audio/utils/random.py
+++ b/pyannote/audio/utils/random.py
@@ -22,12 +22,13 @@
import os
+import zlib
from random import Random
import torch
-def create_rng_for_worker(epoch: int) -> Random:
+def create_rng_for_worker(model) -> Random:
"""Create worker-specific random number generator
This makes sure that
@@ -43,19 +44,23 @@ def create_rng_for_worker(epoch: int) -> Random:
# create random number generator
rng = Random()
- # create seed as a combination of PL_GLOBAL_SEED (set by pl.seed_everything())
- # and other PL multi-processing variables
- global_seed = int(os.environ.get("PL_GLOBAL_SEED", "0"))
- local_rank = int(os.environ.get("LOCAL_RANK", "0"))
- node_rank = int(os.environ.get("NODE_RANK", "0"))
-
+ global_seed = os.environ.get("PL_GLOBAL_SEED", "unset")
worker_info = torch.utils.data.get_worker_info()
if worker_info is None:
- worker_id = 0
+ worker_id = None
else:
worker_id = worker_info.id
- rng.seed(hash((global_seed, worker_id, local_rank, node_rank, epoch)))
+ seed_tuple = (
+ global_seed,
+ worker_id,
+ model.local_rank,
+ model.global_rank,
+ model.current_epoch,
+ )
+ # use adler32 because python's `hash` is not deterministic.
+ seed = zlib.adler32(str(seed_tuple).encode())
+ rng.seed(seed)
return rng
diff --git a/pyannote/audio/utils/receptive_field.py b/pyannote/audio/utils/receptive_field.py
new file mode 100644
index 000000000..420a62de0
--- /dev/null
+++ b/pyannote/audio/utils/receptive_field.py
@@ -0,0 +1,165 @@
+# MIT License
+#
+# Copyright (c) 2023 CNRS
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from typing import List
+
+
+def conv1d_num_frames(
+ num_samples, kernel_size=5, stride=1, padding=0, dilation=1
+) -> int:
+ """Compute expected number of frames after 1D convolution
+
+ Parameters
+ ----------
+ num_samples : int
+ Number of samples in the input signal
+ kernel_size : int
+ Kernel size
+ stride : int
+ Stride
+ padding : int
+ Padding
+ dilation : int
+ Dilation
+
+ Returns
+ -------
+ num_frames : int
+ Number of frames in the output signal
+
+ Source
+ ------
+ https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html#torch.nn.Conv1d
+ """
+ return 1 + (num_samples + 2 * padding - dilation * (kernel_size - 1) - 1) // stride
+
+
+def multi_conv_num_frames(
+ num_samples: int,
+ kernel_size: List[int] = None,
+ stride: List[int] = None,
+ padding: List[int] = None,
+ dilation: List[int] = None,
+) -> int:
+ num_frames = num_samples
+ for k, s, p, d in zip(kernel_size, stride, padding, dilation):
+ num_frames = conv1d_num_frames(
+ num_frames, kernel_size=k, stride=s, padding=p, dilation=d
+ )
+
+ return num_frames
+
+
+def conv1d_receptive_field_size(
+ num_frames=1, kernel_size=5, stride=1, padding=0, dilation=1
+):
+ """Compute size of receptive field
+
+ Parameters
+ ----------
+ num_frames : int, optional
+ Number of frames in the output signal
+ kernel_size : int
+ Kernel size
+ stride : int
+ Stride
+ padding : int
+ Padding
+ dilation : int
+ Dilation
+
+ Returns
+ -------
+ size : int
+ Receptive field size
+ """
+
+ effective_kernel_size = 1 + (kernel_size - 1) * dilation
+ return effective_kernel_size + (num_frames - 1) * stride - 2 * padding
+
+
+def multi_conv_receptive_field_size(
+ num_frames: int,
+ kernel_size: List[int] = None,
+ stride: List[int] = None,
+ padding: List[int] = None,
+ dilation: List[int] = None,
+) -> int:
+ receptive_field_size = num_frames
+
+ for k, s, p, d in reversed(list(zip(kernel_size, stride, padding, dilation))):
+ receptive_field_size = conv1d_receptive_field_size(
+ num_frames=receptive_field_size,
+ kernel_size=k,
+ stride=s,
+ padding=p,
+ dilation=d,
+ )
+ return receptive_field_size
+
+
+def conv1d_receptive_field_center(
+ frame=0, kernel_size=5, stride=1, padding=0, dilation=1
+) -> int:
+ """Compute center of receptive field
+
+ Parameters
+ ----------
+ frame : int
+ Frame index
+ kernel_size : int
+ Kernel size
+ stride : int
+ Stride
+ padding : int
+ Padding
+ dilation : int
+ Dilation
+
+ Returns
+ -------
+ center : int
+ Index of receptive field center
+ """
+
+ effective_kernel_size = 1 + (kernel_size - 1) * dilation
+ return frame * stride + (effective_kernel_size - 1) // 2 - padding
+
+
+def multi_conv_receptive_field_center(
+ frame: int,
+ kernel_size: List[int] = None,
+ stride: List[int] = None,
+ padding: List[int] = None,
+ dilation: List[int] = None,
+) -> int:
+ receptive_field_center = frame
+ for k, s, p, d in reversed(list(zip(kernel_size, stride, padding, dilation))):
+ receptive_field_center = conv1d_receptive_field_center(
+ frame=receptive_field_center,
+ kernel_size=k,
+ stride=s,
+ padding=p,
+ dilation=d,
+ )
+
+ return receptive_field_center
diff --git a/requirements.txt b/requirements.txt
index 7e71fe024..3a0aa74dc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,5 +15,5 @@ speechbrain >= 0.5.14
tensorboardX >= 2.6
torch >= 2.0.0
torch_audiomentations >= 0.11.0
-torchaudio >= 2.0.0
+torchaudio >= 2.2.0
torchmetrics >= 0.11.0
diff --git a/tests/data/database.yml b/tests/data/database.yml
index 608bf40b4..10d3fb084 100644
--- a/tests/data/database.yml
+++ b/tests/data/database.yml
@@ -2,6 +2,7 @@ Protocols:
Debug:
SpeakerDiarization:
Debug:
+ scope: database
train:
uri: debug.train.lst
annotation: debug.train.rttm
diff --git a/tests/data/debug.train.lst b/tests/data/debug.train.lst
index 16be824f4..471bf03d4 100644
--- a/tests/data/debug.train.lst
+++ b/tests/data/debug.train.lst
@@ -1,4 +1,4 @@
-trn00
+trñ00
trn01
trn02
trn03
diff --git a/tests/data/debug.train.rttm b/tests/data/debug.train.rttm
index 004a3f2eb..be89e2a4c 100644
--- a/tests/data/debug.train.rttm
+++ b/tests/data/debug.train.rttm
@@ -1,26 +1,26 @@
-SPEAKER trn00 1 3.168 0.800 MEO069
-SPEAKER trn00 1 5.463 0.640 MEO069
+SPEAKER trn00 1 3.168 0.800 MÉO069
+SPEAKER trn00 1 5.463 0.640 MÉO069
SPEAKER trn00 1 5.496 0.574 MEE068
-SPEAKER trn00 1 10.454 0.499 MEO069
+SPEAKER trn00 1 10.454 0.499 MÉO069
SPEAKER trn00 1 11.040 4.592 MEE068
-SPEAKER trn00 1 16.736 1.410 MEO069
+SPEAKER trn00 1 16.736 1.410 MÉO069
SPEAKER trn00 1 16.980 2.778 MEE067
SPEAKER trn00 1 18.883 0.490 MEE068
-SPEAKER trn00 1 18.985 1.831 MEO069
+SPEAKER trn00 1 18.985 1.831 MÉO069
SPEAKER trn00 1 20.944 0.447 MEE067
SPEAKER trn00 1 21.392 4.465 MEE068
-SPEAKER trn00 1 22.928 0.384 MEO069
-SPEAKER trn00 1 25.001 2.471 MEO069
+SPEAKER trn00 1 22.928 0.384 MÉO069
+SPEAKER trn00 1 25.001 2.471 MÉO069
SPEAKER trn00 1 28.033 1.967 MEE068
SPEAKER trn01 1 2.977 0.391 FEO066
SPEAKER trn01 1 18.705 0.964 MEE068
SPEAKER trn01 1 22.269 0.457 FEO065
-SPEAKER trn01 1 28.474 1.526 MEO069
+SPEAKER trn01 1 28.474 1.526 MÉO069
SPEAKER trn01 1 28.593 1.407 FEO066
SPEAKER trn01 1 28.993 1.007 FEO065
SPEAKER trn02 1 20.704 0.688 FEO066
SPEAKER trn03 1 0.000 1.184 MEE067
-SPEAKER trn03 1 1.104 28.896 MEO069
+SPEAKER trn03 1 1.104 28.896 MÉO069
SPEAKER trn04 1 14.032 1.744 MEE076
SPEAKER trn04 1 14.345 2.471 MEO074
SPEAKER trn04 1 16.736 7.216 MEE075
diff --git a/tests/data/trn00.wav "b/tests/data/tr\303\26100.wav"
similarity index 100%
rename from tests/data/trn00.wav
rename to "tests/data/tr\303\26100.wav"
diff --git a/tests/inference_test.py b/tests/inference_test.py
index bd5040394..da28b79d2 100644
--- a/tests/inference_test.py
+++ b/tests/inference_test.py
@@ -9,7 +9,7 @@
from pyannote.audio.models.segmentation.debug import SimpleSegmentationModel
from pyannote.audio.tasks import VoiceActivityDetection
-HF_SAMPLE_MODEL_ID = "pyannote/TestModelForContinuousIntegration"
+HF_SAMPLE_MODEL_ID = "pyannote/ci-segmentation"
def test_hf_download_inference():
diff --git a/tests/tasks/test_reproducibility.py b/tests/tasks/test_reproducibility.py
index a7307e0cf..88f2b2d8a 100644
--- a/tests/tasks/test_reproducibility.py
+++ b/tests/tasks/test_reproducibility.py
@@ -3,7 +3,7 @@
from pyannote.database import FileFinder, get_protocol
from pyannote.audio.models.segmentation.debug import SimpleSegmentationModel
-from pyannote.audio.tasks import MultiLabelSegmentation, VoiceActivityDetection
+from pyannote.audio.tasks import VoiceActivityDetection
def setup_tasks(task):
@@ -16,7 +16,8 @@ def setup_tasks(task):
def create_dl(model, task):
m = model(task=task)
- m.setup("fit")
+ m.prepare_data()
+ m.setup()
return task.train_dataloader()
@@ -31,35 +32,32 @@ def get_next5(dl):
def test_seeding_ensures_data_loaders():
"Setting a global seed for the dataloaders ensures that we get data back in the same order"
- for task in [VoiceActivityDetection, MultiLabelSegmentation]:
+ seed_everything(1)
+ protocol, vad = setup_tasks(VoiceActivityDetection)
+ dl = create_dl(SimpleSegmentationModel, vad)
+ last5a = get_next5(dl)
- seed_everything(1)
- protocol, vad = setup_tasks(task)
- dl = create_dl(SimpleSegmentationModel, vad)
- last5a = get_next5(dl)
+ seed_everything(1)
+ protocol, vad = setup_tasks(VoiceActivityDetection)
+ dl = create_dl(SimpleSegmentationModel, vad)
+ last5b = get_next5(dl)
- seed_everything(1)
- protocol, vad = setup_tasks(task)
- dl = create_dl(SimpleSegmentationModel, vad)
- last5b = get_next5(dl)
-
- for i in range(len(last5b)):
- assert torch.equal(last5a[i]["X"], last5b[i]["X"])
+ for i in range(len(last5b)):
+ assert torch.equal(last5a[i]["X"], last5b[i]["X"])
def test_different_seeds():
"Changing the global seed will change the order of the data that loads"
- for task in [VoiceActivityDetection, MultiLabelSegmentation]:
- protocol, vad = setup_tasks(task)
- seed_everything(4)
- dl = create_dl(SimpleSegmentationModel, vad)
- last5a = get_next5(dl)
+ protocol, vad = setup_tasks(VoiceActivityDetection)
+ seed_everything(4)
+ dl = create_dl(SimpleSegmentationModel, vad)
+ last5a = get_next5(dl)
- protocol, vad = setup_tasks(task)
- seed_everything(5)
- dl = create_dl(SimpleSegmentationModel, vad)
- last5b = get_next5(dl)
+ protocol, vad = setup_tasks(VoiceActivityDetection)
+ seed_everything(5)
+ dl = create_dl(SimpleSegmentationModel, vad)
+ last5b = get_next5(dl)
- for i in range(5):
- assert not torch.equal(last5a[i]["X"], last5b[i]["X"])
+ for i in range(5):
+ assert not torch.equal(last5a[i]["X"], last5b[i]["X"])
diff --git a/tests/tasks/test_specifications.py b/tests/tasks/test_specifications.py
new file mode 100644
index 000000000..32b816155
--- /dev/null
+++ b/tests/tasks/test_specifications.py
@@ -0,0 +1,27 @@
+import pytest
+from pyannote.database import FileFinder, get_protocol
+
+from pyannote.audio.core.model import Model
+from pyannote.audio.core.task import UnknownSpecificationsError
+from pyannote.audio.tasks import SpeakerDiarization
+
+
+@pytest.fixture()
+def protocol():
+ return get_protocol(
+ "Debug.SpeakerDiarization.Debug", preprocessors={"audio": FileFinder()}
+ )
+
+
+def test_unknown_specifications_error_raised_on_non_setup_task(protocol):
+ task = SpeakerDiarization(protocol=protocol)
+ with pytest.raises(UnknownSpecificationsError):
+ _ = task.specifications
+
+
+def test_unknown_specifications_error_raised_on_non_setup_model_task(protocol):
+ task = SpeakerDiarization(protocol=protocol)
+ model = Model.from_pretrained("pyannote/ci-segmentation")
+ model.task = task
+ with pytest.raises(UnknownSpecificationsError):
+ _ = model.specifications
diff --git a/tests/test_cli.py b/tests/test_cli.py
new file mode 100644
index 000000000..f62cc5260
--- /dev/null
+++ b/tests/test_cli.py
@@ -0,0 +1,149 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2024- CNRS
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import subprocess
+
+import pytest
+from pyannote.database import FileFinder, get_protocol
+
+
+@pytest.fixture()
+def protocol():
+ return get_protocol(
+ "Debug.SpeakerDiarization.Debug", preprocessors={"audio": FileFinder()}
+ )
+
+
+@pytest.fixture()
+def database():
+ return "./tests/data/database.yml"
+
+
+@pytest.fixture()
+def model():
+ return "pyannote/ci-segmentation"
+
+
+def test_cli_train_vad(database, protocol):
+ res = subprocess.run(
+ [
+ "pyannote-audio-train",
+ "model=DebugSegmentation",
+ "task=VoiceActivityDetection",
+ f"+registry={database}",
+ f"protocol={protocol.name}",
+ "trainer=fast_dev_run",
+ "hydra.run.dir=.", # run hydra app in current directory
+ "hydra.output_subdir=null", # disable hydra outputs
+ "hydra/hydra_logging=disabled",
+ "hydra/job_logging=disabled",
+ ]
+ )
+ assert res.returncode == 0
+
+
+def test_cli_train_segmentation(database, protocol):
+ res = subprocess.run(
+ [
+ "pyannote-audio-train",
+ "model=DebugSegmentation",
+ "task=SpeakerDiarization",
+ f"+registry={database}",
+ f"protocol={protocol.name}",
+ "trainer=fast_dev_run",
+ "hydra.run.dir=.", # run hydra app in current directory
+ "hydra.output_subdir=null", # disable hydra outputs
+ "hydra/hydra_logging=disabled",
+ "hydra/job_logging=disabled",
+ ]
+ )
+ assert res.returncode == 0
+
+
+def test_cli_train_osd(database, protocol):
+ res = subprocess.run(
+ [
+ "pyannote-audio-train",
+ "model=DebugSegmentation",
+ "task=OverlappedSpeechDetection",
+ f"+registry={database}",
+ f"protocol={protocol.name}",
+ "trainer=fast_dev_run",
+ "hydra.run.dir=.", # run hydra app in current directory
+ "hydra.output_subdir=null", # disable hydra outputs
+ "hydra/hydra_logging=disabled",
+ "hydra/job_logging=disabled",
+ ]
+ )
+ assert res.returncode == 0
+
+
+def test_cli_train_supervised_representation_with_arcface(database, protocol):
+ res = subprocess.run(
+ [
+ "pyannote-audio-train",
+ "model=DebugEmbedding",
+ "task=SpeakerEmbedding",
+ f"+registry={database}",
+ f"protocol={protocol.name}",
+ "trainer=fast_dev_run",
+ "hydra.run.dir=.", # run hydra app in current directory
+ "hydra.output_subdir=null", # disable hydra outputs
+ "hydra/hydra_logging=disabled",
+ "hydra/job_logging=disabled",
+ ]
+ )
+ assert res.returncode == 0
+
+
+def test_cli_train_segmentation_with_pyannet(database, protocol):
+ res = subprocess.run(
+ [
+ "pyannote-audio-train",
+ "model=PyanNet",
+ "task=SpeakerDiarization",
+ f"+registry={database}",
+ f"protocol={protocol.name}",
+ "trainer=fast_dev_run",
+ "hydra.run.dir=.", # run hydra app in current directory
+ "hydra.output_subdir=null", # disable hydra outputs
+ "hydra/hydra_logging=disabled",
+ "hydra/job_logging=disabled",
+ ]
+ )
+ assert res.returncode == 0
+
+
+def test_cli_eval_segmentation_model(database, protocol, model):
+ res = subprocess.run(
+ [
+ "pyannote-audio-eval",
+ f"model={model}",
+ f"+registry={database}",
+ f"protocol={protocol.name}",
+ "hydra.run.dir=.", # run hydra app in current directory
+ "hydra.output_subdir=null", # disable hydra outputs
+ "hydra/hydra_logging=disabled",
+ "hydra/job_logging=disabled",
+ ]
+ )
+ assert res.returncode == 0
diff --git a/tests/test_metrics.py b/tests/test_metrics.py
new file mode 100644
index 000000000..c366dc091
--- /dev/null
+++ b/tests/test_metrics.py
@@ -0,0 +1,142 @@
+# MIT License
+#
+# Copyright (c) 2024- CNRS
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import pytest
+import torch
+
+from pyannote.audio.torchmetrics.functional.audio.diarization_error_rate import (
+ _der_update,
+ diarization_error_rate,
+)
+
+
+@pytest.fixture
+def target():
+ chunk1 = [[0, 0], [1, 0], [1, 0], [1, 1], [1, 1], [0, 1], [0, 1]]
+ chunk2 = [[0, 0], [0, 0], [1, 0], [1, 0], [1, 0], [1, 0], [0, 0]]
+ return torch.tensor([chunk1, chunk2], dtype=torch.float32).transpose(2, 1)
+
+
+@pytest.fixture
+def prediction():
+ chunk1 = [[0, 0], [1, 0], [0, 0], [1, 1], [0, 1], [1, 1], [1, 0]]
+ chunk2 = [[0, 0], [0, 0], [0, 1], [0, 1], [0, 1], [1, 1], [1, 0]]
+ return torch.tensor([chunk1, chunk2], dtype=torch.float32).transpose(2, 1)
+
+
+def test_frame_reduction(target, prediction):
+ false_alarm, missed_detection, speaker_confusion, speech_total = _der_update(
+ prediction, target, reduce="frame"
+ )
+
+ torch.testing.assert_close(
+ false_alarm,
+ torch.Tensor(
+ [[0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0]]
+ ),
+ )
+
+ torch.testing.assert_close(
+ missed_detection,
+ torch.Tensor(
+ [
+ [0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ]
+ ),
+ )
+
+ torch.testing.assert_close(
+ speaker_confusion,
+ torch.Tensor(
+ [[0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]
+ ),
+ )
+
+ torch.testing.assert_close(
+ speech_total,
+ torch.Tensor(
+ [[0.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0]]
+ ),
+ )
+
+
+def test_chunk_reduction(target, prediction):
+ false_alarm, missed_detection, speaker_confusion, speech_total = _der_update(
+ prediction, target, reduce="chunk"
+ )
+
+ torch.testing.assert_close(
+ false_alarm,
+ torch.Tensor([1.0, 2.0]),
+ )
+
+ torch.testing.assert_close(
+ missed_detection,
+ torch.Tensor([2.0, 0.0]),
+ )
+
+ torch.testing.assert_close(
+ speaker_confusion,
+ torch.Tensor([1.0, 0.0]),
+ )
+
+ torch.testing.assert_close(
+ speech_total,
+ torch.Tensor([8.0, 4.0]),
+ )
+
+
+def test_batch_reduction(target, prediction):
+ false_alarm, missed_detection, speaker_confusion, speech_total = _der_update(
+ prediction, target, reduce="batch"
+ )
+ torch.testing.assert_close(false_alarm.item(), 3.0)
+ torch.testing.assert_close(missed_detection.item(), 2.0)
+ torch.testing.assert_close(speaker_confusion.item(), 1.0)
+ torch.testing.assert_close(speech_total.item(), 12.0)
+
+
+def test_batch_der(target, prediction):
+ der = diarization_error_rate(prediction, target, reduce="batch")
+ torch.testing.assert_close(der.item(), (3.0 + 2.0 + 1.0) / 12.0)
+
+
+def test_batch_der_with_components(target, prediction):
+ der, (
+ false_alarm,
+ missed_detection,
+ speaker_confusion,
+ speech_total,
+ ) = diarization_error_rate(
+ prediction, target, reduce="batch", return_components=True
+ )
+ torch.testing.assert_close(der.item(), (3.0 + 2.0 + 1.0) / 12.0)
+ torch.testing.assert_close(false_alarm.item(), 3.0)
+ torch.testing.assert_close(missed_detection.item(), 2.0)
+ torch.testing.assert_close(speaker_confusion.item(), 1.0)
+ torch.testing.assert_close(speech_total.item(), 12.0)
+
+
+def test_chunk_der(target, prediction):
+ der = diarization_error_rate(prediction, target, reduce="chunk")
+ torch.testing.assert_close(der, torch.Tensor([4.0 / 8.0, 2.0 / 4.0]))
diff --git a/tests/test_sample.py b/tests/test_sample.py
new file mode 100644
index 000000000..d47dc9613
--- /dev/null
+++ b/tests/test_sample.py
@@ -0,0 +1,28 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2024- CNRS
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+def test_sample():
+ from pyannote.audio.sample import SAMPLE_FILE
+
+ assert "annotation" in SAMPLE_FILE
+ assert "annotated" in SAMPLE_FILE
diff --git a/tests/test_train.py b/tests/test_train.py
index 7a7bfe338..6a7a6c69b 100644
--- a/tests/test_train.py
+++ b/tests/test_train.py
@@ -1,11 +1,39 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2024- CNRS
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+from tempfile import mkstemp
+
import pytest
from pyannote.database import FileFinder, get_protocol
from pytorch_lightning import Trainer
+from pyannote.audio.models.embedding.debug import SimpleEmbeddingModel
from pyannote.audio.models.segmentation.debug import SimpleSegmentationModel
from pyannote.audio.tasks import (
+ MultiLabelSegmentation,
OverlappedSpeechDetection,
SpeakerDiarization,
+ SupervisedRepresentationLearningWithArcFace,
VoiceActivityDetection,
)
@@ -17,6 +45,31 @@ def protocol():
)
+@pytest.fixture()
+def cache():
+ return mkstemp()[1]
+
+
+@pytest.fixture()
+def gender_protocol():
+ def to_gender(file):
+ annotation = file["annotation"]
+ mapping = {label: label[0] for label in annotation.labels()}
+ return annotation.rename_labels(mapping)
+
+ def classes(file):
+ return ["M", "F"]
+
+ return get_protocol(
+ "Debug.SpeakerDiarization.Debug",
+ preprocessors={
+ "audio": FileFinder(),
+ "annotation": to_gender,
+ "classes": classes,
+ },
+ )
+
+
def test_train_segmentation(protocol):
segmentation = SpeakerDiarization(protocol)
model = SimpleSegmentationModel(task=segmentation)
@@ -24,6 +77,48 @@ def test_train_segmentation(protocol):
trainer.fit(model)
+def test_train_segmentation_with_cached_data_mono_device(protocol, cache):
+ first_task = SpeakerDiarization(protocol, cache=cache)
+ first_model = SimpleSegmentationModel(task=first_task)
+ first_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ first_trainer.fit(first_model)
+
+ second_task = SpeakerDiarization(protocol, cache=cache)
+ second_model = SimpleSegmentationModel(task=second_task)
+ second_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ second_trainer.fit(second_model)
+
+
+def test_train_multilabel_segmentation(gender_protocol):
+ multilabel_segmentation = MultiLabelSegmentation(gender_protocol)
+ model = SimpleSegmentationModel(task=multilabel_segmentation)
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+
+def test_train_multilabel_segmentation_with_cached_data_mono_device(
+ gender_protocol, cache
+):
+ first_task = MultiLabelSegmentation(gender_protocol, cache=cache)
+ first_model = SimpleSegmentationModel(task=first_task)
+ first_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ first_trainer.fit(first_model)
+
+ second_task = MultiLabelSegmentation(gender_protocol, cache=cache)
+ second_model = SimpleSegmentationModel(task=second_task)
+ second_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ second_trainer.fit(second_model)
+
+
+def test_train_supervised_representation_with_arcface(protocol):
+ supervised_representation_with_arface = SupervisedRepresentationLearningWithArcFace(
+ protocol
+ )
+ model = SimpleEmbeddingModel(task=supervised_representation_with_arface)
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+
def test_train_voice_activity_detection(protocol):
voice_activity_detection = VoiceActivityDetection(protocol)
model = SimpleSegmentationModel(task=voice_activity_detection)
@@ -31,6 +126,18 @@ def test_train_voice_activity_detection(protocol):
trainer.fit(model)
+def test_train_voice_activity_detection_with_cached_data_mono_device(protocol, cache):
+ first_task = VoiceActivityDetection(protocol, cache=cache)
+ first_model = SimpleSegmentationModel(task=first_task)
+ first_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ first_trainer.fit(first_model)
+
+ second_task = VoiceActivityDetection(protocol, cache=cache)
+ second_model = SimpleSegmentationModel(task=second_task)
+ second_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ second_trainer.fit(second_model)
+
+
def test_train_overlapped_speech_detection(protocol):
overlapped_speech_detection = OverlappedSpeechDetection(protocol)
model = SimpleSegmentationModel(task=overlapped_speech_detection)
@@ -38,6 +145,20 @@ def test_train_overlapped_speech_detection(protocol):
trainer.fit(model)
+def test_train_overlapped_speech_detection_with_cached_data_mono_device(
+ protocol, cache
+):
+ first_task = OverlappedSpeechDetection(protocol, cache=cache)
+ first_model = SimpleSegmentationModel(task=first_task)
+ first_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ first_trainer.fit(first_model)
+
+ second_task = OverlappedSpeechDetection(protocol, cache=cache)
+ second_model = SimpleSegmentationModel(task=second_task)
+ second_trainer = Trainer(fast_dev_run=True, accelerator="cpu", devices=1)
+ second_trainer.fit(second_model)
+
+
def test_finetune_with_task_that_does_not_need_setup_for_specs(protocol):
voice_activity_detection = VoiceActivityDetection(protocol)
model = SimpleSegmentationModel(task=voice_activity_detection)
@@ -62,6 +183,18 @@ def test_finetune_with_task_that_needs_setup_for_specs(protocol):
trainer.fit(model)
+def test_finetune_with_task_that_needs_setup_for_specs_and_with_cache(protocol, cache):
+ segmentation = SpeakerDiarization(protocol, cache=cache)
+ model = SimpleSegmentationModel(task=segmentation)
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+ segmentation = SpeakerDiarization(protocol, cache=cache)
+ model.task = segmentation
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+
def test_transfer_with_task_that_does_not_need_setup_for_specs(protocol):
segmentation = SpeakerDiarization(protocol)
model = SimpleSegmentationModel(task=segmentation)
@@ -94,7 +227,22 @@ def test_finetune_freeze_with_task_that_needs_setup_for_specs(protocol):
segmentation = SpeakerDiarization(protocol)
model.task = segmentation
- model.freeze_up_to("mfcc")
+ model.freeze_by_name("mfcc")
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+
+def test_finetune_freeze_with_task_that_needs_setup_for_specs_and_with_cache(
+ protocol, cache
+):
+ segmentation = SpeakerDiarization(protocol, cache=cache)
+ model = SimpleSegmentationModel(task=segmentation)
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+ segmentation = SpeakerDiarization(protocol, cache=cache)
+ model.task = segmentation
+ model.freeze_by_name("mfcc")
trainer = Trainer(fast_dev_run=True, accelerator="cpu")
trainer.fit(model)
@@ -107,7 +255,23 @@ def test_finetune_freeze_with_task_that_does_not_need_setup_for_specs(protocol):
vad = VoiceActivityDetection(protocol)
model.task = vad
- model.freeze_up_to("mfcc")
+ model.freeze_by_name("mfcc")
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+
+def test_finetune_freeze_with_task_that_does_not_need_setup_for_specs_and_with_cache(
+ protocol,
+ cache,
+):
+ vad = VoiceActivityDetection(protocol, cache=cache)
+ model = SimpleSegmentationModel(task=vad)
+ trainer = Trainer(fast_dev_run=True, accelerator="cpu")
+ trainer.fit(model)
+
+ vad = VoiceActivityDetection(protocol, cache=cache)
+ model.task = vad
+ model.freeze_by_name("mfcc")
trainer = Trainer(fast_dev_run=True, accelerator="cpu")
trainer.fit(model)
@@ -120,7 +284,7 @@ def test_transfer_freeze_with_task_that_does_not_need_setup_for_specs(protocol):
voice_activity_detection = VoiceActivityDetection(protocol)
model.task = voice_activity_detection
- model.freeze_up_to("mfcc")
+ model.freeze_by_name("mfcc")
trainer = Trainer(fast_dev_run=True, accelerator="cpu")
trainer.fit(model)
@@ -133,6 +297,6 @@ def test_transfer_freeze_with_task_that_needs_setup_for_specs(protocol):
segmentation = SpeakerDiarization(protocol)
model.task = segmentation
- model.freeze_up_to("mfcc")
+ model.freeze_by_name("mfcc")
trainer = Trainer(fast_dev_run=True, accelerator="cpu")
trainer.fit(model)
diff --git a/tests/utils/test_powerset.py b/tests/utils/test_powerset.py
index dd12eed41..e04480753 100644
--- a/tests/utils/test_powerset.py
+++ b/tests/utils/test_powerset.py
@@ -27,10 +27,8 @@
def test_roundtrip():
-
for num_classes in range(2, 5):
for max_set_size in range(1, num_classes + 1):
-
powerset = Powerset(num_classes, max_set_size)
# simulate a sequence where each frame is assigned to a different powerset class
@@ -51,3 +49,28 @@ def test_roundtrip():
reconstruction = powerset.to_powerset(batch_multilabel)
assert torch.equal(batch_powerset, reconstruction)
+
+
+def test_permutate_powerset():
+ for num_classes in range(1, 6):
+ for max_set_size in range(1, num_classes + 1):
+ powerset = Powerset(num_classes, max_set_size)
+
+ # create (num_powerset_class, num_powerset_class)-shaped tensor, where each frame is assigned to a different powerset class
+ # and convert it to its multi-label equivalent
+ t1 = torch.nn.functional.one_hot(
+ torch.arange(powerset.num_powerset_classes),
+ powerset.num_powerset_classes,
+ )
+ t1_ml = powerset.to_multilabel(t1)
+
+ # then permutate the powerset class in powerset space AND the multilabel equivalent in its native space
+ # and check it has the same result.
+ # perm = torch.randperm(num_classes)
+ perm = tuple(torch.randperm(num_classes).tolist())
+ t1_ml_perm = t1_ml[:, perm]
+ perm_ps = powerset.permutation_mapping[perm]
+ t1_ps_perm = t1[..., perm_ps]
+ t1_ps_perm_ml = powerset.to_multilabel(t1_ps_perm)
+
+ assert t1_ml_perm.equal(t1_ps_perm_ml)
diff --git a/tutorials/MRE_template.ipynb b/tutorials/MRE_template.ipynb
new file mode 100644
index 000000000..70ffacbc2
--- /dev/null
+++ b/tutorials/MRE_template.ipynb
@@ -0,0 +1,2220 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "provenance": [],
+ "gpuType": "T4",
+ "authorship_tag": "ABX9TyNUZLZoYLpzG6gIYECEOuiV",
+ "include_colab_link": true
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ },
+ "language_info": {
+ "name": "python"
+ },
+ "accelerator": "GPU",
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "3d0fe95350234ab599497683ae6d4ce6": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HBoxModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_239beda16fde4b1d9e6abfb47f036040",
+ "IPY_MODEL_2d6f5fe6f9ab4a8b853e7b023aaee35f",
+ "IPY_MODEL_771629a0fbab4b0e9ad6425b5affe380"
+ ],
+ "layout": "IPY_MODEL_8763b8e4c8104b879d4324257a810c0f"
+ }
+ },
+ "239beda16fde4b1d9e6abfb47f036040": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_22536aef3997408dbf5ea58241f01e3e",
+ "placeholder": "",
+ "style": "IPY_MODEL_2a6a5f33d7c34b6b996ab7a5b7c2f11d",
+ "value": "config.yaml: 100%"
+ }
+ },
+ "2d6f5fe6f9ab4a8b853e7b023aaee35f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "FloatProgressModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "FloatProgressModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ProgressView",
+ "bar_style": "success",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_c348b2f57c6c437fa8a9a2688bf17f4f",
+ "max": 469,
+ "min": 0,
+ "orientation": "horizontal",
+ "style": "IPY_MODEL_7526127b349a4467a6d3083d92bef5ec",
+ "value": 469
+ }
+ },
+ "771629a0fbab4b0e9ad6425b5affe380": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_30efc0ed76fb496483d4bb425a930636",
+ "placeholder": "",
+ "style": "IPY_MODEL_e760e231084f4889bb489bc550b7a816",
+ "value": " 469/469 [00:00<00:00, 21.8kB/s]"
+ }
+ },
+ "8763b8e4c8104b879d4324257a810c0f": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "22536aef3997408dbf5ea58241f01e3e": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "2a6a5f33d7c34b6b996ab7a5b7c2f11d": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "c348b2f57c6c437fa8a9a2688bf17f4f": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "7526127b349a4467a6d3083d92bef5ec": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "ProgressStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ProgressStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "bar_color": null,
+ "description_width": ""
+ }
+ },
+ "30efc0ed76fb496483d4bb425a930636": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "e760e231084f4889bb489bc550b7a816": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "9951dce8a6c947dd9a2ed6106cb68f30": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HBoxModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_d68c24e62487484b83bbb06271a6981c",
+ "IPY_MODEL_467f3c9f15184784aa913cb3ae46700f",
+ "IPY_MODEL_c87055ce8cef498f999a20ff2b34e1b8"
+ ],
+ "layout": "IPY_MODEL_63d957e24276476b9bf1be150675217c"
+ }
+ },
+ "d68c24e62487484b83bbb06271a6981c": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_afe35fd2ea654d7b861046e847f82e51",
+ "placeholder": "",
+ "style": "IPY_MODEL_c5f4f5f5fbad4d14973dc21eae2358d4",
+ "value": "pytorch_model.bin: 100%"
+ }
+ },
+ "467f3c9f15184784aa913cb3ae46700f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "FloatProgressModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "FloatProgressModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ProgressView",
+ "bar_style": "success",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_b4faa4c7fd01498abe07fef6189de4d4",
+ "max": 5905440,
+ "min": 0,
+ "orientation": "horizontal",
+ "style": "IPY_MODEL_35ab2642d8a5481780c43eaef7044f3c",
+ "value": 5905440
+ }
+ },
+ "c87055ce8cef498f999a20ff2b34e1b8": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_37de7e413b25451ca5288ea5f43dd2d5",
+ "placeholder": "",
+ "style": "IPY_MODEL_47012c0ff9394d77b8d857a933b4082e",
+ "value": " 5.91M/5.91M [00:00<00:00, 66.3MB/s]"
+ }
+ },
+ "63d957e24276476b9bf1be150675217c": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "afe35fd2ea654d7b861046e847f82e51": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "c5f4f5f5fbad4d14973dc21eae2358d4": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "b4faa4c7fd01498abe07fef6189de4d4": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "35ab2642d8a5481780c43eaef7044f3c": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "ProgressStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ProgressStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "bar_color": null,
+ "description_width": ""
+ }
+ },
+ "37de7e413b25451ca5288ea5f43dd2d5": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "47012c0ff9394d77b8d857a933b4082e": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "d3ca3e02944c49f88d2b232295b19293": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HBoxModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_392a6347341f4dac94cad19e1f0bf02b",
+ "IPY_MODEL_ba0102afa62c443eb9de89412301bb46",
+ "IPY_MODEL_b71a286118004001a9a65ece5ba352d2"
+ ],
+ "layout": "IPY_MODEL_29b969a7441d41059969962f338d0def"
+ }
+ },
+ "392a6347341f4dac94cad19e1f0bf02b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3d0be590ca374ef1a768b8d3577d3105",
+ "placeholder": "",
+ "style": "IPY_MODEL_c0ac81654e1c4904a87a2c777b520c09",
+ "value": "config.yaml: 100%"
+ }
+ },
+ "ba0102afa62c443eb9de89412301bb46": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "FloatProgressModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "FloatProgressModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ProgressView",
+ "bar_style": "success",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_36f8eb5005864f779aa8185acf55e2c5",
+ "max": 399,
+ "min": 0,
+ "orientation": "horizontal",
+ "style": "IPY_MODEL_5cbb5cf6a37d451c87215851ee8b0b65",
+ "value": 399
+ }
+ },
+ "b71a286118004001a9a65ece5ba352d2": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_ca3ee9d356bc464e82ee061375cc4ef2",
+ "placeholder": "",
+ "style": "IPY_MODEL_67e4c4a2768b40eca34e8add6265c40c",
+ "value": " 399/399 [00:00<00:00, 28.2kB/s]"
+ }
+ },
+ "29b969a7441d41059969962f338d0def": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "3d0be590ca374ef1a768b8d3577d3105": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "c0ac81654e1c4904a87a2c777b520c09": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "36f8eb5005864f779aa8185acf55e2c5": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "5cbb5cf6a37d451c87215851ee8b0b65": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "ProgressStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ProgressStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "bar_color": null,
+ "description_width": ""
+ }
+ },
+ "ca3ee9d356bc464e82ee061375cc4ef2": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "67e4c4a2768b40eca34e8add6265c40c": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "2149e37d14e94f82a77386682ba29195": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HBoxModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_501eb1f4c1a8458a86c917d7dac5eeb5",
+ "IPY_MODEL_7a115cf3065f4acdb0ae13577447a333",
+ "IPY_MODEL_532d713a67c94b0d8cf0d61be72c73e7"
+ ],
+ "layout": "IPY_MODEL_3f36703cc5bc4fbcbeb97ab722e573cc"
+ }
+ },
+ "501eb1f4c1a8458a86c917d7dac5eeb5": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_8088c86a3d394f9e88267196b369dfb9",
+ "placeholder": "",
+ "style": "IPY_MODEL_46c5a63bcc3a472284869bcb11407bed",
+ "value": "pytorch_model.bin: 100%"
+ }
+ },
+ "7a115cf3065f4acdb0ae13577447a333": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "FloatProgressModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "FloatProgressModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ProgressView",
+ "bar_style": "success",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_754c1729ba074d518557bd53c01e3787",
+ "max": 26645418,
+ "min": 0,
+ "orientation": "horizontal",
+ "style": "IPY_MODEL_bbe45325b7b74832bf6fe4a9769e0565",
+ "value": 26645418
+ }
+ },
+ "532d713a67c94b0d8cf0d61be72c73e7": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_9261da2864ce4fd9b0f05f2a2efc54a3",
+ "placeholder": "",
+ "style": "IPY_MODEL_940ed223c43d40e5b85eadf3a5ef0382",
+ "value": " 26.6M/26.6M [00:00<00:00, 172MB/s]"
+ }
+ },
+ "3f36703cc5bc4fbcbeb97ab722e573cc": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "8088c86a3d394f9e88267196b369dfb9": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "46c5a63bcc3a472284869bcb11407bed": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "754c1729ba074d518557bd53c01e3787": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "bbe45325b7b74832bf6fe4a9769e0565": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "ProgressStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ProgressStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "bar_color": null,
+ "description_width": ""
+ }
+ },
+ "9261da2864ce4fd9b0f05f2a2efc54a3": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "940ed223c43d40e5b85eadf3a5ef0382": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "ef97ca55c62b40f7bb233120f8efba62": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HBoxModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_2da74c40ebd44b61adaf840b9e7ce343",
+ "IPY_MODEL_c9517e2631c247b6ba083da05cfd0399",
+ "IPY_MODEL_29b6d0dc6624409c8c8a8e0565c2bc08"
+ ],
+ "layout": "IPY_MODEL_7b6f8f9b2eee485f8defe25d2a9afc4a"
+ }
+ },
+ "2da74c40ebd44b61adaf840b9e7ce343": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_fbaa859f9a8d4d5fb15667ede53a2cfb",
+ "placeholder": "",
+ "style": "IPY_MODEL_1840bc4e8cb54d3d89d5b1f199065c77",
+ "value": "config.yaml: 100%"
+ }
+ },
+ "c9517e2631c247b6ba083da05cfd0399": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "FloatProgressModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "FloatProgressModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ProgressView",
+ "bar_style": "success",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3f955f5b7421415bb79319058d0d094d",
+ "max": 221,
+ "min": 0,
+ "orientation": "horizontal",
+ "style": "IPY_MODEL_849cf4fb4ac249368fb8a5c837f8430a",
+ "value": 221
+ }
+ },
+ "29b6d0dc6624409c8c8a8e0565c2bc08": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "HTMLModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_0411eb97e38b4fa081e05f87076ba129",
+ "placeholder": "",
+ "style": "IPY_MODEL_34842bb9a73048caace624929cfc2b03",
+ "value": " 221/221 [00:00<00:00, 10.8kB/s]"
+ }
+ },
+ "7b6f8f9b2eee485f8defe25d2a9afc4a": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "fbaa859f9a8d4d5fb15667ede53a2cfb": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "1840bc4e8cb54d3d89d5b1f199065c77": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "3f955f5b7421415bb79319058d0d094d": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "849cf4fb4ac249368fb8a5c837f8430a": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "ProgressStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ProgressStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "bar_color": null,
+ "description_width": ""
+ }
+ },
+ "0411eb97e38b4fa081e05f87076ba129": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "1.2.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "34842bb9a73048caace624929cfc2b03": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "DescriptionStyleModel",
+ "model_module_version": "1.5.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ }
+ }
+ }
+ },
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "view-in-github",
+ "colab_type": "text"
+ },
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Sharing a minimal reproduction example (MRE) is a prerequisite for `pyannote.audio` contributors to be able to solve them.\n",
+ "\n",
+ "Having an MRE is very important for contributors to be able to reproduce the bug in the same way that you are experiencing it. When testing a potential fix for the issue, contributors will use the MRE to validate that the fix is working as intended.\n",
+ "\n",
+ "This notebook provides a template that should help you create such a MRE.\n",
+ "\n",
+ "Duplicate it, edit it, and share it as a link within your `pyannote.audio` bug report."
+ ],
+ "metadata": {
+ "id": "SWidE_E7ol-U"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# Setup\n",
+ "\n",
+ "Before anything, make sure to run this section."
+ ],
+ "metadata": {
+ "id": "k1vex_KZTDFm"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Specify the `pyannote.audio` version you found the issue in (including the Git commit hash if using a non-released version)."
+ ],
+ "metadata": {
+ "id": "XRNSJ2omranm"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "!pip install -qqq pyannote.audio==3.1.1"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "THKj6xjdSv9k",
+ "outputId": "719baaf8-2028-4b8e-8e46-e6a813aaf6f8"
+ },
+ "execution_count": 1,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m208.7/208.7 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m44.6/44.6 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m15.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m79.5/79.5 kB\u001b[0m \u001b[31m10.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.5/58.5 kB\u001b[0m \u001b[31m8.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m48.1/48.1 kB\u001b[0m \u001b[31m7.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m51.4/51.4 kB\u001b[0m \u001b[31m6.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m118.6/118.6 kB\u001b[0m \u001b[31m16.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m630.6/630.6 kB\u001b[0m \u001b[31m21.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m101.7/101.7 kB\u001b[0m \u001b[31m14.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m47.9/47.9 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m806.1/806.1 kB\u001b[0m \u001b[31m25.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m777.7/777.7 kB\u001b[0m \u001b[31m29.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m117.0/117.0 kB\u001b[0m \u001b[31m18.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m413.4/413.4 kB\u001b[0m \u001b[31m29.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.3/1.3 MB\u001b[0m \u001b[31m39.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m59.6/59.6 kB\u001b[0m \u001b[31m9.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m233.4/233.4 kB\u001b[0m \u001b[31m27.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m116.4/116.4 kB\u001b[0m \u001b[31m14.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m78.6/78.6 kB\u001b[0m \u001b[31m12.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m526.7/526.7 kB\u001b[0m \u001b[31m45.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Building wheel for antlr4-python3-runtime (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ " Building wheel for docopt (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ " Building wheel for julius (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Declare your [Huggingface token](https://huggingface.co/settings/tokens) as `HF_TOKEN` secret by clicking on the 🔑 icon on the left:\n",
+ "\n",
+ "* **Name**: `HF_TOKEN` \n",
+ "* **Value**: your Huggingface token (e.g. `hf_ABCdzRFTkglhlcalBAPGHSQvxLmQs`)"
+ ],
+ "metadata": {
+ "id": "ZLhE8e7iTpTu"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Check that you can load the pretrained pipeline."
+ ],
+ "metadata": {
+ "id": "Mogy5_qYUoXs"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# access your HF token\n",
+ "from google.colab import userdata\n",
+ "hf_token = userdata.get('HF_TOKEN')\n",
+ "\n",
+ "# load the pretrained pipeline\n",
+ "from pyannote.audio import Pipeline\n",
+ "pipeline = Pipeline.from_pretrained(\n",
+ " \"pyannote/speaker-diarization-3.1\",\n",
+ " use_auth_token=hf_token)"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 307,
+ "referenced_widgets": [
+ "3d0fe95350234ab599497683ae6d4ce6",
+ "239beda16fde4b1d9e6abfb47f036040",
+ "2d6f5fe6f9ab4a8b853e7b023aaee35f",
+ "771629a0fbab4b0e9ad6425b5affe380",
+ "8763b8e4c8104b879d4324257a810c0f",
+ "22536aef3997408dbf5ea58241f01e3e",
+ "2a6a5f33d7c34b6b996ab7a5b7c2f11d",
+ "c348b2f57c6c437fa8a9a2688bf17f4f",
+ "7526127b349a4467a6d3083d92bef5ec",
+ "30efc0ed76fb496483d4bb425a930636",
+ "e760e231084f4889bb489bc550b7a816",
+ "9951dce8a6c947dd9a2ed6106cb68f30",
+ "d68c24e62487484b83bbb06271a6981c",
+ "467f3c9f15184784aa913cb3ae46700f",
+ "c87055ce8cef498f999a20ff2b34e1b8",
+ "63d957e24276476b9bf1be150675217c",
+ "afe35fd2ea654d7b861046e847f82e51",
+ "c5f4f5f5fbad4d14973dc21eae2358d4",
+ "b4faa4c7fd01498abe07fef6189de4d4",
+ "35ab2642d8a5481780c43eaef7044f3c",
+ "37de7e413b25451ca5288ea5f43dd2d5",
+ "47012c0ff9394d77b8d857a933b4082e",
+ "d3ca3e02944c49f88d2b232295b19293",
+ "392a6347341f4dac94cad19e1f0bf02b",
+ "ba0102afa62c443eb9de89412301bb46",
+ "b71a286118004001a9a65ece5ba352d2",
+ "29b969a7441d41059969962f338d0def",
+ "3d0be590ca374ef1a768b8d3577d3105",
+ "c0ac81654e1c4904a87a2c777b520c09",
+ "36f8eb5005864f779aa8185acf55e2c5",
+ "5cbb5cf6a37d451c87215851ee8b0b65",
+ "ca3ee9d356bc464e82ee061375cc4ef2",
+ "67e4c4a2768b40eca34e8add6265c40c",
+ "2149e37d14e94f82a77386682ba29195",
+ "501eb1f4c1a8458a86c917d7dac5eeb5",
+ "7a115cf3065f4acdb0ae13577447a333",
+ "532d713a67c94b0d8cf0d61be72c73e7",
+ "3f36703cc5bc4fbcbeb97ab722e573cc",
+ "8088c86a3d394f9e88267196b369dfb9",
+ "46c5a63bcc3a472284869bcb11407bed",
+ "754c1729ba074d518557bd53c01e3787",
+ "bbe45325b7b74832bf6fe4a9769e0565",
+ "9261da2864ce4fd9b0f05f2a2efc54a3",
+ "940ed223c43d40e5b85eadf3a5ef0382",
+ "ef97ca55c62b40f7bb233120f8efba62",
+ "2da74c40ebd44b61adaf840b9e7ce343",
+ "c9517e2631c247b6ba083da05cfd0399",
+ "29b6d0dc6624409c8c8a8e0565c2bc08",
+ "7b6f8f9b2eee485f8defe25d2a9afc4a",
+ "fbaa859f9a8d4d5fb15667ede53a2cfb",
+ "1840bc4e8cb54d3d89d5b1f199065c77",
+ "3f955f5b7421415bb79319058d0d094d",
+ "849cf4fb4ac249368fb8a5c837f8430a",
+ "0411eb97e38b4fa081e05f87076ba129",
+ "34842bb9a73048caace624929cfc2b03"
+ ]
+ },
+ "id": "i8rs3XylTTys",
+ "outputId": "b1b7445e-6f29-4ce0-c111-f5ffcb488c47"
+ },
+ "execution_count": 3,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ "config.yaml: 0%| | 0.00/469 [00:00, ?B/s]"
+ ],
+ "application/vnd.jupyter.widget-view+json": {
+ "version_major": 2,
+ "version_minor": 0,
+ "model_id": "3d0fe95350234ab599497683ae6d4ce6"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "/usr/local/lib/python3.10/dist-packages/pyannote/audio/pipelines/speaker_verification.py:43: UserWarning: torchaudio._backend.get_audio_backend has been deprecated. With dispatcher enabled, this function is no-op. You can remove the function call.\n",
+ " backend = torchaudio.get_audio_backend()\n",
+ "/usr/local/lib/python3.10/dist-packages/pyannote/audio/pipelines/speaker_verification.py:53: 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(backend)\n",
+ "/usr/local/lib/python3.10/dist-packages/pyannote/audio/tasks/segmentation/mixins.py:37: UserWarning: `torchaudio.backend.common.AudioMetaData` has been moved to `torchaudio.AudioMetaData`. Please update the import path.\n",
+ " from torchaudio.backend.common import AudioMetaData\n"
+ ]
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ "pytorch_model.bin: 0%| | 0.00/5.91M [00:00, ?B/s]"
+ ],
+ "application/vnd.jupyter.widget-view+json": {
+ "version_major": 2,
+ "version_minor": 0,
+ "model_id": "9951dce8a6c947dd9a2ed6106cb68f30"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ "config.yaml: 0%| | 0.00/399 [00:00, ?B/s]"
+ ],
+ "application/vnd.jupyter.widget-view+json": {
+ "version_major": 2,
+ "version_minor": 0,
+ "model_id": "d3ca3e02944c49f88d2b232295b19293"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ "pytorch_model.bin: 0%| | 0.00/26.6M [00:00, ?B/s]"
+ ],
+ "application/vnd.jupyter.widget-view+json": {
+ "version_major": 2,
+ "version_minor": 0,
+ "model_id": "2149e37d14e94f82a77386682ba29195"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ "config.yaml: 0%| | 0.00/221 [00:00, ?B/s]"
+ ],
+ "application/vnd.jupyter.widget-view+json": {
+ "version_major": 2,
+ "version_minor": 0,
+ "model_id": "ef97ca55c62b40f7bb233120f8efba62"
+ }
+ },
+ "metadata": {}
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Check that GPU is available and send pipeline to GPU."
+ ],
+ "metadata": {
+ "id": "SSGSKkLdXheL"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import torch\n",
+ "if torch.cuda.is_available():\n",
+ " gpu = torch.device(\"cuda\")\n",
+ " pipeline.to(gpu)\n",
+ "else:\n",
+ " print(\"Please switch to (free) T4 GPU runtime.\")"
+ ],
+ "metadata": {
+ "id": "vxMDKwA0XcKi"
+ },
+ "execution_count": 4,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Dowload a sample audio file (make sure the download link is public or your bug report will not be reproducible by anyone)."
+ ],
+ "metadata": {
+ "id": "ISngZk15Uzhb"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "!wget https://github.com/pyannote/pyannote-audio/raw/develop/tutorials/assets/sample.wav"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "jYfZIys7Te0z",
+ "outputId": "ba64b747-c973-4274-feb4-3b1b4293e529"
+ },
+ "execution_count": 5,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "--2024-01-08 15:31:41-- https://github.com/pyannote/pyannote-audio/raw/develop/tutorials/assets/sample.wav\n",
+ "Resolving github.com (github.com)... 140.82.113.4\n",
+ "Connecting to github.com (github.com)|140.82.113.4|:443... connected.\n",
+ "HTTP request sent, awaiting response... 302 Found\n",
+ "Location: https://raw.githubusercontent.com/pyannote/pyannote-audio/develop/tutorials/assets/sample.wav [following]\n",
+ "--2024-01-08 15:31:41-- https://raw.githubusercontent.com/pyannote/pyannote-audio/develop/tutorials/assets/sample.wav\n",
+ "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n",
+ "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n",
+ "HTTP request sent, awaiting response... 200 OK\n",
+ "Length: 960104 (938K) [audio/wav]\n",
+ "Saving to: ‘sample.wav’\n",
+ "\n",
+ "sample.wav 100%[===================>] 937.60K --.-KB/s in 0.04s \n",
+ "\n",
+ "2024-01-08 15:31:42 (25.7 MB/s) - ‘sample.wav’ saved [960104/960104]\n",
+ "\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Apply the pretrained pipeline and visualize the output."
+ ],
+ "metadata": {
+ "id": "RH6AEClgaAgU"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "diarization = pipeline(\"sample.wav\")"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "AoCal-3UXK0z",
+ "outputId": "59428f0f-af42-4e78-fc04-abd6324c73db"
+ },
+ "execution_count": 6,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "/usr/local/lib/python3.10/dist-packages/pyannote/audio/utils/reproducibility.py:74: ReproducibilityWarning: TensorFloat-32 (TF32) has been disabled as it might lead to reproducibility issues and lower accuracy.\n",
+ "It can be re-enabled by calling\n",
+ " >>> import torch\n",
+ " >>> torch.backends.cuda.matmul.allow_tf32 = True\n",
+ " >>> torch.backends.cudnn.allow_tf32 = True\n",
+ "See https://github.com/pyannote/pyannote-audio/issues/1370 for more details.\n",
+ "\n",
+ " warnings.warn(\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "diarization"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 259
+ },
+ "id": "iIKvKZoZXN_M",
+ "outputId": "e7dcd7e1-0512-425c-b46a-6dc18d7a67b1"
+ },
+ "execution_count": 7,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ ""
+ ],
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAABiIAAADyCAYAAADAzN2uAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAe8UlEQVR4nO3de5RV5X038O/hKnEuCjgzoCPiJV4SiMamikmMQQWV5RKlpsalkWhkhYV0qWnkjUWNsZqG9aY2qdrc8NIgxmWjJjG1uViwJqBGG0MxKY0UoykyIMhw0QGEef/wZepkCJyR2XMG5vNZa9Zi9n7Os3/n8Jxn79nfc/Yutba2tgYAAAAAAKAAfSpdAAAAAAAAsPcSRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIURRAAAAAAAAIXZ64OIVatWZerUqTn44IMzcODANDQ0ZPz48fn5z3+eJDnkkENSKpVSKpWy77775v3vf38eeOCBtsd//vOfb1v/9p+jjjqqw7buu+++9O3bN9OmTeuwbv78+SmVSlm7dm3bsuXLl2fUqFE5+eST09zc3NZmRz8rVqzoUE/fvn3T2NiYKVOmZM2aNWW/Ji0tLZk2bVqGDBmSqqqqTJo0KU1NTe3avPTSS5kwYULe9a53pa6uLp/97Gfz5ptvlr2N3sY466iccfYXf/EXOf744zNw4MAce+yxZffdWxlnHe1qnP3qV7/Kxz/+8TQ2NmbQoEE5+uij85WvfKXs/gEAAADYff12t4PmTc1dUUdZagfWdvoxkyZNyubNm3PPPffk0EMPTVNTUx577LGsXr26rc0XvvCFXH755Vm3bl2+/OUv58///M9z4IEH5qSTTkqSvOc978lPf/rTdv3269fxpZs9e3auueaafP3rX8+Xv/zl7LPPPn+0rqVLl+b000/PMccckwceeCCDBg1qW7dkyZLU1NS0a19XV9f27+31bN26Nb/5zW9y6aWXprm5Offff39Zr8lVV12VH/7wh3nggQdSW1ubK664Iuedd17bycytW7dmwoQJaWhoyIIFC/LKK6/kE5/4RPr3759bbrmlrG10pa1v+7/qDn2HDOn0Y4yzjnY1zra79NJL89RTT2XRokVl9Vuk1zZu7rZt7b/vgE4/xjjraFfj7Nlnn01dXV3mzJmTxsbGLFiwIFOmTEnfvn1zxRVXlLUNAAAAAHbPbgcRFz96YVfUUZbvT/xhp9qvXbs2TzzxRObPn5+PfOQjSZIRI0bkT//0T9u1q66uTkNDQxoaGnL77bdnzpw5+cEPftB24q5fv35paGjY6baWLVuWBQsW5Lvf/W7mzZuXBx98MBdeuOPXZtGiRRk/fnzGjh2be+65p8NJwLq6uuy3335/dFtvr+fAAw/M+eefn7vuumun9W3X3Nyc2bNnZ+7cuRk7dmyS5K677srRRx+dJ598MieeeGJ+/OMf59e//nV++tOfpr6+Pscee2xuuummzJgxI5///OczYEDnT6DujhWjj+3W7R34Py93qr1x1lE54yxJvvrVryZ565P+PSGIOHPWvG7b1pM3ju9Ue+Oso3LG2aWXXtruMYceemgWLlyYBx98UBABAAAA0E326kszVVVVpaqqKg8//HA2bdpU1mP69euX/v37Z/Pmzn0y+q677sqECRNSW1ubiy66KLNnz95huwULFuQjH/lIJk2alDlz5uzwk8id8eKLL+ZHP/pR2eHAs88+my1btuS0005rW3bUUUfl4IMPzsKFC5MkCxcuzKhRo1JfX9/WZvz48Vm3bl2ef/753ap3b2ScdVTOOKNzjLOO3uk4a25uzuDBg3erVgAAAADKt1cHEf369cvdd9+de+65J/vtt18++MEP5tprr/2jn7zevHlzvvjFL6a5ubnt07VJ8h//8R9tJwG3/3z6059uW79t27bcfffdueiii5IkF1xwQX72s59l2bJlHbZx7rnn5uyzz85tt92WUqm0wzoOOuigdtt6z3ve02799noGDRqUkSNH5vnnn8+MGTPKek1WrFiRAQMGdPiEcn19fdt121esWNEuhNi+fvs62jPOOipnnNE5xllH72ScLViwIPfff3+mTJlS1jYAAAAA2H27fWmmnm7SpEmZMGFCnnjiiTz55JN59NFHM2vWrHzrW9/K5MmTkyQzZszIzJkz09LSkqqqqvzN3/xNJkyY0NbHkUceme9///vt+n37Nc9/8pOfZOPGjTnrrLOSJEOHDs3pp5+eO++8MzfddFO7x51zzjl56KGH8sQTT+TDH/7wDmt+4oknUl1d3fZ7//79263fXk9LS0vmzJmT5557LtOnT+/8i0OXMc7oDsbZ7lm8eHHOOeec3HDDDRk3blwh2wAAAACgo90OIr595tyuqKNQ++yzT04//fScfvrpue666/KpT30qN9xwQ9uJu89+9rOZPHlyqqqqUl9f3+GTvQMGDMjhhx/+R/ufPXt21qxZ0+4Grdu2bcuiRYty4403pk+f//3iyde//vVcc801OfPMM/PP//zPOfnkkzv0N3LkyJ1eU/3t9Ww/yXjjjTd2OEm4Iw0NDdm8eXPWrl3bbhtNTU1t12lvaGjI008/3e5xTU1Nbeu6W8Oi57p9m++Ecfa/yhlnPdGj13y00iXsknH2vzozzn7961/n1FNPzZQpUzJz5sxd9g0AAABA19ntIKJ2YG1X1NGtjjnmmDz88MNtvw8dOnSnJ+Z2ZvXq1fne976X73znO+0uObJ169Z86EMfyo9//OOcccYZbctLpVK+8Y1vpE+fPjnrrLPywx/+sO3Gs+/UzJkzM3bs2EydOjXDhw/fadvjjz8+/fv3z2OPPZZJkyYlSZYsWZKXXnopY8aMSZKMGTMmN998c1auXJm6urokb31KuqamJsccc8xu1fpO9B0ypNu32RWMs52Ps55o/32790bsXcE42/U4e/755zN27Nhccsklufnmm3erPgAAAAA6b6++NNPq1atz/vnn59JLL83o0aNTXV2dZ555JrNmzco555xTdj9vvvlmh+uNl0ql1NfX59vf/naGDBmSj33sYx0+eXzWWWdl9uzZ7U7cbX/s1772tfTt27ft5N0pp5zStn7lypVpaWlp95ghQ4Z0uKTJdmPGjMno0aNzyy235Lbbbtvpc6mtrc1ll12Wq6++OoMHD05NTU2mT5+eMWPG5MQTT0ySjBs3Lsccc0wuvvjizJo1KytWrMjMmTMzbdq0DBw4cKf990bGWUfljLMkeeGFF7Jhw4asWLEib7zxRp577rkkb51cL/eGxb2FcdZROeNs8eLFGTt2bMaPH5+rr7667bn37ds3BxxwwE77BwAAAKBr7NVBRFVVVU444YTceuutWbp0abZs2ZLGxsZcfvnlufbaa8vu5/nnn8+wYcPaLRs4cGBaWlpy55135txzz93hjVonTZqUiy++OK+++mqHdaVSKbfffnv69OmTCRMm5JFH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SzMBvc6u5syXX345F110URYvXpyNGzemsbEx5557bmbOnJmamppurhZgzyeIAAAAAAAACuMeEQAAAAAAQGEEEQAAAAAAQGEEEQAAAAAAQGEEEQAAAAAAQGEEEQAAAAAAQGEEEQAAAAAAQGEEEQAAAAAAQGEEEQAAAAAAQGEEEQAAQDuTJ0/OxIkTK10GAACwl+hX6QIAAIDuUyqVdrr+hhtuyFe+8pW0trZ2U0UAAMDeThABAAC9yCuvvNL27/vvvz/XX399lixZ0rasqqoqVVVVlSgNAADYS7k0EwAA9CINDQ1tP7W1tSmVSu2WVVVVdbg00ymnnJLp06fnyiuvzP7775/6+vp885vfzMaNG/PJT34y1dXVOfzww/Poo4+229bixYtz5plnpqqqKvX19bn44ovz6quvdvMzBgAAKk0QAQAA7NI999yToUOH5umnn8706dMzderUnH/++TnppJPy7//+7xk3blwuvvjivP7660mStWvXZuzYsTnuuOPyzDPP5F/+5V/S1NSUj33sYxV+JgAAQHcTRAAAALv0vve9LzNnzswRRxyRz33uc9lnn30ydOjQXH755TniiCNy/fXXZ/Xq1Vm0aFGS5Lbbbstxxx2XW265JUcddVSOO+643HnnnZk3b17+67/+q8LPBgAA6E7uEQEAAOzS6NGj2/7dt2/fDBkyJKNGjWpbVl9fnyRZuXJlkuRXv/pV5s2bt8P7TSxdujTvfve7C64YAADoKQQRAADALvXv37/d76VSqd2yUqmUJNm2bVuSZMOGDTn77LPzpS99qUNfw4YNK7BSAACgpxFEAAAAXe79739/vvvd7+aQQw5Jv37+7AAAgN7MPSIAAIAuN23atKxZsyYf//jH84tf/CJLly7Nj370o3zyk5/M1q1bK10eAADQjQQRAABAlxs+fHh+/vOfZ+vWrRk3blxGjRqVK6+8Mvvtt1/69PFnCAAA9Cal1tbW1koXAQAAAAAA7J18FAkAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACiMIAIAAAAAACjM/wM8DotLF49/uQAAAABJRU5ErkJggg==\n"
+ },
+ "metadata": {},
+ "execution_count": 7
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# MRE\n",
+ "\n",
+ "Now that things are setup, edit the following cells with the piece of code allowing to reproduce the bug report.\n"
+ ],
+ "metadata": {
+ "id": "qHxFJZDxr5O1"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "from pyannote.audio import Model\n",
+ "model = Model.from_pretrained(\n",
+ " \"pyannote/speaker-diarization-3.1\",\n",
+ " use_auth_token=hf_token)"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 499
+ },
+ "id": "gVrDtBcusDbK",
+ "outputId": "25823c18-bff7-43b5-ef30-f5e8b2e43e2b"
+ },
+ "execution_count": 8,
+ "outputs": [
+ {
+ "output_type": "error",
+ "ename": "EntryNotFoundError",
+ "evalue": "404 Client Error. (Request ID: Root=1-659c1570-229842ad49cdd505022bd7b3;3b3426ec-0f8e-49a4-8783-f5740d92a8ed)\n\nEntry Not Found for url: https://huggingface.co/pyannote/speaker-diarization-3.1/resolve/main/pytorch_model.bin.",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mHTTPError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_errors.py\u001b[0m in \u001b[0;36mhf_raise_for_status\u001b[0;34m(response, endpoint_name)\u001b[0m\n\u001b[1;32m 285\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 286\u001b[0;31m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mraise_for_status\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 287\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mHTTPError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/requests/models.py\u001b[0m in \u001b[0;36mraise_for_status\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1020\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mhttp_error_msg\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1021\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mHTTPError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhttp_error_msg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1022\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mHTTPError\u001b[0m: 404 Client Error: Not Found for url: https://huggingface.co/pyannote/speaker-diarization-3.1/resolve/main/pytorch_model.bin",
+ "\nThe above exception was the direct cause of the following exception:\n",
+ "\u001b[0;31mEntryNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mpyannote\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maudio\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mModel\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m model = Model.from_pretrained(\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;34m\"pyannote/speaker-diarization-3.1\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m use_auth_token=hf_token)\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pyannote/audio/core/model.py\u001b[0m in \u001b[0;36mfrom_pretrained\u001b[0;34m(cls, checkpoint, map_location, hparams_file, strict, use_auth_token, cache_dir, **kwargs)\u001b[0m\n\u001b[1;32m 622\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 623\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 624\u001b[0;31m path_for_pl = hf_hub_download(\n\u001b[0m\u001b[1;32m 625\u001b[0m \u001b[0mmodel_id\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 626\u001b[0m \u001b[0mHF_PYTORCH_WEIGHTS_NAME\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_validators.py\u001b[0m in \u001b[0;36m_inner_fn\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 116\u001b[0m \u001b[0mkwargs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msmoothly_deprecate_use_auth_token\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhas_token\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mhas_token\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 118\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 119\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 120\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0m_inner_fn\u001b[0m \u001b[0;31m# type: ignore\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/file_download.py\u001b[0m in \u001b[0;36mhf_hub_download\u001b[0;34m(repo_id, filename, subfolder, repo_type, revision, library_name, library_version, cache_dir, local_dir, local_dir_use_symlinks, user_agent, force_download, force_filename, proxies, etag_timeout, resume_download, token, local_files_only, legacy_cache_layout, endpoint)\u001b[0m\n\u001b[1;32m 1236\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1237\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1238\u001b[0;31m metadata = get_hf_file_metadata(\n\u001b[0m\u001b[1;32m 1239\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1240\u001b[0m \u001b[0mtoken\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtoken\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_validators.py\u001b[0m in \u001b[0;36m_inner_fn\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 116\u001b[0m \u001b[0mkwargs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msmoothly_deprecate_use_auth_token\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhas_token\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mhas_token\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 118\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 119\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 120\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0m_inner_fn\u001b[0m \u001b[0;31m# type: ignore\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/file_download.py\u001b[0m in \u001b[0;36mget_hf_file_metadata\u001b[0;34m(url, token, proxies, timeout, library_name, library_version, user_agent)\u001b[0m\n\u001b[1;32m 1629\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1630\u001b[0m \u001b[0;31m# Retrieve metadata\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1631\u001b[0;31m r = _request_wrapper(\n\u001b[0m\u001b[1;32m 1632\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"HEAD\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1633\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/file_download.py\u001b[0m in \u001b[0;36m_request_wrapper\u001b[0;34m(method, url, follow_relative_redirects, **params)\u001b[0m\n\u001b[1;32m 383\u001b[0m \u001b[0;31m# Recursively follow relative redirects\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfollow_relative_redirects\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 385\u001b[0;31m response = _request_wrapper(\n\u001b[0m\u001b[1;32m 386\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 387\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/file_download.py\u001b[0m in \u001b[0;36m_request_wrapper\u001b[0;34m(method, url, follow_relative_redirects, **params)\u001b[0m\n\u001b[1;32m 407\u001b[0m \u001b[0;31m# Perform request and return if status_code is not in the retry list.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 408\u001b[0m \u001b[0mresponse\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_session\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 409\u001b[0;31m \u001b[0mhf_raise_for_status\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 410\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 411\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_errors.py\u001b[0m in \u001b[0;36mhf_raise_for_status\u001b[0;34m(response, endpoint_name)\u001b[0m\n\u001b[1;32m 294\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"EntryNotFound\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 295\u001b[0m \u001b[0mmessage\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34mf\"{response.status_code} Client Error.\"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"\\n\\n\"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34mf\"Entry Not Found for url: {response.url}.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 296\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mEntryNotFoundError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 297\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 298\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"GatedRepo\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mEntryNotFoundError\u001b[0m: 404 Client Error. (Request ID: Root=1-659c1570-229842ad49cdd505022bd7b3;3b3426ec-0f8e-49a4-8783-f5740d92a8ed)\n\nEntry Not Found for url: https://huggingface.co/pyannote/speaker-diarization-3.1/resolve/main/pytorch_model.bin."
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# this does not work because `pyannote/speaker-diarization-3.1` is a not a `Model`, it is a `Pipeline`."
+ ],
+ "metadata": {
+ "id": "e4GWU8Sbsy9u"
+ },
+ "execution_count": 9,
+ "outputs": []
+ }
+ ]
+}
diff --git a/tutorials/adapting_pretrained_pipeline.ipynb b/tutorials/adapting_pretrained_pipeline.ipynb
index 06d318809..ee749fd80 100644
--- a/tutorials/adapting_pretrained_pipeline.ipynb
+++ b/tutorials/adapting_pretrained_pipeline.ipynb
@@ -43,9 +43,7 @@
"id": "CZjbjOBBDrdm"
},
"source": [
- "## Installation\n",
- "\n",
- "Let's start by installing `pyannote.audio` 2.1.1 (and `rich` for pretty progress bars)."
+ "## Installation\n"
]
},
{
@@ -66,7 +64,7 @@
"id": "ndQ10VIf2W1c"
},
"source": [
- "⚠ Restart the runtime (Runtime > Restart runtime). \n",
+ "⚠ Restart the runtime (Runtime > Restart session). \n",
"If you don't, `pyannote.database` will throw an error below."
]
},
@@ -154,10 +152,10 @@
},
"outputs": [],
"source": [
- "import os\n",
- "os.environ[\"PYANNOTE_DATABASE_CONFIG\"] = \"/content/AMI-diarization-setup/pyannote/database.yml\"\n",
- "from pyannote.database import get_protocol, FileFinder\n",
- "dataset = get_protocol(\"AMI-SDM.SpeakerDiarization.mini\", {\"audio\": FileFinder()})"
+ "from pyannote.database import registry, FileFinder\n",
+ "\n",
+ "registry.load_database(\"AMI-diarization-setup/pyannote/database.yml\")\n",
+ "dataset = registry.get_protocol(\"AMI-SDM.SpeakerDiarization.mini\", {\"audio\": FileFinder()})"
]
},
{
@@ -344,7 +342,8 @@
" loss=\"bce\", \n",
" vad_loss=\"bce\")\n",
"model.task = task\n",
- "model.setup(stage=\"fit\")"
+ "model.prepare_data()\n",
+ "model.setup()"
]
},
{
diff --git a/tutorials/add_your_own_model.ipynb b/tutorials/add_your_own_model.ipynb
index 30020f8a9..487932588 100644
--- a/tutorials/add_your_own_model.ipynb
+++ b/tutorials/add_your_own_model.ipynb
@@ -1,284 +1 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Defining a custom model\n",
- "\n",
- "A collection of models is readily available in `pyannote.audio.models` but you will eventually want to try your own architecture. \n",
- "\n",
- "This tutorial explains how to define (and then use) your own model. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from typing import Optional\n",
- "import torch\n",
- "import torch.nn as nn\n",
- "from pyannote.audio import Model\n",
- "from pyannote.audio.core.task import Task, Resolution\n",
- "from torchaudio.transforms import MFCC\n",
- "\n",
- "# Your custom model must be a subclass of `pyannote.audio.Model`,\n",
- "# which is a subclass of `pytorch_lightning.LightningModule`, \n",
- "# which is a subclass of `torch.nn.Module`.\n",
- "class MyCustomModel(Model):\n",
- " \"\"\"My custom model\"\"\"\n",
- "\n",
- "\n",
- " def __init__(\n",
- " self,\n",
- " sample_rate: int = 16000, \n",
- " num_channels: int = 1, \n",
- " task: Optional[Task] = None,\n",
- " param1: int = 32,\n",
- " param2: int = 16,\n",
- " ):\n",
- "\n",
- " # First three parameters (sample_rate, num_channels, and task)\n",
- " # must be there and passed to super().__init__()\n",
- " super().__init__(sample_rate=sample_rate, \n",
- " num_channels=num_channels, \n",
- " task=task)\n",
- "\n",
- " # Mark param1 and param2 as hyper-parameters.\n",
- " self.save_hyperparameters(\"param1\", \"param2\")\n",
- "\n",
- " # They will be saved automatically into checkpoints.\n",
- " # They are now also available in self.hparams:\n",
- " # - param1 == self.hparams.param1\n",
- " # - param2 == self.hparams.param2\n",
- "\n",
- " # Layers that do not depend on the addressed task should be defined in '__init__'.\n",
- " self.mfcc = MFCC()\n",
- " self.linear1 = nn.Linear(self.mfcc.n_mfcc, self.hparams.param1)\n",
- " self.linear2 = nn.Linear(self.hparams.param1, self.hparams.param2)\n",
- "\n",
- " def build(self):\n",
- " # Add layers that depend on the specifications of the task addressed \n",
- " # by this model.\n",
- "\n",
- " # For instance, this simple model could be used for \"speech vs. non-speech\"\n",
- " # or \"speech vs. music vs. other\" classification and the only difference\n",
- " # would lie in the number of classes (2 or 3) in the final classifier.\n",
- " \n",
- " # Since task specifications are not available at the time '__init__' is called,\n",
- " # task-dependent layers can only be added a 'build' time (where task specifications\n",
- " # are available in 'specifications' attribute)\n",
- " \n",
- " num_classes = len(self.specifications.classes)\n",
- " self.classifier = nn.Linear(self.hparams.param2, num_classes)\n",
- "\n",
- " # 'specifications' has several attributes describing what the task is:\n",
- " # - classes: the list of classes\n",
- " # - problem: the type of machine learning problem (e.g. binary \n",
- " # classification or representation learning) \n",
- " # - duration: the duration of input audio chunks, in seconds\n",
- " # - resolution: the resolution of the output (e.g. frame-wise scores\n",
- " # for voice activity detection or chunk-wise vector for speaker \n",
- " # embedding)\n",
- " # - permutation_invariant : whether classes are permutation-invariant\n",
- " # (e.g. in the case of speaker diarization)\n",
- "\n",
- " # Depending on the type of 'problem', 'default_activation' can be used\n",
- " # to automatically guess what the final activation should be (e.g. softmax\n",
- " # for multi-class classification or sigmoid for multi-label classification).\n",
- " self.activation = self.default_activation()\n",
- "\n",
- " # You obviously do not _have_ to use 'default_activation' and can choose to\n",
- " # use any activation you see fit (or even not use any activation layer). But\n",
- " # note that pyannote.audio tasks also define default loss functions that are\n",
- " # consistent with `default_activation` (e.g. binary cross entropy with softmax\n",
- " # for binary classification tasks)\n",
- " \n",
- " def forward(self, waveforms: torch.Tensor) -> torch.Tensor:\n",
- "\n",
- " # Models are expected to work on batches of audio chunks provided as tensors\n",
- " # with shape (batch_size, num_channels, num_samples) and using the sample rate \n",
- " # passed to __init__. Resampling will be done automatically for you so you do \n",
- " # not have to bother about that when preparing the data.\n",
- "\n",
- " # Extract sequence of MFCCs and passed them through two linear layers\n",
- " mfcc = self.mfcc(waveforms).squeeze(dim=1).transpose(1, 2)\n",
- " output = self.linear1(mfcc)\n",
- " output = self.linear2(output)\n",
- "\n",
- " # Apply temporal pooling for tasks which need an output at chunk-level. \n",
- " if self.specifications.resolution == Resolution.CHUNK:\n",
- " output = torch.mean(output, dim=-1)\n",
- " # Keep 'mfcc' frame resolution for frame-level tasks.\n",
- " elif self.specifications.resolution == Resolution.FRAME:\n",
- " pass\n",
- " \n",
- " # Apply final classifier and activation function\n",
- " output = self.classifier(output)\n",
- " return self.activation(output) "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Using your model with `pyannote.audio` API \n",
- "\n",
- "Your model can now be used like any other builtin model."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# initialize your experimental protocol\n",
- "from pyannote.database import get_protocol\n",
- "protocol = get_protocol('Debug.SpeakerDiarization.Debug')\n",
- "\n",
- "# initialize the task you want to address\n",
- "from pyannote.audio.tasks import VoiceActivityDetection\n",
- "task = VoiceActivityDetection(protocol)\n",
- "\n",
- "# initialize the model\n",
- "model = MyCustomModel(task=task)\n",
- "\n",
- "# train the model\n",
- "from pytorch_lightning import Trainer\n",
- "trainer = Trainer(max_epochs=1)\n",
- "trainer.fit(model)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Using your model with `pyannote-audio-train` CLI\n",
- "\n",
- "1. Define your model in a proper Python package:\n",
- "\n",
- "```\n",
- "/your/favorite/directory/\n",
- " your_package_name/\n",
- " __init__.py # needs to be here but can be empty\n",
- " custom_model.py # contains the above definition of your model \n",
- "```\n",
- "\n",
- "2. Add the package to your `PYTHONPATH`:\n",
- "\n",
- "```bash\n",
- "$ export PYTHONPATH=/your/favorite/directory\n",
- "```\n",
- "\n",
- "3. Check that you can import it from Python:\n",
- "\n",
- "```python\n",
- ">>> from your_package_name.custom_model import MyCustomModel\n",
- "```\n",
- "\n",
- "4. Tell `Hydra` (on which `pyannote-audio-train` is based) about this new model:\n",
- "\n",
- "```\n",
- "/your/favorite/directory/\n",
- " custom_config/\n",
- " model/\n",
- " MyCustomModel.yaml\n",
- "```\n",
- "\n",
- "where the content of `MyCustomModel.yaml` is as follows:\n",
- "\n",
- "```yaml\n",
- "# @package _group_\n",
- "_target_: your_package_name.custom_model.MyCustomModel\n",
- "param1: 32\n",
- "param2: 16\n",
- "```\n",
- "\n",
- "5. Enjoy\n",
- "\n",
- "```bash\n",
- "$ pyannote-audio-train --config-dir=/your/favorite/directory/custom_config \\\n",
- " protocol=Debug.SpeakerDiarization.Debug \\\n",
- " task=VoiceActivityDetection \\\n",
- " model=MyCustomModel \\\n",
- " model.param2=12 \n",
- "```"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Contributing your model to `pyannote-audio` \n",
- "\n",
- "1. Add your model in `pyannote.audio.models`.\n",
- "\n",
- "```\n",
- "pyannote/\n",
- " audio/\n",
- " models/\n",
- " custom_model.py \n",
- "```\n",
- "\n",
- "2. Check that you can import it from Python:\n",
- "\n",
- "```python\n",
- ">>> from pyannote.audio.models.custom_model import MyCustomModel\n",
- "```\n",
- "\n",
- "3. Add the corresponding `Hydra` configuration file:\n",
- "\n",
- "```\n",
- "pyannote/\n",
- " audio/\n",
- " cli/\n",
- " train_config/\n",
- " model/\n",
- " MyCustomModel.yaml\n",
- "```\n",
- "\n",
- "where the content of `MyCustomModel.yaml` is as follows:\n",
- "\n",
- "```yaml\n",
- "# @package _group_\n",
- "_target_: pyannote.audio.models.custom_model.MyCustomModel\n",
- "param1: 32\n",
- "param2: 16\n",
- "```\n",
- "\n",
- "4. Enjoy\n",
- "\n",
- "```bash\n",
- "$ pyannote-audio-train protocol=Debug.SpeakerDiarization.Debug \\\n",
- " task=VoiceActivityDetection \\\n",
- " model=MyCustomModel \\\n",
- " model.param2=12 \n",
- "```"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "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.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
+{"cells":[{"cell_type":"markdown","metadata":{"id":"kY1p-wCLHw92"},"source":["# Add your own model"]},{"cell_type":"markdown","metadata":{"id":"iD_DNGmmHs9v"},"source":[""]},{"cell_type":"markdown","metadata":{"id":"hhBTSvk6H_JC"},"source":["## Tutorial setup"]},{"cell_type":"markdown","metadata":{"id":"r-ocA5Z8PqNl"},"source":["### `Google Colab` setup"]},{"cell_type":"markdown","metadata":{"id":"I7lc6ctfIBv-"},"source":["If you are running this tutorial on `Colab`, execute the following commands in order to setup `Colab` environment. These commands will install `pyannote.audio` and download a mini version of the `AMI` corpus."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"l07Xq_UAIUFE"},"outputs":[],"source":["!pip install -qq pyannote.audio==3.1.1\n","!pip install -qq ipython==7.34.0\n","!git clone https://github.com/pyannote/AMI-diarization-setup.git\n","%cd ./AMI-diarization-setup/pyannote/\n","!bash ./download_ami_mini.sh\n","%cd /content"]},{"cell_type":"markdown","metadata":{"id":"3rjw5hATOv_c"},"source":["⚠ Restart the runtime (Runtime > Restart session)."]},{"cell_type":"markdown","metadata":{},"source":["### Non `Google Colab` setup"]},{"cell_type":"markdown","metadata":{"id":"VdMVQD-9QAto"},"source":["If you are not using `Colab`, this tutorial assumes that\n","* `pyannote.audio` has been installed\n","* the [AMI corpus](https://groups.inf.ed.ac.uk/ami/corpus/) has already been [setup for use with `pyannote`](https://github.com/pyannote/AMI-diarization-setup/tree/main/pyannote)"]},{"cell_type":"markdown","metadata":{"id":"kuemd4PWHeqh"},"source":["## Defining a custom model\n","\n","A collection of models is readily available in `pyannote.audio.models` but you will eventually want to try your own architecture.\n","\n","This tutorial explains how to define (and then use) your own model. "]},{"cell_type":"code","execution_count":18,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":12960,"status":"ok","timestamp":1704802939163,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"kNwQfnTOHeqm","outputId":"5f71bde3-5f13-4431-918f-6e1ca3ddd518"},"outputs":[],"source":["from typing import Optional\n","import torch\n","import torch.nn as nn\n","from pyannote.audio import Model\n","from pyannote.core import SlidingWindow\n","from pyannote.audio.core.task import Task, Resolution\n","from torchaudio.transforms import MFCC\n","\n","# Your custom model must be a subclass of `pyannote.audio.Model`,\n","# which is a subclass of `pytorch_lightning.LightningModule`,\n","# which is a subclass of `torch.nn.Module`.\n","class MyCustomModel(Model):\n"," \"\"\"My custom model\"\"\"\n","\n","\n"," def __init__(\n"," self,\n"," sample_rate: int = 16000,\n"," num_channels: int = 1,\n"," task: Optional[Task] = None,\n"," param1: int = 32,\n"," param2: int = 16,\n"," ):\n","\n"," # First three parameters (sample_rate, num_channels, and task)\n"," # must be there and passed to super().__init__()\n"," super().__init__(sample_rate=sample_rate,\n"," num_channels=num_channels,\n"," task=task)\n","\n"," # Mark param1 and param2 as hyper-parameters.\n"," self.save_hyperparameters(\"param1\", \"param2\")\n","\n"," # They will be saved automatically into checkpoints.\n"," # They are now also available in self.hparams:\n"," # - param1 == self.hparams.param1\n"," # - param2 == self.hparams.param2\n","\n"," # Layers that do not depend on the addressed task should be defined in '__init__'.\n"," self.mfcc = MFCC()\n"," self.linear1 = nn.Linear(self.mfcc.n_mfcc, self.hparams.param1)\n"," self.linear2 = nn.Linear(self.hparams.param1, self.hparams.param2)\n","\n"," def num_frames(self, num_samples: int) -> int:\n"," # Compute number of output frames for a given number of input samples\n"," hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length\n"," n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft\n"," center = self.mfcc.MelSpectrogram.spectrogram.center\n"," return (\n"," 1 + num_samples // hop_length\n"," if center\n"," else 1 + (num_samples - n_fft) // hop_length\n"," )\n","\n"," def receptive_field_size(self, num_frames: int = 1) -> int:\n"," # Compute receptive field size\n"," hop_length = self.mfcc.MelSpectrogram.spectrogram.hop_length\n"," n_fft = self.mfcc.MelSpectrogram.spectrogram.n_fft\n"," center = self.mfcc.MelSpectrogram.spectrogram.center\n","\n"," if center:\n"," return (num_frames - 1) * hop_length\n"," else:\n"," return (num_frames - 1) * hop_length + n_fft\n","\n"," def receptive_field(self) -> SlidingWindow:\n"," # Compute receptive field\n","\n"," # duration of the receptive field of each output frame\n"," duration = (\n"," self.mfcc.MelSpectrogram.spectrogram.win_length / self.hparams.sample_rate\n"," )\n","\n"," # step between the receptive field region of two consecutive output frames\n"," step = (\n"," self.mfcc.MelSpectrogram.spectrogram.hop_length / self.hparams.sample_rate\n"," )\n","\n"," return SlidingWindow(start=0.0, duration=duration, step=step)\n","\n"," def build(self):\n"," # Add layers that depend on the specifications of the task addressed\n"," # by this model.\n","\n"," # For instance, this simple model could be used for \"speech vs. non-speech\"\n"," # or \"speech vs. music vs. other\" classification and the only difference\n"," # would lie in the number of classes (2 or 3) in the final classifier.\n","\n"," # Since task specifications are not available at the time '__init__' is called,\n"," # task-dependent layers can only be added a 'build' time (where task specifications\n"," # are available in 'specifications' attribute)\n","\n"," num_classes = len(self.specifications.classes)\n"," self.classifier = nn.Linear(self.hparams.param2, num_classes)\n","\n"," # 'specifications' has several attributes describing what the task is:\n"," # - classes: the list of classes\n"," # - problem: the type of machine learning problem (e.g. binary\n"," # classification or representation learning)\n"," # - duration: the duration of input audio chunks, in seconds\n"," # - resolution: the resolution of the output (e.g. frame-wise scores\n"," # for voice activity detection or chunk-wise vector for speaker\n"," # embedding)\n"," # - permutation_invariant : whether classes are permutation-invariant\n"," # (e.g. in the case of speaker diarization)\n","\n"," # Depending on the type of 'problem', 'default_activation' can be used\n"," # to automatically guess what the final activation should be (e.g. softmax\n"," # for multi-class classification or sigmoid for multi-label classification).\n"," self.activation = self.default_activation()\n","\n"," # You obviously do not _have_ to use 'default_activation' and can choose to\n"," # use any activation you see fit (or even not use any activation layer). But\n"," # note that pyannote.audio tasks also define default loss functions that are\n"," # consistent with `default_activation` (e.g. binary cross entropy with softmax\n"," # for binary classification tasks)\n","\n"," def forward(self, waveforms: torch.Tensor) -> torch.Tensor:\n","\n"," # Models are expected to work on batches of audio chunks provided as tensors\n"," # with shape (batch_size, num_channels, num_samples) and using the sample rate\n"," # passed to __init__. Resampling will be done automatically for you so you do\n"," # not have to bother about that when preparing the data.\n","\n"," # Extract sequence of MFCCs and passed them through two linear layers\n"," mfcc = self.mfcc(waveforms).squeeze(dim=1).transpose(1, 2)\n"," output = self.linear1(mfcc)\n"," output = self.linear2(output)\n","\n"," # Apply temporal pooling for tasks which need an output at chunk-level.\n"," if self.specifications.resolution == Resolution.CHUNK:\n"," output = torch.mean(output, dim=-1)\n"," # Keep 'mfcc' frame resolution for frame-level tasks.\n"," elif self.specifications.resolution == Resolution.FRAME:\n"," pass\n","\n"," # Apply final classifier and activation function\n"," output = self.classifier(output)\n"," return self.activation(output)"]},{"cell_type":"markdown","metadata":{"id":"BuieqViJHeqp"},"source":["## Using your model with `pyannote.audio` API\n","\n","Your model can now be used like any other builtin model."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"qwTjuGuvHeqr"},"outputs":[],"source":["# initialize your experimental protocol\n","from pyannote.database import registry, FileFinder\n","\n","registry.load_database(\"./AMI-diarization-setup/pyannote/database.yml\")\n","protocol = registry.get_protocol('AMI.SpeakerDiarization.mini', preprocessors={\"audio\": FileFinder()})\n","\n","# initialize the task you want to address\n","from pyannote.audio.tasks import VoiceActivityDetection\n","task = VoiceActivityDetection(protocol)\n","\n","# initialize the model\n","model = MyCustomModel(task=task)\n","\n","# train the model\n","from pytorch_lightning import Trainer\n","trainer = Trainer(max_epochs=1)\n","trainer.fit(model)"]},{"cell_type":"markdown","metadata":{"id":"4qidmGQyHeqt"},"source":["## Using your model with `pyannote-audio-train` CLI\n","\n","1. Define your model in a proper Python package:\n","\n","```\n","/your/favorite/directory/\n"," your_package_name/\n"," __init__.py # needs to be here but can be empty\n"," custom_model.py # contains the above definition of your model\n","```\n","\n","2. Add the package to your `PYTHONPATH`:\n","\n","```bash\n","$ export PYTHONPATH=/your/favorite/directory\n","```\n","\n","3. Check that you can import it from Python:\n","\n","```python\n",">>> from your_package_name.custom_model import MyCustomModel\n","```\n","\n","4. Tell `Hydra` (on which `pyannote-audio-train` is based) about this new model:\n","\n","```\n","/your/favorite/directory/\n"," custom_config/\n"," model/\n"," MyCustomModel.yaml\n","```\n","\n","where the content of `MyCustomModel.yaml` is as follows:\n","\n","```yaml\n","# @package _group_\n","_target_: your_package_name.custom_model.MyCustomModel\n","param1: 32\n","param2: 16\n","```\n","\n","5. Enjoy\n","\n","```bash\n","$ pyannote-audio-train --config-dir=/your/favorite/directory/custom_config \\\n"," protocol=Debug.SpeakerDiarization.Debug \\\n"," task=VoiceActivityDetection \\\n"," model=MyCustomModel \\\n"," model.param2=12\n","```"]},{"cell_type":"markdown","metadata":{"id":"8W2UT1IpHequ"},"source":["## Contributing your model to `pyannote-audio`\n","\n","1. Add your model in `pyannote.audio.models`.\n","\n","```\n","pyannote/\n"," audio/\n"," models/\n"," custom_model.py \n","```\n","\n","2. Check that you can import it from Python:\n","\n","```python\n",">>> from pyannote.audio.models.custom_model import MyCustomModel\n","```\n","\n","3. Add the corresponding `Hydra` configuration file:\n","\n","```\n","pyannote/\n"," audio/\n"," cli/\n"," train_config/\n"," model/\n"," MyCustomModel.yaml\n","```\n","\n","where the content of `MyCustomModel.yaml` is as follows:\n","\n","```yaml\n","# @package _group_\n","_target_: pyannote.audio.models.custom_model.MyCustomModel\n","param1: 32\n","param2: 16\n","```\n","\n","4. Enjoy\n","\n","```bash\n","$ pyannote-audio-train protocol=Debug.SpeakerDiarization.Debug \\\n"," task=VoiceActivityDetection \\\n"," model=MyCustomModel \\\n"," model.param2=12\n","```"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"T4","provenance":[]},"kernelspec":{"display_name":"Python 3","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.13"}},"nbformat":4,"nbformat_minor":0}
diff --git a/tutorials/add_your_own_task.ipynb b/tutorials/add_your_own_task.ipynb
index 251846957..b572e3d28 100644
--- a/tutorials/add_your_own_task.ipynb
+++ b/tutorials/add_your_own_task.ipynb
@@ -1,350 +1 @@
-{
- "cells": [
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Defining a custom task\n",
- "\n",
- "In `pyannote.audio`, a *task* is a combination of a **_problem_** that needs to be addressed and an **experimental protocol**.\n",
- "\n",
- "For example, one can address **_voice activity detection_** following the **AMI only_words** experimental protocol, by instantiating the following *task*:\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# this assumes that the AMI corpus has been setup for diarization\n",
- "# according to https://github.com/pyannote/AMI-diarization-setup\n",
- "import os\n",
- "os.environ['PYANNOTE_DATABASE_CONFIG'] = '/Users/bredin/Development/pyannote/pyannote-db/AMI-diarization-setup/pyannote/database.yml'\n",
- "\n",
- "from pyannote.database import get_protocol, FileFinder\n",
- "ami = get_protocol('AMI.SpeakerDiarization.only_words', \n",
- " preprocessors={'audio': FileFinder()})\n",
- "\n",
- "# address voice activity detection\n",
- "from pyannote.audio.tasks import VoiceActivityDetection\n",
- "task = VoiceActivityDetection(ami)"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A growing collection of tasks is readily available in `pyannote.audio.tasks`..."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from pyannote.audio.tasks import __all__ as TASKS; print('\\n'.join(TASKS))"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "... but you will eventually want to use `pyannote.audio` to address a different task. \n",
- "In this example, we will add a new task addressing the **sound event detection** problem.\n",
- "\n"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Problem specification\n",
- "\n",
- "A problem is expected to be solved by a model $f$ that takes an audio chunk $X$ as input and returns its predicted solution $\\hat{y} = f(X)$. \n",
- "\n",
- "### Resolution\n",
- "\n",
- "Depending on the addressed problem, you might expect the model to output just one prediction for the whole audio chunk (`Resolution.CHUNK`) or a temporal sequence of predictions (`Resolution.FRAME`).\n",
- "\n",
- "In our particular case, we would like the model to provide one decision for the whole chunk:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from pyannote.audio.core.task import Resolution\n",
- "resolution = Resolution.CHUNK"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Type of problem\n",
- "\n",
- "Similarly, the type of your problem may fall into one of these generic machine learning categories:\n",
- "* `Problem.BINARY_CLASSIFICATION` for binary classification\n",
- "* `Problem.MONO_LABEL_CLASSIFICATION` for multi-class classification \n",
- "* `Problem.MULTI_LABEL_CLASSIFICATION` for multi-label classification\n",
- "* `Problem.REGRESSION` for regression\n",
- "* `Problem.REPRESENTATION` for representation learning\n",
- "\n",
- "In our particular case, we would like the model to do multi-label classification because one audio chunk may contain multiple sound events:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from pyannote.audio.core.task import Problem\n",
- "problem = Problem.MULTI_LABEL_CLASSIFICATION"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from pyannote.audio.core.task import Specifications\n",
- "specifications = Specifications(\n",
- " problem=problem,\n",
- " resolution=resolution,\n",
- " duration=5.0,\n",
- " classes=[\"Speech\", \"Dog\", \"Cat\", \"Alarm_bell_ringing\", \"Dishes\", \n",
- " \"Frying\", \"Blender\", \"Running_water\", \"Vacuum_cleaner\", \n",
- " \"Electric_shaver_toothbrush\"],\n",
- ")"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A task is expected to be solved by a model $f$ that (usually) takes an audio chunk $X$ as input and returns its predicted solution $\\hat{y} = f(X)$. \n",
- "\n",
- "To help training the model $f$, the task $\\mathcal{T}$ is in charge of \n",
- "- generating $(X, y)$ training samples using the **dataset**\n",
- "- defining the loss function $\\mathcal{L}(y, \\hat{y})$\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from typing import Optional\n",
- "import torch\n",
- "import torch.nn as nn\n",
- "import numpy as np\n",
- "from pyannote.core import Annotation\n",
- "from pyannote.audio import Model\n",
- "from pyannote.audio.core.task import Task, Resolution\n",
- "\n",
- "# Your custom task must be a subclass of `pyannote.audio.core.task.Task`\n",
- "class SoundEventDetection(Task):\n",
- " \"\"\"Sound event detection\"\"\"\n",
- "\n",
- " def __init__(\n",
- " self,\n",
- " protocol: Protocol,\n",
- " duration: float = 5.0,\n",
- " warm_up: Union[float, Tuple[float, float]] = 0.0,\n",
- " batch_size: int = 32,\n",
- " num_workers: int = None,\n",
- " pin_memory: bool = False,\n",
- " augmentation: BaseWaveformTransform = None,\n",
- " **other_params,\n",
- " ):\n",
- "\n",
- " super().__init__(\n",
- " protocol,\n",
- " duration=duration,\n",
- " min_duration=min_duration,\n",
- " warm_up=warm_up,\n",
- " batch_size=batch_size,\n",
- " num_workers=num_workers,\n",
- " pin_memory=pin_memory,\n",
- " augmentation=augmentation,\n",
- " )\n",
- "\n",
- " def setup(self):\n",
- "\n",
- " # load metadata for training subset\n",
- " self.train_metadata_ = list()\n",
- " for training_file in self.protocol.train():\n",
- " self.training_metadata_.append({\n",
- " # path to audio file (str)\n",
- " \"audio\": training_file[\"audio\"],\n",
- " # duration of audio file (float)\n",
- " \"duration\": training_file[\"duration\"],\n",
- " # reference annotation (pyannote.core.Annotation)\n",
- " \"annotation\": training_file[\"annotation\"],\n",
- " })\n",
- "\n",
- " # gather the list of classes\n",
- " classes = set()\n",
- " for training_file in self.train_metadata_:\n",
- " classes.update(training_file[\"reference\"].labels())\n",
- " classes = sorted(classes)\n",
- "\n",
- " # specify the addressed problem\n",
- " self.specifications = Specifications(\n",
- " # it is a multi-label classification problem\n",
- " problem=Problem.MULTI_LABEL_CLASSIFICATION,\n",
- " # we expect the model to output one prediction \n",
- " # for the whole chunk\n",
- " resolution=Resolution.CHUNK,\n",
- " # the model will ingest chunks with that duration (in seconds)\n",
- " duration=self.duration,\n",
- " # human-readable names of classes\n",
- " classes=classes)\n",
- "\n",
- " # `has_validation` is True iff protocol defines a development set\n",
- " if not self.has_validation:\n",
- " return\n",
- "\n",
- " # load metadata for validation subset\n",
- " self.validation_metadata_ = list()\n",
- " for validation_file in self.protocol.development():\n",
- " self.validation_metadata_.append({\n",
- " \"audio\": validation_file[\"audio\"],\n",
- " \"num_samples\": math.floor(validation_file[\"duration\"] / self.duration),\n",
- " \"annotation\": validation_file[\"annotation\"],\n",
- " })\n",
- " \n",
- " \n",
- "\n",
- " def train__iter__(self):\n",
- " # this method generates training samples, one at a time, \"ad infinitum\". each worker \n",
- " # of the dataloader will run it, independently from other workers. pyannote.audio and\n",
- " # pytorch-lightning will take care of making batches out of it.\n",
- "\n",
- " # create worker-specific random number generator (RNG) to avoid this common bug:\n",
- " # tanelp.github.io/posts/a-bug-that-plagues-thousands-of-open-source-ml-projects/\n",
- " rng = create_rng_for_worker(self.model.current_epoch)\n",
- "\n",
- " # load list and number of classes\n",
- " classes = self.specifications.classes\n",
- " num_classes = len(classes)\n",
- "\n",
- " # yield training samples \"ad infinitum\"\n",
- " while True:\n",
- "\n",
- " # select training file at random\n",
- " random_training_file, *_ = rng.choices(self.train_metadata_, k=1)\n",
- "\n",
- " # select one chunk at random \n",
- " random_start_time = rng.uniform(0, random_training_file[\"duration\"] - self.duration)\n",
- " random_chunk = Segment(random_start_time, random_start_time + self.duration)\n",
- "\n",
- " # load audio excerpt corresponding to random chunk\n",
- " X = self.model.audio.crop(random_training_file[\"audio\"], \n",
- " random_chunk, \n",
- " fixed=self.duration)\n",
- " \n",
- " # load labels corresponding to random chunk as {0|1} numpy array\n",
- " # y[k] = 1 means that kth class is active\n",
- " y = np.zeros((num_classes,))\n",
- " active_classes = random_training_file[\"annotation\"].crop(random_chunk).labels()\n",
- " for active_class in active_classes:\n",
- " y[classes.index(active_class)] = 1\n",
- " \n",
- " # yield training samples as a dict (use 'X' for input and 'y' for target)\n",
- " yield {'X': X, 'y': y}\n",
- "\n",
- " def train__len__(self):\n",
- " # since train__iter__ runs \"ad infinitum\", we need a way to define what an epoch is.\n",
- " # this is the purpose of this method. it outputs the number of training samples that\n",
- " # make an epoch.\n",
- "\n",
- " # we compute this number as the total duration of the training set divided by \n",
- " # duration of training chunks. we make sure that an epoch is at least one batch long,\n",
- " # or pytorch-lightning will complain\n",
- " train_duration = sum(training_file[\"duration\"] for training_file in self.train_metadata_)\n",
- " return max(self.batch_size, math.ceil(train_duration / self.duration))\n",
- "\n",
- " def val__getitem__(self, sample_idx):\n",
- "\n",
- " # load list and number of classes\n",
- " classes = self.specifications.classes\n",
- " num_classes = len(classes)\n",
- "\n",
- "\n",
- " # find which part of the validation set corresponds to sample_idx\n",
- " num_samples = np.cumsum([\n",
- " validation_file[\"num_samples\"] for validation_file in self.validation_metadata_])\n",
- " file_idx = np.where(num_samples < sample_idx)[0][0]\n",
- " validation_file = self.validation_metadata_[file_idx]\n",
- " idx = sample_idx - (num_samples[file_idx] - validation_file[\"num_samples\"]) \n",
- " chunk = SlidingWindow(start=0., duration=self.duration, step=self.duration)[idx]\n",
- "\n",
- " # load audio excerpt corresponding to current chunk\n",
- " X = self.model.audio.crop(validation_file[\"audio\"], chunk, fixed=self.duration)\n",
- "\n",
- " # load labels corresponding to random chunk as {0|1} numpy array\n",
- " # y[k] = 1 means that kth class is active\n",
- " y = np.zeros((num_classes,))\n",
- " active_classes = validaiton_file[\"annotation\"].crop(chunk).labels()\n",
- " for active_class in active_classes:\n",
- " y[classes.index(active_class)] = 1\n",
- "\n",
- " return {'X': X, 'y': y}\n",
- "\n",
- " def val__len__(self):\n",
- " return sum(validation_file[\"num_samples\"] \n",
- " for validation_file in self.validation_metadata_)\n",
- "\n",
- " # `pyannote.audio.core.task.Task` base class provides a `LightningModule.training_step` and \n",
- " # `LightningModule.validation_step` methods that rely on self.specifications to guess which \n",
- " # loss and metrics should be used. you can obviously choose to customize them. \n",
- " # More details can be found in pytorch-lightning documentation and in \n",
- " # pyannote.audio.core.task.Task source code. \n",
- "\n",
- " # def training_step(self, batch, batch_idx: int):\n",
- " # return loss\n",
- "\n",
- " # def validation_step(self, batch, batch_idx: int):\n",
- " # return metric\n",
- "\n",
- " # pyannote.audio.tasks.segmentation.mixin also provides a convenient mixin\n",
- " # for \"segmentation\" tasks (ie. with Resolution.FRAME) that already defines\n",
- " # a bunch of useful methods. \n"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3.8.5 64-bit ('pyannote-audio-v2': conda)",
- "name": "python385jvsc74a57bd0af55542e943232842f746a64555e4e006c72c98a3a863e85e6cbaf12772fa219"
- },
- "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.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
+{"cells":[{"cell_type":"markdown","metadata":{"id":"W7BMj2EZlWqU"},"source":[""]},{"cell_type":"markdown","metadata":{"id":"HG6OvaE4lWqZ"},"source":["# Defining a custom task"]},{"cell_type":"markdown","metadata":{"id":"c6LwrLYVlWqZ"},"source":["## Tutorial setup"]},{"cell_type":"markdown","metadata":{"id":"6lR9bgJBlWqb"},"source":["### `Google Colab` setup"]},{"cell_type":"markdown","metadata":{},"source":["If you are running this tutorial on `Colab`, execute the following commands in order to setup `Colab` environment. These commands will install `pyannote.audio` and download a mini version of the `AMI` corpus."]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":127254,"status":"ok","timestamp":1704809957597,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"6LoOS-PjlWqd","outputId":"cd92e2d4-83cc-4bb0-ad5c-824cb2ca11ac"},"outputs":[],"source":["!pip install -qq pyannote.audio==3.1.1\n","!pip install -qq ipython==7.34.0\n","!git clone https://github.com/pyannote/AMI-diarization-setup.git\n","%cd ./AMI-diarization-setup/pyannote/\n","!bash ./download_ami_mini.sh\n","%cd /content"]},{"cell_type":"markdown","metadata":{"id":"LsZTSX-ulWqf"},"source":["⚠ Restart the runtime (Runtime > Restart session)."]},{"cell_type":"markdown","metadata":{"id":"904hVjv8lWqg"},"source":["### Non `Google Colab` setup"]},{"cell_type":"markdown","metadata":{"id":"serWAfFxlWqh"},"source":["If you are not using `Colab`, this tutorial assumes that\n","* `pyannote.audio` has been installed\n","* the [AMI corpus](https://groups.inf.ed.ac.uk/ami/corpus/) has already been [setup for use with `pyannote`](https://github.com/pyannote/AMI-diarization-setup/tree/main/pyannote)"]},{"cell_type":"markdown","metadata":{"id":"uWyNce9FlkA3"},"source":["## Task in `pyannote.audio`"]},{"cell_type":"markdown","metadata":{"id":"BK4hbdq6lWqj"},"source":["\n","In `pyannote.audio`, a *task* is a combination of a **_problem_** that needs to be addressed and an **experimental protocol**.\n","\n","For example, one can address **_voice activity detection_** following the **AMI only_words** experimental protocol, by instantiating the following *task*:\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"-4B8nLDmlWql"},"outputs":[],"source":["# this assumes that the AMI corpus has been setup for diarization\n","# according to https://github.com/pyannote/AMI-diarization-setup\n","\n","from pyannote.database import registry, FileFinder\n","registry.load_database(\"AMI-diarization-setup/pyannote/database.yml\")\n","ami = registry.get_protocol('AMI.SpeakerDiarization.mini',\n"," preprocessors={'audio': FileFinder()})\n","\n","# address voice activity detection\n","from pyannote.audio.tasks import VoiceActivityDetection\n","task = VoiceActivityDetection(ami)"]},{"cell_type":"markdown","metadata":{"id":"A9nxwDQGlWqn"},"source":["A growing collection of tasks is readily available in `pyannote.audio.tasks`..."]},{"cell_type":"code","execution_count":2,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":232,"status":"ok","timestamp":1704810010556,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"qbbDA2P5lWqp","outputId":"bf1988fb-9140-4d6a-8a2c-970578331f35"},"outputs":[{"name":"stdout","output_type":"stream","text":["SpeakerDiarization\n","VoiceActivityDetection\n","OverlappedSpeechDetection\n","MultiLabelSegmentation\n","SpeakerEmbedding\n","Segmentation\n"]}],"source":["from pyannote.audio.tasks import __all__ as TASKS; print('\\n'.join(TASKS))"]},{"cell_type":"markdown","metadata":{"id":"hihPu4iElWqr"},"source":["... but you will eventually want to use `pyannote.audio` to address a different task. \n","In this example, we will add a new task addressing the **sound event detection** problem.\n","\n"]},{"cell_type":"markdown","metadata":{"id":"RZOs3C4HlWqr"},"source":["## Problem specification\n","\n","A problem is expected to be solved by a model $f$ that takes an audio chunk $X$ as input and returns its predicted solution $\\hat{y} = f(X)$.\n","\n","### Resolution\n","\n","Depending on the addressed problem, you might expect the model to output just one prediction for the whole audio chunk (`Resolution.CHUNK`) or a temporal sequence of predictions (`Resolution.FRAME`).\n","\n","In our particular case, we would like the model to provide one decision for the whole chunk:"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":234,"status":"ok","timestamp":1704810016464,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"G96Mz8vPlWqs"},"outputs":[],"source":["from pyannote.audio.core.task import Resolution\n","resolution = Resolution.CHUNK"]},{"cell_type":"markdown","metadata":{"id":"_Efd28eclWqt"},"source":["### Type of problem\n","\n","Similarly, the type of your problem may fall into one of these generic machine learning categories:\n","* `Problem.BINARY_CLASSIFICATION` for binary classification\n","* `Problem.MONO_LABEL_CLASSIFICATION` for multi-class classification\n","* `Problem.MULTI_LABEL_CLASSIFICATION` for multi-label classification\n","* `Problem.REGRESSION` for regression\n","* `Problem.REPRESENTATION` for representation learning\n","\n","In our particular case, we would like the model to do multi-label classification because one audio chunk may contain multiple sound events:"]},{"cell_type":"code","execution_count":4,"metadata":{"executionInfo":{"elapsed":315,"status":"ok","timestamp":1704810020230,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"Cl0VqB5jlWqu"},"outputs":[],"source":["from pyannote.audio.core.task import Problem\n","problem = Problem.MULTI_LABEL_CLASSIFICATION"]},{"cell_type":"code","execution_count":5,"metadata":{"executionInfo":{"elapsed":251,"status":"ok","timestamp":1704810021646,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"Hz_B7FCplWqv"},"outputs":[],"source":["from pyannote.audio.core.task import Specifications\n","specifications = Specifications(\n"," problem=problem,\n"," resolution=resolution,\n"," duration=5.0,\n"," classes=[\"Speech\", \"Dog\", \"Cat\", \"Alarm_bell_ringing\", \"Dishes\",\n"," \"Frying\", \"Blender\", \"Running_water\", \"Vacuum_cleaner\",\n"," \"Electric_shaver_toothbrush\"],\n",")"]},{"cell_type":"markdown","metadata":{"id":"5N72ksU7lWqv"},"source":["A task is expected to be solved by a model $f$ that (usually) takes an audio chunk $X$ as input and returns its predicted solution $\\hat{y} = f(X)$.\n","\n","To help training the model $f$, the task $\\mathcal{T}$ is in charge of\n","- generating $(X, y)$ training samples using the **dataset**\n","- defining the loss function $\\mathcal{L}(y, \\hat{y})$\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"lrTD1RwUlWqw"},"outputs":[],"source":["from math import ceil\n","from typing import Dict, Optional,Tuple, Union\n","import numpy as np\n","from pyannote.core import Segment, SlidingWindow\n","from pyannote.audio.utils.random import create_rng_for_worker\n","from pyannote.audio.core.task import Task, Resolution\n","from pyannote.database import Protocol\n","from torchmetrics.classification import MultilabelAUROC\n","\n","# Your custom task must be a subclass of `pyannote.audio.core.task.Task`\n","class SoundEventDetection(Task):\n"," \"\"\"Sound event detection\"\"\"\n","\n"," def __init__(\n"," self,\n"," protocol: Protocol,\n"," duration: float = 5.0,\n"," min_duration: float = 5.0,\n"," warm_up: Union[float, Tuple[float, float]] = 0.0,\n"," batch_size: int = 32,\n"," num_workers: int = None,\n"," pin_memory: bool = False,\n"," augmentation = None,\n"," cache: Optional[Union[str, None]] = None,\n"," **other_params,\n"," ):\n","\n"," super().__init__(\n"," protocol,\n"," duration=duration,\n"," min_duration=min_duration,\n"," warm_up=warm_up,\n"," batch_size=batch_size,\n"," num_workers=num_workers,\n"," pin_memory=pin_memory,\n"," augmentation=augmentation,\n"," cache=cache,\n"," )\n"," \n"," def prepare_data(self):\n"," # this method is called to prepare data from the specified protocol. \n"," # For most tasks, calling Task.prepare_data() is sufficient. If you \n"," # need to prepare task-specific data, define a post_prepare_data method for your task.\n"," super().prepare_data()\n","\n"," def post_prepare_data(self, prepared_data: Dict):\n"," # this method is called at the end of Task.prepare_data() \n"," # to complete data preparation with task-specific data, here \n"," # the list of classes and some training metadata\n","\n"," # load metadata for training subset\n"," prepared_data[\"train_metadata\"] = list()\n"," for training_file in self.protocol.train():\n"," prepared_data[\"train_metadata\"].append({\n"," # path to audio file (str)\n"," \"audio\": training_file[\"audio\"],\n"," # duration of audio file (float)\n"," \"duration\": training_file[\"torchaudio.info\"].num_frames / training_file[\"torchaudio.info\"].sample_rate,\n"," # reference annotation (pyannote.core.Annotation)\n"," \"annotation\": training_file[\"annotation\"],\n"," })\n","\n"," # gather the list of classes\n"," classes = set()\n"," for training_file in prepared_data[\"train_metadata\"]:\n"," classes.update(training_file[\"annotation\"].labels())\n"," prepared_data[\"classes\"] = sorted(classes)\n","\n"," # `has_validation` is True if protocol defines a development set\n"," if not self.has_validation:\n"," return\n"," \n"," def prepare_validation(self, prepared_data : Dict):\n"," # this method is called at the end of Task.prepare_data(), to complete data preparation\n"," # with task validation elements\n"," \n"," # load metadata for validation subset\n"," prepared_data[\"validation\"] = list()\n"," for validation_file in self.protocol.development():\n"," prepared_data[\"validation\"].append({\n"," \"audio\": validation_file[\"audio\"],\n"," \"num_samples\": validation_file[\"torchaudio.info\"].num_frames,\n"," \"annotation\": validation_file[\"annotation\"],\n"," })\n"," \n"," \n"," def setup(self, stage: Optional[Union[str, None]] = None):\n"," # this method assigns prepared data from task.prepare_data() to the task\n"," # and declares the task specifications\n","\n"," super().setup(stage)\n"," \n"," # specify the addressed problem\n"," self.specifications = Specifications(\n"," # it is a multi-label classification problem\n"," problem=Problem.MULTI_LABEL_CLASSIFICATION,\n"," # we expect the model to output one prediction \n"," # for the whole chunk\n"," resolution=Resolution.CHUNK,\n"," # the model will ingest chunks with that duration (in seconds)\n"," duration=self.duration,\n"," # human-readable names of classes\n"," classes=self.prepared_data[\"classes\"])\n"," \n"," def default_metric(self):\n"," # this method defines the default metrics used to evaluate the model during\n"," # a training\n"," num_classes = len(self.specifications.classes)\n"," return MultilabelAUROC(num_classes, average=\"macro\", compute_on_cpu=True)\n","\n"," def train__iter__(self):\n"," # this method generates training samples, one at a time, \"ad infinitum\". each worker \n"," # of the dataloader will run it, independently from other workers. pyannote.audio and\n"," # pytorch-lightning will take care of making batches out of it.\n","\n"," # create worker-specific random number generator (RNG) to avoid this common bug:\n"," # tanelp.github.io/posts/a-bug-that-plagues-thousands-of-open-source-ml-projects/\n"," rng = create_rng_for_worker(self.model)\n","\n"," # load list and number of classes\n"," classes = self.specifications.classes\n"," num_classes = len(classes)\n","\n"," # yield training samples \"ad infinitum\"\n"," while True:\n","\n"," # select training file at random\n"," random_training_file, *_ = rng.choices(self.prepared_data[\"train_metadata\"], k=1)\n","\n"," # select one chunk at random \n"," random_start_time = rng.uniform(0, random_training_file[\"duration\"] - self.duration)\n"," random_chunk = Segment(random_start_time, random_start_time + self.duration)\n","\n"," # load audio excerpt corresponding to random chunk\n"," X = self.model.audio.crop(random_training_file[\"audio\"], \n"," random_chunk, \n"," fixed=self.duration)\n"," \n"," # load labels corresponding to random chunk as {0|1} numpy array\n"," # y[k] = 1 means that kth class is active\n"," y = np.zeros((num_classes,))\n"," active_classes = random_training_file[\"annotation\"].crop(random_chunk).labels()\n"," for active_class in active_classes:\n"," y[classes.index(active_class)] = 1\n"," \n"," # yield training samples as a dict (use 'X' for input and 'y' for target)\n"," yield {'X': X, 'y': y}\n","\n"," def train__len__(self):\n"," # since train__iter__ runs \"ad infinitum\", we need a way to define what an epoch is.\n"," # this is the purpose of this method. it outputs the number of training samples that\n"," # make an epoch.\n","\n"," # we compute this number as the total duration of the training set divided by \n"," # duration of training chunks. we make sure that an epoch is at least one batch long,\n"," # or pytorch-lightning will complain\n"," train_duration = sum(training_file[\"duration\"] for training_file in self.prepared_data[\"train_metadata\"])\n"," return max(self.batch_size, ceil(train_duration / self.duration))\n","\n"," def val__getitem__(self, sample_idx):\n","\n"," # load list and number of classes\n"," classes = self.specifications.classes\n"," num_classes = len(classes)\n","\n","\n"," # find which part of the validation set corresponds to sample_idx\n"," num_samples = np.cumsum([\n"," validation_file[\"num_samples\"] for validation_file in self.prepared_data[\"validation\"]])\n"," file_idx = np.where(num_samples < sample_idx)[0][0]\n"," validation_file = self.prepared_data[\"validation\"][file_idx]\n"," idx = sample_idx - (num_samples[file_idx] - validation_file[\"num_samples\"]) \n"," chunk = SlidingWindow(start=0., duration=self.duration, step=self.duration)[idx]\n","\n"," # load audio excerpt corresponding to current chunk\n"," X = self.model.audio.crop(validation_file[\"audio\"], chunk, fixed=self.duration)\n","\n"," # load labels corresponding to random chunk as {0|1} numpy array\n"," # y[k] = 1 means that kth class is active\n"," y = np.zeros((num_classes,))\n"," active_classes = validation_file[\"annotation\"].crop(chunk).labels()\n"," for active_class in active_classes:\n"," y[classes.index(active_class)] = 1\n","\n"," return {'X': X, 'y': y}\n","\n"," def val__len__(self):\n"," return sum(validation_file[\"num_samples\"] \n"," for validation_file in self.prepared_data[\"validation\"])\n","\n"," # `pyannote.audio.core.task.Task` base class provides a `LightningModule.training_step` and \n"," # `LightningModule.validation_step` methods that rely on self.specifications to guess which \n"," # loss and metrics should be used. you can obviously choose to customize them. \n"," # More details can be found in pytorch-lightning documentation and in \n"," # pyannote.audio.core.task.Task source code. \n","\n"," # def training_step(self, batch, batch_idx: int):\n"," # return loss\n","\n"," # def validation_step(self, batch, batch_idx: int):\n"," # return metric\n","\n"," # pyannote.audio.tasks.segmentation.mixin also provides a convenient mixin\n"," # for \"segmentation\" tasks (ie. with Resolution.FRAME) that already defines\n"," # a bunch of useful methods. You can use it by inheriting your task from the \n"," # pyannote.audio.tasks.segmentation.mixinSegmentationTask"]}],"metadata":{"colab":{"provenance":[]},"kernelspec":{"display_name":"Python 3","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.13"}},"nbformat":4,"nbformat_minor":0}
diff --git a/tutorials/applying_a_model.ipynb b/tutorials/applying_a_model.ipynb
index e035d0654..68524eb57 100644
--- a/tutorials/applying_a_model.ipynb
+++ b/tutorials/applying_a_model.ipynb
@@ -1,437 +1 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "# preparing notebook for visualization purposes\n",
- "# (only show outputs between t=0s and t=30s)\n",
- "from pyannote.core import notebook, Segment\n",
- "notebook.crop = Segment(0, 30)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Applying a pretrained model\n",
- "\n",
- "In this tutorial, you will learn how to apply `pyannote.audio` models on an audio file, whose manual annotation is depicted below"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "# clone pyannote-audio Github repository and update ROOT_DIR accordingly\n",
- "ROOT_DIR = \"/Users/hbredin/Development/pyannote/pyannote-audio\"\n",
- "AUDIO_FILE = f\"{ROOT_DIR}/tutorials/assets/sample.wav\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAABi8AAADyCAYAAAA1MlYeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy89olMNAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAdwUlEQVR4nO3dfZBV9X0/8PeCgDzsrjwtC/JQqsgQJSrSUTQViBFlTEY0aRFTfxDSGIqmohPNRNOI0UDVStpqS2xSk2qTAE0UMw1GmSCgZWTUhmqTjA1GBAO4SoVdCS7K3t8fjtsQTAxwl3t29/Wa2Zm95977PZ9777nf/dx933NOValUKgUAAAAAAKAgulS6AAAAAAAAgF8nvAAAAAAAAApFeAEAAAAAABSK8AIAAAAAACgU4QUAAAAAAFAowgsAAAAAAKBQhBcAAAAAAEChCC8AAAAAAIBCEV4AAAAAAACFIrwAAAAAAAAKRXgBAAAAAAAUivACAAAAAAAoFOEFAAAAAABQKMILAAAAAACgUIQXAAAAAABAoQgvKmDWrFmZNm1apcugHbCtAAAAAACdkfCiA2lqasq8efMyYsSI9OzZM2eeeWaefPLJ/W5TKpUyf/78DBkyJD179sykSZPyk5/8pEIVUym/z7Zy//3357zzzsuAAQNSVVWVDRs2VKZYAAAAAKDTOarcA+7bsaPcQ/5OXfv3P6LrK6I333wz3bp1y5//+Z/nv//7v3PfffdlyJAh+dd//dd86EMfyk9/+tMce+yxSZLbbrstixYtyje/+c2ccMIJueWWW3LuuefmueeeS3V19RGv/bXde4/o+vr27n5E11c0B7Ot7N69O2eddVb+5E/+JJ/61KcqXDkAAAAA0JlUlUqlUjkH/OWxw8o53Hs69pdbDvo+3/3ud3PTTTdl48aN6dWrV0499dQ8+OCDueKKK7Jz586ceuqp+Yd/+Ie88cYbmTFjRu6888507/72P71LpVJuv/32fPWrX822bdtywgkn5K/+6q/ysY99LEmyb9++XH755Vm1alW2b9+e4cOHZ+7cubnqqqta1z9r1qzs3Lkzy5cvT5I8/fTTmTp1aq666qrccMMN2bVrV6699tosX748b7zxRsaPH5+vfOUrOfnkk5Mk8+fPz/Lly/OXf/mXueWWW7Jp06bs3r071dXVefDBB3PBBRe0ruuUU07Jhz/84dxyyy0plUoZMmRI5s2bl8997nNJkubm5gwaNCi33nprPv3pTx/Sa3A4zrjx4SO6viduOu+gbt9Zt5Vft2nTpowcOTI//vGPc8oppxzsUw4AAAAAcNDKvudF0W3bti0zZszIbbfdlosuuihNTU157LHH8k6G86Mf/ShHH310Hn300WzatCmf+MQnMmDAgHz5y19OknzhC1/I/fffn8WLF2fUqFFZu3Zt/uzP/iwDBw7MxIkT09LSkqFDh2bZsmUZMGBA1q1bl8svvzyDBw/On/7pnx5Qz+rVqzNt2rQsXLgwf/EXf5FSqZQLLrgg/fr1y4oVK1JbW5u7774755xzTv7nf/4n/fr1S5Js3Lgxy5Yty/e+97107do1b731Vvbt25ejjz56v/F79uyZxx9/PEnywgsvZPv27ZkyZUrr9T169MjEiROzbt26ioQXRdaZtxUAAAAAgErqlOHFW2+9lYsvvjgjRoxIkowdO7b1+u7du+eee+5Jr169cuKJJ+ZLX/pSrr322tx8883Zs2dPFi1alFWrVmXChAlJkj/8wz/M448/nrvvvjsTJ05Mt27dctNNN7WON3LkyKxbty7Lli074B/SDz74YC677LLcfffdmTFjRpLk0UcfzbPPPpuGhob06NEjSfI3f/M3Wb58eb773e/m8ssvT5Ls3bs39913XwYOHNg63oQJE3LzzTdnzJgxGTRoUL7zne9k/fr1GTVqVJJk+/btSZJBgwbtV8egQYPy4osvHv6T28F05m0FAAAAAKCSOl14cfLJJ+ecc87J2LFjc95552XKlCn52Mc+lr59+7Ze36tXr9bbT5gwIa+//nq2bNmShoaGvPHGGzn33HP3G3Pv3r059dRTWy9/9atfzde//vW8+OKL2bNnT/bu3XvA4XbWr1+ff//3f8+//du/5aKLLmpd/vTTT+f1119P/984l8eePXvy/PPPt14eMWLEfv+MTpL77rsvs2fPzrHHHpuuXbtm3LhxufTSS/Of//mf+92uqqpqv8ulUumAZdhWAAAAAAAqpezhRf0zG8o9ZFl17do1K1euzLp16/LII4/kzjvvzA033JD169f/zvtVVVWlpaUlSfKDH/yg9aTG73jnm+/Lli3L1VdfnTvuuCMTJkxIdXV1br/99gPGP+6449K/f//cc889ueCCC1rPk9DS0pLBgwdn9erV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",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pyannote.database.util import load_rttm\n",
- "REFERENCE = f\"{ROOT_DIR}/tutorials/assets/sample.rttm\"\n",
- "reference = load_rttm(REFERENCE)[\"sample\"]\n",
- "reference"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Loading models from 🤗 hub\n",
- "\n",
- "A bunch of pretrained models are available on [🤗 Huggingface model hub](https://hf.co/models?other=pyannote-audio-model) and can be listed by looking for the [`pyannote-audio-model`](https://hf.co/models?other=pyannote-audio-model) tag."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "['pyannote/Segmentation-PyanNet-DIHARD',\n",
- " 'pyannote/TestModelForContinuousIntegration',\n",
- " 'pyannote/embedding',\n",
- " 'pyannote/segmentation',\n",
- " 'pyannote/brouhaha']"
- ]
- },
- "execution_count": 16,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from huggingface_hub import HfApi\n",
- "available_models = [m.modelId for m in HfApi().list_models(filter=\"pyannote-audio-model\")]\n",
- "list(filter(lambda p: p.startswith(\"pyannote/\"), available_models))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Official [pyannote.audio](https://github.com/pyannote/pyannote-audio) models (i.e. those under the [`pyannote` organization](https://hf.co/pyannote) umbrella) are open-source, but gated. It means that you have to first accept users conditions on their respective Huggingface page to access the pretrained weights and hyper-parameters. Despite this initial process, those models can perfectly be downloaded for later offline use: keep reading this tutorial until the end to learn how to do that.\n",
- "\n",
- "For instance, to load the speaker segmentation model used in this tutorial, you have to visit [hf.co/pyannote/segmentation](https://hf.co/pyannote/segmentation), accept the terms, and log in using `notebook_login` below:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "1b7ac613e9e841c8903dc4932e183006",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HTML(value=' , resolution=, duration=5.0, warm_up=(0.0, 0.0), classes=['speaker#1', 'speaker#2', 'speaker#3'], permutation_invariant=True)"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "specs = model.specifications\n",
- "specs"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "... which can be understood like that:\n",
- "\n",
- "* `duration = 5.0`: the model ingests 5s-long audio chunks\n",
- "* `Resolution.FRAME` and `len(classes) == 3`: the model output a sequence of frame-wise 3-dimensoinal scores\n",
- "* `Problem.MULTI_LABEL_CLASSIFICATION` for each frame, more than one speaker can be active at once"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To apply the model on the audio file, we wrap it into an `Inference` instance:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAABi4AAAGZCAYAAAAetMkNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy89olMNAAAACXBIWXMAAA9hAAAPYQGoP6dpAADTZ0lEQVR4nOzdd2AcZ53/8ffMNvVuybbk3lsc2+m9EtIJgUCAEHo7erkf9TjuDg6OO2roJUDoSSgJ6QnpzUkc995lVavXrTO/P55dFVu2VXa1K/nzgs3Mzs7OPJLWszPzfb7P13Jd10VERERERERERERERCQD2OlugIiIiIiIiIiIiIiISIICFyIiIiIiIiIiIiIikjEUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQMBS5ERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGN7RvtFxHGpra8nPz8eyrGS2SUREREREREREREREJhjXdens7GT69OnY9ujzJkYduKitrWXGjBmj3rGIiIiIiIiIiIiIiEw+1dXVVFVVjfr9ow5c5Ofn9zWgoKBg1A0QEREREREREREREZGJr6OjgxkzZvTFD0Zr1IGLxPBQBQUFClyIiIiIiIiIiIiIiAjAmMtLqDi3iIiIiIiIiIiIiIhkDAUuREREREREREREREQkYyhwISIiIiIiIiIiIiIiGUOBCxERERERERERERERyRgKXIiIiIiIiIiIiIiISMZQ4EJERERERERERERERDKGAhciIiIiIiIiIiIiIpIxFLgQEREREREREREREZGMocCFiIiIiIiIiIiIiIhkDAUuREREREREREREREQkY3jT3QAREZHxFozECEUdYo5L1IlPY278udu3nmX1v8fqW2YNsWzgetZRy47c3mi2YR0xYzFgG9YR6wzYx+BlR7w3PrEtyPZ58HpOrv4MruviuBBzXLy2hW0P8UcTkZFzXXCi4MTAdcwDt3/edeMP5zivD5jniHUHvo7bvz2z8/73JNqCO0QjE474d3/Uwfs4B/NjbmOM+xjqC2TM28iUfRz5lgHreLMgf9rw3ncCkZhDTzhGbzhGOOoQcRwiMYdI1MVxXWzLwrLMrmzLij+ILxvwHLOebZtvzv71rAHvja9nc/T7jlwvCT+bSCZr6grhOOb8ysU1h2fM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JXNcPedquiJD1yQ6llF9Tl0X13WwnGj/kGaJaeL6uu8+lNlLYpkVf//AZQxcdtSUI9Yd4rUjtjd4HwNZR8wOOpoPXm/QIfzoexxH3TEa8vx/8OvWkcuP9Z5BbTuyzZjhST1+M9ycP98M/9TXruN89ySyARJD0MXvd1h99z1i8QzgI+ZJ3B8xv1MziIYzxN8obohMEWvg86HuHw75nhF+j474GmyEe4hnpFgeH1jxrJXEvTrbM2De2z9EuTdrVNc3I72ezPHmUJJVQnFWMSVZJcwsmDnifYoMZcxDRY015UNERERERERERERERCa+ZMUNJl6VZBERERERERERERERmbQUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQMBS5ERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGApciIiIiIiIiIiIiIhIxlDgQkREREREREREREREMoYCFyIiIiIiIiIiIiIikjEUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQM72jf6LouAB0dHUlrjIiIiIiIiIiIiIiITEyJeEEifjBaow5cNDc3AzBjxowxNUBERERERERERERERCaPzs5OCgsLR/3+UQcuSkpKADh48OCYGiAiE1dHRwczZsygurqagoKCdDdHRNJAxwER0XFAREDHAhHRcUBE+o8DW7duZfr06WPa1qgDF7ZtymMUFhbqYCRykisoKNBxQOQkp+OAiOg4ICKgY4GI6DggIlBZWdkXPxgtFecWEREREREREREREZGMocCFiIiIiIiIiIiIiIhkjFEHLgKBAF/+8pcJBALJbI+ITCA6DoiIjgMiouOAiICOBSKi44CIJPc4YLmu6yahTSIiIiIiIiIiIiIiImOmoaJERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGApciIiIiIiIiIiIiIhIxlDgQkREREREREREREREMoYCFyIiIiIiIiIiIiIikjEUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQMBS5ERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGApciIiIiIiIiIiIiIhIxlDgQkREREREREREREREMoZ3tG90HIfa2lry8/OxLCuZ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",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pyannote.audio import Inference\n",
- "inference = Inference(model, step=2.5)\n",
- "output = inference(AUDIO_FILE)\n",
- "output"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For each of the 11 positions of the 5s window, the model outputs a 3-dimensional vector every 16ms (293 frames for 5 seconds), corresponding to the probabilities that each of (up to) 3 speakers is active. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(11, 293, 3)"
- ]
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "output.data.shape"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Processing a file from memory\n",
- "\n",
- "In case the audio file is not stored on disk, pipelines can also process audio provided as a `{\"waveform\": ..., \"sample_rate\": ...}` dictionary. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "type(waveform)=\n",
- "waveform.shape=torch.Size([1, 480000])\n",
- "waveform.dtype=torch.float32\n"
- ]
- }
- ],
- "source": [
- "import torchaudio\n",
- "waveform, sample_rate = torchaudio.load(AUDIO_FILE)\n",
- "\n",
- "print(f\"{type(waveform)=}\")\n",
- "print(f\"{waveform.shape=}\")\n",
- "print(f\"{waveform.dtype=}\")\n",
- "\n",
- "audio_in_memory = {\"waveform\": waveform, \"sample_rate\": sample_rate}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAABi4AAAGZCAYAAAAetMkNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy89olMNAAAACXBIWXMAAA9hAAAPYQGoP6dpAADTZ0lEQVR4nOzdd2AcZ53/8ffMNvVuybbk3lsc2+m9EtIJgUCAEHo7erkf9TjuDg6OO2roJUDoSSgJ6QnpzUkc995lVavXrTO/P55dFVu2VXa1K/nzgs3Mzs7OPJLWszPzfb7P13Jd10VERERERERERERERCQD2OlugIiIiIiIiIiIiIiISIICFyIiIiIiIiIiIiIikjEUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQMBS5ERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGN7RvtFxHGpra8nPz8eyrGS2SUREREREREREREREJhjXdens7GT69OnY9ujzJkYduKitrWXGjBmj3rGIiIiIiIiIiIiIiEw+1dXVVFVVjfr9ow5c5Ofn9zWgoKBg1A0QEREREREREREREZGJr6OjgxkzZvTFD0Zr1IGLxPBQBQUFClyIiIiIiIiIiIiIiAjAmMtLqDi3iIiIiIiIiIiIiIhkDAUuREREREREREREREQkYyhwISIiIiIiIiIiIiIiGUOBCxERERERERERERERyRgKXIiIiIiIiIiIiIiISMZQ4EJERERERERERERERDKGAhciIiIiIiIiIiIiIpIxFLgQEREREREREREREZGMocCFiIiIiIiIiIiIiIhkDAUuREREREREREREREQkY3jT3QAREZHxFozECEUdYo5L1IlPY278udu3nmX1v8fqW2YNsWzgetZRy47c3mi2YR0xYzFgG9YR6wzYx+BlR7w3PrEtyPZ58HpOrv4MruviuBBzXLy2hW0P8UcTkZFzXXCi4MTAdcwDt3/edeMP5zivD5jniHUHvo7bvz2z8/73JNqCO0QjE474d3/Uwfs4B/NjbmOM+xjqC2TM28iUfRz5lgHreLMgf9rw3ncCkZhDTzhGbzhGOOoQcRwiMYdI1MVxXWzLwrLMrmzLij+ILxvwHLOebZtvzv71rAHvja9nc/T7jlwvCT+bSCZr6grhOOb8ysU1h2fM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JXNcPedquiJD1yQ6llF9Tl0X13WwnGj/kGaJaeL6uu8+lNlLYpkVf//AZQxcdtSUI9Yd4rUjtjd4HwNZR8wOOpoPXm/QIfzoexxH3TEa8vx/8OvWkcuP9Z5BbTuyzZjhST1+M9ycP98M/9TXruN89ySyARJD0MXvd1h99z1i8QzgI+ZJ3B8xv1MziIYzxN8obohMEWvg86HuHw75nhF+j474GmyEe4hnpFgeH1jxrJXEvTrbM2De2z9EuTdrVNc3I72ezPHmUJJVQnFWMSVZJcwsmDnifYoMZcxDRY015UNERERERERERERERCa+ZMUNJl6VZBERERERERERERERmbQUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQMBS5ERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGApciIiIiIiIiIiIiIhIxlDgQkREREREREREREREMoYCFyIiIiIiIiIiIiIikjEUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQM72jf6LouAB0dHUlrjIiIiIiIiIiIiIiITEyJeEEifjBaow5cNDc3AzBjxowxNUBERERERERERERERCaPzs5OCgsLR/3+UQcuSkpKADh48OCYGiAiE1dHRwczZsygurqagoKCdDdHRNJAxwER0XFAREDHAhHRcUBE+o8DW7duZfr06WPa1qgDF7ZtymMUFhbqYCRykisoKNBxQOQkp+OAiOg4ICKgY4GI6DggIlBZWdkXPxgtFecWEREREREREREREZGMocCFiIiIiIiIiIiIiIhkjFEHLgKBAF/+8pcJBALJbI+ITCA6DoiIjgMiouOAiICOBSKi44CIJPc4YLmu6yahTSIiIiIiIiIiIiIiImOmoaJERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGApciIiIiIiIiIiIiIhIxlDgQkREREREREREREREMoYCFyIiIiIiIiIiIiIikjEUuBARERERERERERERkYyhwIWIiIiIiIiIiIiIiGQMBS5ERERERERERERERCRjKHAhIiIiIiIiIiIiIiIZQ4ELERERERERERERERHJGApciIiIiIiIiIiIiIhIxlDgQkREREREREREREREMoZ3tG90HIfa2lry8/OxLCuZ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",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "output = inference(audio_in_memory)\n",
- "output"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Processing part of a file\n",
- "\n",
- "If needed, `Inference` can be used to process only part of a file:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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vnx53vrWt+bd7353TjvttJx22ml597vfnWnTpuXVr351E6sGGumJrgNz5szJNddck1/8xV/MokWL8vDDD+cd73hH5s2bl5e97GVNrBpopDe/+c35j//4j3zuc5/LzJkzRz9N2d3dnalTp6YoCq8J4Bh3qOvAjh07vCaAY9w73vGOXHnllVm2bFl6e3vziU98It/+9rfzla98paGvBcYUXLziFa/I5s2b82d/9mdZu3Ztzj333HzpS1/KiSeeOJbugElm1apVedWrXpVNmzblhBNOyJOf/OT88Ic/dA2AY9jNN9+cZz/72aPPR+azee1rX5uPfvSj+YM/+IPs3r07b3rTm7J169Zcfvnl+drXvpaZM2c2q2SgwZ7oOvDBD34wd9xxRz72sY9l27ZtWbRoUZ797Gfn2muvdR2AY8gHP/jBJMmznvWs/dZ/5CMfyete97ok8ZoAjnGHug5Uq1WvCeAYt379+rzmNa/J2rVr093dnfPPPz9f+cpX8vznPz9J414LFGVZlhPxBQAAAAAAABypI57jAgAAAAAAYKIILgAAAAAAgJYhuAAAAAAAAFqG4AIAAAAAAGgZggsAAAAAAKBlCC4AAAAAAICWIbgAAAAAAABahuACAAAAAABoGYILAADgkK655ppceOGFzS4DAAA4DhRlWZbNLgIAAGieoiiecPtrX/vavP/9709fX1/mzp17lKoCAACOV4ILAAA4zq1bt250+dprr82f/umf5p577hldN3Xq1HR3dzejNAAA4DjkVlEAAHCcW7hw4eiju7s7RVE8Zt2Bt4p63etel6uuuirvfve7s2DBgsyaNSvvete7Mjg4mN///d/PnDlzsnTp0vzLv/zLfudavXp1XvGKV2T27NmZO3duXvrSl+bhhx8+ul8wAADQ0gQXAADAmHzzm9/MmjVr8p3vfCd/8zd/k2uuuSYvfvGLM3v27PzoRz/K1VdfnauvvjorV65MkuzatSvPfvazM2PGjHznO9/Jd7/73cyYMSMvfOEL09/f3+SvBgAAaBWCCwAAYEzmzJmTv/u7v8sZZ5yR17/+9TnjjDOya9euvOMd78hpp52W//E//kc6Ojryve99L0nyiU98IpVKJf/8z/+c8847L2eddVY+8pGP5NFHH823v/3t5n4xAABAy2hrdgEAAMDkdM4556RS2ftZqAULFuTcc88dfV6tVjN37txs2LAhSXLLLbfk/vvvz8yZM/frZ8+ePXnggQeOTtEAAEDLE1wAAABj0t7evt/zoigOuq5WqyVJarVaLrnkknz84x9/TF8nnHDCxBUKAABMKoILAADgqLj44otz7bXXZv78+enq6mp2OQAAQIsyxwUAAHBU/Mqv/ErmzZuXl770pbnhhhvy0EMP5frrr8/v/d7vZdWqVc0uDwAAaBGCCwAA4KiYNm1avvOd72T58uV5+ctfnrPOOiuvf/3rs3v3biMwAACAUUVZlmWziwAAAAAAAEiMuAAAAAAAAFqI4AIAAAAAAGgZggsAAAAAAKBlCC4AAAAAAICWIbgAAAAAAABahuACAAAAAABoGYILAAAAAACgZQguAAAAAACAliG4AAAAAAAAWobgAgAAAAAAaBmCCwAAAAAAoGX8/wFqlZQ/bA3JugAAAABJRU5ErkJggg==",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pyannote.core import Segment\n",
- "output = inference.crop(AUDIO_FILE, Segment(10, 20))\n",
- "output"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Offline use\n",
- "\n",
- "Gating models allows [me](https://herve.niderb.fr) to know a bit more about `pyannote.audio` user base and eventually help me write grant proposals to make `pyannote.audio` even better. Please fill this form as precisely as possible. \n",
- "\n",
- "For instance, before gating `pyannote/segmentation`, I had no idea that so many people were relying on it in production. Hint: sponsors are more than welcome! maintaining open source libraries is time consuming.\n",
- "\n",
- "That being said: this whole authentication process does not prevent you from using official `pyannote.audio` models offline (i.e. without going through the authentication process in every `docker run ...` or whatever you are using in production).\n",
- "\n",
- "* Step 1: download the `pytorch_model.bin` model\n",
- "\n",
- "![](assets/download-model.png)\n",
- "\n",
- "* Step 2: load the model"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [],
- "source": [
- "# look ma: no hands! \n",
- "offline_model = Model.from_pretrained(\"pytorch_model.bin\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {},
- "outputs": [],
- "source": [
- "# just checking weights are the same...\n",
- "import torch\n",
- "for weights, offline_weights in zip(model.parameters(), offline_model.parameters()):\n",
- " assert torch.equal(weights, offline_weights)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3.9.13 ('pyannote-mps')",
- "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.9.13"
- },
- "vscode": {
- "interpreter": {
- "hash": "36a3a48a52702f18671693adf589423ec3f7db45d50f6ee539f1b0696bb58d43"
- }
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
+{"cells":[{"cell_type":"markdown","metadata":{"id":"rkz0m90MTNdU"},"source":["****"]},{"cell_type":"markdown","metadata":{"id":"vDBFFNeGWF0v"},"source":["# Applying a pretrained model\n","\n","In this tutorial, you will learn how to apply `pyannote.audio` models on an audio file, whose manual annotation is depicted below"]},{"cell_type":"markdown","metadata":{"id":"DcXUj3lVTkWz"},"source":["## Tutorial setup"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":221,"status":"ok","timestamp":1704806538788,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"p7uwJtF1W0Od"},"outputs":[],"source":["# preparing notebook for visualization purposes\n","# (only show outputs between t=0s and t=30s)\n","from pyannote.core import notebook, Segment\n","notebook.crop = Segment(0, 30)"]},{"cell_type":"markdown","metadata":{"id":"yr4ONuV9Tlgj"},"source":["### `Google Colab` setup"]},{"cell_type":"markdown","metadata":{"id":"OaXXRLf5Tp2D"},"source":["If you are running this tutorial on `Colab`, execute the following commands in order to setup `Colab` environment. These commands will install `pyannote.audio`, and download resources used in this tutorial."]},{"cell_type":"code","execution_count":null,"metadata":{"id":"wQub0z0VTzpU"},"outputs":[],"source":["!pip install -qq pyannote.audio==3.1.1\n","!pip install -qq ipython==7.34.0\n","!wget -q \"https://github.com/pyannote/pyannote-audio/raw/develop/tutorials/assets/sample.wav\"\n","!wget -q \"https://github.com/pyannote/pyannote-audio/raw/develop/tutorials/assets/sample.rttm\"\n","!wget -q -P ./assets/ \"https://github.com/pyannote/pyannote-audio/blob/develop/tutorials/assets/download-model.png\""]},{"cell_type":"markdown","metadata":{"id":"4Qy1iMvGVaHF"},"source":["⚠ Restart the runtime (Runtime > Restart session)."]},{"cell_type":"code","execution_count":18,"metadata":{"executionInfo":{"elapsed":203,"status":"ok","timestamp":1704807063824,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"vHwJOO-sUdF2"},"outputs":[],"source":["AUDIO_FILE = \"sample.wav\"\n","REFERENCE = \"sample.rttm\""]},{"cell_type":"markdown","metadata":{"id":"CUmGkiY-V-wI"},"source":["### Non `Google Colab` setup"]},{"cell_type":"markdown","metadata":{"id":"_E4buYUQWXE5"},"source":["If you are not using Colab, clone `pyannote.audio` [GitHub repository](https://github.com/pyannote/pyannote-audio) and update ROOT_DIR accordingly"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":232,"status":"ok","timestamp":1704806051725,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"Wii7pyvSTIa1"},"outputs":[],"source":["# clone pyannote-audio Github repository and update ROOT_DIR accordingly\n","ROOT_DIR = \"/pyannote-audio\"\n","AUDIO_FILE = f\"{ROOT_DIR}/tutorials/assets/sample.wav\"\n","REFERENCE = f\"{ROOT_DIR}/tutorials/assets/sample.rttm\""]},{"cell_type":"markdown","metadata":{"id":"o01jf1VTXC8u"},"source":["## References\n","\n","First, let's take a look at the audio reference used in this tutorial. It can be accessed as follows:"]},{"cell_type":"code","execution_count":4,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":259},"executionInfo":{"elapsed":542,"status":"ok","timestamp":1704807074571,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"Q4hYAMEiTIa3","outputId":"9fecf73e-2448-4a4e-93e4-f35d2ec4da8b"},"outputs":[{"data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAABi8AAADyCAYAAAA1MlYeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAfHUlEQVR4nO3dfZRU9X0/8PeCgAi7i4AsrCKigpgEEB9KVq2aSED02KIxCnlQqNXWIKeoJNZWRKvGBmsejCYmaa3RVI0xgm2soSkIVkPwISHG2hjhaLA/npSE5UEFszu/PzxuQzAmwOzO3d3X65w9Z/feme/9zNzvfPc78557b1WpVCoFAAAAAACgILpUugAAAAAAAIDfJLwAAAAAAAAKRXgBAAAAAAAUivACAAAAAAAoFOEFAAAAAABQKMILAAAAAACgUIQXAAAAAABAoQgvAAAAAACAQhFeAAAAAAAAhSK8AAAAAAAACkV4AQAAAAAAFIrwAgAAAAAAKBThBQAAAAAAUCjCCwAAAAAAoFCEFwAAAAAAQKEILypg6tSpmTRpUqXLoB3QVwAAAACAzkh40YFs3rw5M2fOzJAhQ9KzZ88ce+yxefLJJ3e4TalUylVXXZVBgwalZ8+eGTduXF544YUKVUyl/CF95YEHHsj48ePTr1+/VFVVZfny5ZUpFgAAAADodPYqd4NNGzaUu8l31bVfvzbdXhFt37493bt3z5//+Z/n2WefzV133ZX6+vp885vfzLhx4/Lcc89l//33T5LMnTs3N998c77xjW9k6NChmT17diZMmJDnnnsue++9d5vW/aut29t0e/v26t6m2yuiXekrW7duzfHHH5+zzz47F1xwQYUrBwAAAAA6k6pSqVQqZ4P/b//B5Wzu99r//728y/e5//77c80112TFihXZZ599MmbMmDz44IOZPn16Nm7cmDFjxuSWW27Jtm3b8tGPfjQ333xzund/64Pv5ubmfPazn83Xvva1rF27NsOHD8/s2bNz1llnJUmamppy4YUXZtGiRVm7dm0OPPDAfPKTn8xf/dVftWx/6tSp2bhxY+bPn58kefLJJ3Pqqadm1qxZufzyy7Nx48bMmjUrDz74YLZt25ajjz46n//85zN69OgkydVXX5358+fn4osvzvXXX59f/OIX2bp1a6qrq/Pggw/mtNNOa9nWUUcdlYkTJ+a6665LqVRKfX19LrvsssyaNStJ0tjYmLq6utxxxx2ZPHnybu2D3fX+OQvadHs/vGbCLt+ns/aV3/TSSy9l6NCh+fGPf5wjjjhil59DAAAAAIBdVfYjL4puzZo1mTJlSubOnZszzjgjmzdvzn/913/l7Qxn4cKF2XvvvbN48eK89NJLmTZtWvr165frr78+SXLDDTfkm9/8Zm677bYMGzYsjz76aD7+8Y9nv/32y4knnpjm5uYccMAB+fa3v51+/frlBz/4QS688MIMGjQoZ5999k71LFq0KGeeeWbmzp2bCy+8MEnykY98JD179szDDz+c2trafPWrX83JJ5+cn//85+nbt2+SZMWKFfnOd76TBx54IF27ds2vf/3rNDU17XT0RM+ePfPYY48lSV588cWsXbs248aNa1lfW1ubsWPHZunSpW0eXhRdZ+4rAAAAAACV1CnDi1//+tc588wzM2TIkCTJyJEjW9Z37949t99+e/bZZ5+8973vzd/93d/lU5/6VK699tq8+eab+cxnPpP//M//TENDQ5Lk4IMPzmOPPZavfvWrOfHEE9OtW7dcc801Le0NHTo0S5cuzX333bfTB9Lz5s3Lueeem3/8x3/MOeeckyR57LHH8sQTT2T9+vXp0aNHkuQf/uEfMn/+/Nx///0tH1pv3749d955Z/bbb7+W9hoaGnLttdfm8MMPT11dXe65554sXbo0hx56aJJk7dq1SZK6urod6qirq2tZx//pzH0FAAAAAKCSOl14MXr06Jx88skZOXJkJkyYkPHjx+ess87Kvvvu27J+n332abl9Q0NDtmzZkpdffjlbtmzJa6+9lg996EM7tLl9+/aMGTOm5e9bb701t99+e1atWpXXX38927dv3+l0O8uWLct3v/vd3H///Zk0aVLL8p/85CfZsmVL+v3WtTxef/31rFy5suXvIUOG7PBhdJLcdddd+bM/+7Psv//+6dq1a4488shMmTIlTz/99G49V52dvgIAAAAAUBllDy8GPrO83E2WVdeuXfP9738/P/jBD/If//Ef+dKXvpS//du/zbJly37vfbds2ZIkeeihh1ouavy2t7/5fu+992bWrFm56aab0tDQkOrq6tx44407tX/IIYekX79+uf3223PaaaelW7duLdsYNGhQFi9evNP2+/Tp0/J7r169dlp/yCGHZMmSJdm6dWs2bdqU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","text/plain":[""]},"execution_count":4,"metadata":{},"output_type":"execute_result"}],"source":["from pyannote.database.util import load_rttm\n","\n","reference = load_rttm(REFERENCE)[\"sample\"]\n","reference"]},{"cell_type":"markdown","metadata":{"id":"3cpR2brxTIa6"},"source":["## Loading models from 🤗 hub\n","\n","A bunch of pretrained models are available on [🤗 Huggingface model hub](https://hf.co/models?other=pyannote-audio-model) and can be listed by looking for the [`pyannote-audio-model`](https://hf.co/models?other=pyannote-audio-model) tag."]},{"cell_type":"code","execution_count":5,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":1201,"status":"ok","timestamp":1704807077972,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"OXNju-sFTIa7","outputId":"6c587fd6-f14f-4162-81ba-0609153aa7f2"},"outputs":[{"data":{"text/plain":["['pyannote/TestModelForContinuousIntegration',\n"," 'pyannote/embedding',\n"," 'pyannote/segmentation',\n"," 'pyannote/brouhaha',\n"," 'pyannote/segmentation-3.0',\n"," 'pyannote/wespeaker-voxceleb-resnet34-LM']"]},"execution_count":5,"metadata":{},"output_type":"execute_result"}],"source":["from huggingface_hub import HfApi\n","available_models = [m.modelId for m in HfApi().list_models(filter=\"pyannote-audio-model\")]\n","list(filter(lambda p: p.startswith(\"pyannote/\"), available_models))"]},{"cell_type":"markdown","metadata":{"id":"LrQ2ykU4TIa-"},"source":["Official [pyannote.audio](https://github.com/pyannote/pyannote-audio) models (i.e. those under the [`pyannote` organization](https://hf.co/pyannote) umbrella) are open-source, but gated. It means that you have to first accept users conditions on their respective Huggingface page to access the pretrained weights and hyper-parameters. Despite this initial process, those models can perfectly be downloaded for later offline use: keep reading this tutorial until the end to learn how to do that.\n","\n","For instance, to load the speaker segmentation model used in this tutorial, you have to visit [hf.co/pyannote/segmentation](https://hf.co/pyannote/segmentation), accept the terms, and log in using `notebook_login` below:"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":145,"referenced_widgets":["a73cecb8608f491e8f996c5114df4d0f","bc10c6804346449b8e349728a1acb8d2","73915caf6d1042ca9a27853986217ae2","2d1965df902b4b7eb6e4e28e44d6e32b","b2e03b10050d46548932f429bcc18d81","0c537fef94bd4a3d8c42d981a70ea35b","79d55946b3764666a0b57a72722f6c19","988c83c85f7d44d0be949de6eedcf977","53919e13e42441d9b8cf5eb4f2effe96","47da80658de14604a7cc5268b951c172","c7fbfffbbc304f0ba025e03beb8f638a","416ffb7703b1404ab1c19c6b1ecafb4c","5be7421c575d41128d0675dc9abbc196","8b3353af24074ce5b5d2d9b162c61062","cd40e31c191044b7a0f8fa4694ad6380","ecbb880cf0044404ab9bfc5995656807","79287ffea49a4e4a80191b1157de15cc","0e04a45510f346b8ab3c465b10ccdfd2","bf5c88fe90f0462b95aa8a81467c1e9d","09ee64808a5c431b928066a4cb287a78","52a4a1aab39741f2a0499428f07a4c25","f23cc133109c4ecb9b383f118bcc71aa","2b91f4b11d5848c0b6795b649bc2d7bc","b437981acb894f97ad45daaebe2734c7","01a79756e1104be0bcbe1d233677d605","990375a830eb4cd79c69ad78b9ac685b","49cb317b141a43b7b8ce342e2d62ab03","abc23089f4ef4d2a9f8a104fb1dba14a","57cf64e9c70e4057a76c2f3fb1e9b191","5e90e4818f1f43f2aa4714e0e40dc15d","fb027db34fd740c2a4758d650ae3f73c","1a30ac8b519948bbad72886049b53d55"]},"executionInfo":{"elapsed":215,"status":"ok","timestamp":1704807086866,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"x9iQwHjfTIa_","outputId":"b5b3c597-4c2e-4306-e6a5-9ccc9ed19d08"},"outputs":[],"source":["from huggingface_hub import notebook_login\n","notebook_login()"]},{"cell_type":"markdown","metadata":{"id":"fUvB3kwwTIbA"},"source":["Once authenticated, you can load the model..."]},{"cell_type":"code","execution_count":null,"metadata":{"executionInfo":{"elapsed":3254,"status":"ok","timestamp":1704807117456,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"IzYUeS99TIbE"},"outputs":[],"source":["from pyannote.audio import Model\n","model = Model.from_pretrained(\"pyannote/segmentation-3.0\", use_auth_token=True)"]},{"cell_type":"markdown","metadata":{"id":"UxuGtfPoTIbF"},"source":["... which consists in SincNet feature extraction (`sincnet`) , LSTM sequence modeling (`lstm`), a few feed-forward layers (`linear`), and a final multi-label `classifier`:"]},{"cell_type":"code","execution_count":8,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":223,"status":"ok","timestamp":1704807124564,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"BQ2RDdqUTIbH","outputId":"6caf82ff-7a19-401d-ad79-8350315ec9de"},"outputs":[{"data":{"text/plain":[" | Name | Type | Params | In sizes | Out sizes \n","---------------------------------------------------------------------------------------------------------\n","0 | sincnet | SincNet | 42.6 K | [1, 1, 160000] | [1, 60, 589] \n","1 | lstm | LSTM | 1.4 M | [1, 589, 60] | [[1, 589, 256], [[8, 1, 128], [8, 1, 128]]]\n","2 | linear | ModuleList | 49.4 K | ? | ? \n","3 | classifier | Linear | 903 | [1, 589, 128] | [1, 589, 7] \n","4 | activation | LogSoftmax | 0 | [1, 589, 7] | [1, 589, 7] \n","---------------------------------------------------------------------------------------------------------\n","1.5 M Trainable params\n","0 Non-trainable params\n","1.5 M Total params\n","5.893 Total estimated model params size (MB)"]},"execution_count":8,"metadata":{},"output_type":"execute_result"}],"source":["from pytorch_lightning.utilities.model_summary import summarize\n","\n","summarize(model)"]},{"cell_type":"markdown","metadata":{"id":"ahfL4saFTIbI"},"source":["More details about the model are provided by its specifications..."]},{"cell_type":"code","execution_count":9,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":195,"status":"ok","timestamp":1704807127275,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"B0OFti5ITIbJ","outputId":"c2d74d99-7727-4f36-9a0f-4ec2aa76bd25"},"outputs":[{"data":{"text/plain":["Specifications(problem=, resolution=, duration=10.0, min_duration=None, warm_up=(0.0, 0.0), classes=['speaker#1', 'speaker#2', 'speaker#3'], powerset_max_classes=2, permutation_invariant=True)"]},"execution_count":9,"metadata":{},"output_type":"execute_result"}],"source":["specs = model.specifications\n","specs"]},{"cell_type":"markdown","metadata":{"id":"kP5sRrrdTIbK"},"source":["... which can be understood like that:\n","\n","* `duration = 10.0`: the model ingests 10s-long audio chunks\n","* `Resolution.FRAME`: the model output a sequence of frame-wise scores\n","* `len(classes) = 3`: model handle chunks with up to 3 speakers\n","* `powerset_max_classes = 2`: at most 2 speakers can talk at the same time (overlapped speech)\n","The previous two specifications give the classes that the model can predict: {no speech}, {spk1}, {spk2}, {spk3}, {spk1, spk2}, {spk1, spk3}, {spk2, spk3}, so a total of 7 classes.\n","More details about powerset can be found in the article `A. Plaquet and H. Bredin, “Powerset multi-class cross entropy loss for neural speaker diarization,” 2023.`, available [here](https://arxiv.org/abs/2310.13025).\n","* `Problem.MONO_LABEL_CLASSIFICATION`: the model prediction associates one class to each time frame"]},{"cell_type":"markdown","metadata":{"id":"wTY4-nT2TIbM"},"source":["To apply the model on the audio file, we wrap it into an `Inference` instance:"]},{"cell_type":"code","execution_count":10,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":657},"executionInfo":{"elapsed":1614,"status":"ok","timestamp":1704807131091,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"vKcaevu8TIbN","outputId":"e020fdb9-3c92-4f76-fcec-5053c1842d19"},"outputs":[{"data":{"image/png":"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JspDAQAAAAAAWRC0AAAAAAAAsiBoAQAAAAAAZEHQAgAAAAAAyMJUQYtf/uVfjvve975xySWXxOMf//j467/+66bHBWTqx3/8x6MoinX/99CHPrTtYQEJveMd74jnPOc5ceDAgSiKIt70pjet+/2yLOPVr3513Ote94rdu3fH05/+9PjEJz7RzmCBJC50H3jRi1503vzgWc96VjuDBZL46Z/+6fjKr/zK2Lt3b1xzzTXx3Oc+Nz72sY+t+5577rknXvayl8WVV14Ze/bsiW/91m+Nz3/+8y2NGGjaxdwHnvrUp543J/in//SftjRioGmvfe1r48Ybb4yVlZVYWVmJJz7xifHmN7+5/v2m5gITBy1+93d/N37gB34gbrrppnjve98bj3rUo+KZz3xmfOELX5j45MBievjDHx633XZb/X/vfOc72x4SkNDx48fjUY96VPzyL//yhr//Mz/zM/GLv/iL8Su/8ivxV3/1V3HZZZfFM5/5zLjnnnvmPFIglQvdByIinvWsZ62bH7zhDW+Y4wiB1N7+9rfHy172svjLv/zL+NM//dM4c+ZMPOMZz4jjx4/X3/P93//98Yd/+IfxX//rf423v/3tcfjw4fiWb/mWFkcNNOli7gMRES95yUvWzQl+5md+pqURA0274YYb4t/8m38T73nPe+Ld7353PO1pT4tv+qZvig9/+MMR0dxcoCjLspzkBx7/+MfHV37lV8Yv/dIvRUTEcDiMgwcPxstf/vL44R/+4YkHACyWH//xH483velN8f73v7/toQAtKIoi3vjGN8Zzn/vciFjLsjhw4EC88pWvjB/8wR+MiIgjR47EtddeG6973evi+c9/foujBVI49z4QsZZpcffdd5+XgQEsry9+8YtxzTXXxNvf/vZ4ylOeEkeOHImrr746Xv/618fznve8iIj46Ec/Gg972MPiXe96VzzhCU9oecRA0869D0SsZVo8+tGPjp//+Z9vd3DA3Ozfvz9+9md/Np73vOc1NheYKNPi9OnT8Z73vCee/vSnnz1ApxNPf/rT413vetckhwIW2Cc+8Yk4cOBA3P/+949/+A//Ydx6661tDwloyac//em4/fbb180N9u3bF49//OPNDWCbedvb3hbXXHNNPOQhD4mXvvSlceedd7Y9JCChI0eORMTaQkVExHve8544c+bMujnBQx/60Lj3ve9t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","text/plain":[""]},"execution_count":10,"metadata":{},"output_type":"execute_result"}],"source":["from pyannote.audio import Inference\n","inference = Inference(model, step=2.5)\n","output = inference(AUDIO_FILE)\n","output"]},{"cell_type":"markdown","metadata":{"id":"MoqfhoX_TIbO"},"source":["For each of the 9 positions of the 10s window, the model outputs a 3-dimensional vector every 17ms (589 frames for 10 seconds), corresponding to the probabilities that each of (up to) 3 speakers is active. "]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":196,"status":"ok","timestamp":1704807141814,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"JObvduJMTIbO","outputId":"af45591c-c30d-401a-8906-db029140cea2"},"outputs":[{"data":{"text/plain":["(9, 589, 3)"]},"execution_count":11,"metadata":{},"output_type":"execute_result"}],"source":["output.data.shape"]},{"cell_type":"markdown","metadata":{"id":"Zdk-iqOaTIbQ"},"source":["## Processing a file from memory\n","\n","In case the audio file is not stored on disk, pipelines can also process audio provided as a `{\"waveform\": ..., \"sample_rate\": ...}` dictionary."]},{"cell_type":"code","execution_count":12,"metadata":{"executionInfo":{"elapsed":229,"status":"ok","timestamp":1704807145587,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"oFQrkl01TIbQ"},"outputs":[{"name":"stdout","output_type":"stream","text":["type(waveform)=\n","waveform.shape=torch.Size([1, 480000])\n","waveform.dtype=torch.float32\n"]}],"source":["import torchaudio\n","waveform, sample_rate = torchaudio.load(AUDIO_FILE)\n","\n","print(f\"{type(waveform)=}\")\n","print(f\"{waveform.shape=}\")\n","print(f\"{waveform.dtype=}\")\n","\n","audio_in_memory = {\"waveform\": waveform, \"sample_rate\": sample_rate}"]},{"cell_type":"code","execution_count":13,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":657},"executionInfo":{"elapsed":1904,"status":"ok","timestamp":1704807149946,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"j2zi1CzHTIbR","outputId":"fb8ac3d0-c9f0-4b0a-c01f-a10612bdf254"},"outputs":[{"data":{"image/png":"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JspDAQAAAAAAWRC0AAAAAAAAsiBoAQAAAAAAZEHQAgAAAAAAyMJUQYtf/uVfjvve975xySWXxOMf//j467/+66bHBWTqx3/8x6MoinX/99CHPrTtYQEJveMd74jnPOc5ceDAgSiKIt70pjet+/2yLOPVr3513Ote94rdu3fH05/+9PjEJz7RzmCBJC50H3jRi1503vzgWc96VjuDBZL46Z/+6fjKr/zK2Lt3b1xzzTXx3Oc+Nz72sY+t+5577rknXvayl8WVV14Ze/bsiW/91m+Nz3/+8y2NGGjaxdwHnvrUp543J/in//SftjRioGmvfe1r48Ybb4yVlZVYWVmJJz7xifHmN7+5/v2m5gITBy1+93d/N37gB34gbrrppnjve98bj3rUo+KZz3xmfOELX5j45MBievjDHx633XZb/X/vfOc72x4SkNDx48fjUY96VPzyL//yhr//Mz/zM/GLv/iL8Su/8ivxV3/1V3HZZZfFM5/5zLjnnnvmPFIglQvdByIinvWsZ62bH7zhDW+Y4wiB1N7+9rfHy172svjLv/zL+NM//dM4c+ZMPOMZz4jjx4/X3/P93//98Yd/+IfxX//rf423v/3tcfjw4fiWb/mWFkcNNOli7gMRES95yUvWzQl+5md+pqURA0274YYb4t/8m38T73nPe+Ld7353PO1pT4tv+qZvig9/+MMR0dxcoCjLspzkBx7/+MfHV37lV8Yv/dIvRUTEcDiMgwcPxstf/vL44R/+4YkHACyWH//xH483velN8f73v7/toQAtKIoi3vjGN8Zzn/vciFjLsjhw4EC88pWvjB/8wR+MiIgjR47EtddeG6973evi+c9/foujBVI49z4QsZZpcffdd5+XgQEsry9+8YtxzTXXxNvf/vZ4ylOeEkeOHImrr746Xv/618fznve8iIj46Ec/Gg972MPiXe96VzzhCU9oecRA0869D0SsZVo8+tGPjp//+Z9vd3DA3Ozfvz9+9md/Np73vOc1NheYKNPi9OnT8Z73vCee/vSnnz1ApxNPf/rT413vetckhwIW2Cc+8Yk4cOBA3P/+949/+A//Ydx6661tDwloyac//em4/fbb180N9u3bF49//OPNDWCbedvb3hbXXHNNPOQhD4mXvvSlceedd7Y9JCChI0eORMTaQkVExHve8544c+bMujnBQx/60Lj3ve9t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","text/plain":[""]},"execution_count":13,"metadata":{},"output_type":"execute_result"}],"source":["output = inference(audio_in_memory)\n","output"]},{"cell_type":"markdown","metadata":{"id":"aB5QNx7lTIbS"},"source":["## Processing part of a file\n","\n","If needed, `Inference` can be used to process only part of a file:"]},{"cell_type":"code","execution_count":19,"metadata":{"id":"E0Pydt0VTIbT"},"outputs":[{"data":{"image/png":"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IQ95SFx11VUtrhpo0itf+cp4xzveEX/8x38ce/bsGfWmXl5ejl27dsXy8nK8/OUvj9e85jWxd+/eWFpaile96lVx5ZVXxpOf/OSWVw804Uz3gVtuuSXe8Y53xLd8y7fEeeedF5/85CfjB3/wB+NpT3taXH755S2vHmjC6173urj66qvj/ve/fxw+fDje8Y53xPXXXx/vec97Gv0sUFRVVW12cdddd138zM/8TNx+++3xmMc8Jt761reOyr2A+faCF7wgPvCBD8TBgwfjggsuiKc+9anxkz/5k3pTwhy7/vrr41/9q391r99/yUteEm9/+9ujqqq49tpr41d+5Vfirrvuiqc+9anxtre9LS677LIWVgukcLr7wC/90i/FNddcEx//+Mfjrrvuin379sWzn/3s+PEf//G48MILW1gtkEJRFKf8/V//9V+Pl770pRERcezYsXjta18bv/3bvx3Hjx+Pq666Kt72trdpDwVz4kz3gf3798eLXvSiuOmmm+LIkSOxsrIS/+7f/bt4/etfH0tLS1NeLZDCy1/+8njve98bt912WywvL8fll18eP/IjPxLf/M3fHBHNfRaYKLQAAAAAAABo2qZmWgAAAAAAAKQitAAAAAAAALIgtAAAAAAAALIgtAAAAAAAALIgtAAAAAAAALIgtAAAAAAAALIgtAAAAAAAALIgtAAAAAAAALIgtAAAAE7rpS99aVxzzTVtLwMAAFgAvbYXAAAAtKcoitP+82uvvTZ+4Rd+IaqqmtKKAACARSa0AACABXbbbbeNfv27v/u78YY3vCE+85nPjH5v9+7dsXv37jaWBgAALCDtoQAAYIFddNFFo/8tLy9HURQbfm/37t33ag/19Kc/PV71qlfFq1/96jj33HPjwgsvjF/91V+NI0eOxMte9rLYs2dPPOQhD4k/+7M/23Cum266Ka6++urYvXt3XHjhhfHiF7847rzzzin/iQEAgJwJLQAAgE37jd/4jTj//PPj7/7u7+JVr3pVfN/3fV98+7d/ezzlKU+Jj33sY/HsZz87XvziF8c999wTERF33XVXPOMZz4jHPvax8ZGPfCT+/M//PL74xS/Gd3zHd7T8JwEAAHIitAAAADbt0Y9+dLz+9a+Phz70ofG6170udu7cGeeff3684hWviIc+9KHxhje8IQ4ePBif/OQnIyLiuuuui8c+9rHxUz/1U/Hwhz88HvvYx8av/dqvxfve9774x3/8x5b/NAAAQC7MtAAAADbt8ssvH/262+3GeeedF4961KNGv3fhhRdGRMSXvvSliIj4xCc+Ee973/tOOR/jlltuicsuuyzxigEAgFkgtAAAADZt27ZtG/7/oig2/F5RFBERUZZlRETcfffd8dznPjf+03/6T/c61sUXX5xwpQAAwCwRWgAAAMk97nGPiz/8wz+MBz7wgdHr+c8QAADg1My0AAAAknvlK18ZX/7yl+OFL3xhfPjDH45bbrkl3vOe98TLXvayGAwGbS8PAADIhNACAABIbt++ffHBD34wBoNBPPvZz45HPepR8epXvzrOOeec6HT8ZwkAALCmqKqqansRAAAAAAAAHmkCAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACyILQAAAAAAACy8P8DwJDOCD5+uAYAAAAASUVORK5CYII=","text/plain":[""]},"execution_count":19,"metadata":{},"output_type":"execute_result"}],"source":["from pyannote.core import Segment\n","output = inference.crop(audio_in_memory, Segment(0, 20))\n","output"]},{"cell_type":"markdown","metadata":{"id":"K_Z-ciLaTIbU"},"source":["## Offline use\n","\n","Gating models allows [me](https://herve.niderb.fr) to know a bit more about `pyannote.audio` user base and eventually help me write grant proposals to make `pyannote.audio` even better. Please fill this form as precisely as possible.\n","\n","For instance, before gating `pyannote/segmentation`, I had no idea that so many people were relying on it in production. Hint: sponsors are more than welcome! maintaining open source libraries is time consuming.\n","\n","That being said: this whole authentication process does not prevent you from using official `pyannote.audio` models offline (i.e. without going through the authentication process in every `docker run ...` or whatever you are using in production).\n","\n","* Step 1: download the `pytorch_model.bin` model\n","\n","![](assets/download-model.png)\n","\n","* Step 2: load the model"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"t_kZgFSSTIbV"},"outputs":[],"source":["# look ma: no hands!\n","offline_model = Model.from_pretrained(\"pytorch_model.bin\")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"wBkIFwR-TIbV"},"outputs":[],"source":["# just checking weights are the same...\n","import torch\n","for weights, offline_weights in zip(model.parameters(), offline_model.parameters()):\n"," assert torch.equal(weights, offline_weights)"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"T4","provenance":[]},"kernelspec":{"display_name":"Python 3","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.13"},"vscode":{"interpreter":{"hash":"36a3a48a52702f18671693adf589423ec3f7db45d50f6ee539f1b0696bb58d43"}},"widgets":{"application/vnd.jupyter.widget-state+json":{"01a79756e1104be0bcbe1d233677d605":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"09ee64808a5c431b928066a4cb287a78":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"0c537fef94bd4a3d8c42d981a70ea35b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ecbb880cf0044404ab9bfc5995656807","placeholder":"","style":"IPY_MODEL_79287ffea49a4e4a80191b1157de15cc","value":"\nPro Tip: If you don't already have one, you can create a dedicated\n'notebooks' token with 'write' access, that you can then easily reuse for all\nnotebooks. "}},"0e04a45510f346b8ab3c465b10ccdfd2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_bf5c88fe90f0462b95aa8a81467c1e9d","placeholder":"","style":"IPY_MODEL_09ee64808a5c431b928066a4cb287a78","value":"Connecting..."}},"1a30ac8b519948bbad72886049b53d55":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"2b91f4b11d5848c0b6795b649bc2d7bc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_57cf64e9c70e4057a76c2f3fb1e9b191","placeholder":"","style":"IPY_MODEL_5e90e4818f1f43f2aa4714e0e40dc15d","value":"Your token has been saved to /root/.cache/huggingface/token"}},"2d1965df902b4b7eb6e4e28e44d6e32b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"Add token as git credential?","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_416ffb7703b1404ab1c19c6b1ecafb4c","style":"IPY_MODEL_5be7421c575d41128d0675dc9abbc196","value":true}},"416ffb7703b1404ab1c19c6b1ecafb4c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"47da80658de14604a7cc5268b951c172":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"49cb317b141a43b7b8ce342e2d62ab03":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"52a4a1aab39741f2a0499428f07a4c25":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_01a79756e1104be0bcbe1d233677d605","placeholder":"","style":"IPY_MODEL_990375a830eb4cd79c69ad78b9ac685b","value":"Token is valid (permission: write)."}},"53919e13e42441d9b8cf5eb4f2effe96":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"57cf64e9c70e4057a76c2f3fb1e9b191":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5be7421c575d41128d0675dc9abbc196":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5e90e4818f1f43f2aa4714e0e40dc15d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"73915caf6d1042ca9a27853986217ae2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"PasswordModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"PasswordModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"PasswordView","continuous_update":true,"description":"Token:","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_47da80658de14604a7cc5268b951c172","placeholder":"","style":"IPY_MODEL_c7fbfffbbc304f0ba025e03beb8f638a","value":""}},"79287ffea49a4e4a80191b1157de15cc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"79d55946b3764666a0b57a72722f6c19":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":"center","align_self":null,"border":null,"bottom":null,"display":"flex","flex":null,"flex_flow":"column","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50%"}},"8b3353af24074ce5b5d2d9b162c61062":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"988c83c85f7d44d0be949de6eedcf977":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"990375a830eb4cd79c69ad78b9ac685b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a73cecb8608f491e8f996c5114df4d0f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_52a4a1aab39741f2a0499428f07a4c25","IPY_MODEL_f23cc133109c4ecb9b383f118bcc71aa","IPY_MODEL_2b91f4b11d5848c0b6795b649bc2d7bc","IPY_MODEL_b437981acb894f97ad45daaebe2734c7"],"layout":"IPY_MODEL_79d55946b3764666a0b57a72722f6c19"}},"abc23089f4ef4d2a9f8a104fb1dba14a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"b2e03b10050d46548932f429bcc18d81":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"Login","disabled":false,"icon":"","layout":"IPY_MODEL_8b3353af24074ce5b5d2d9b162c61062","style":"IPY_MODEL_cd40e31c191044b7a0f8fa4694ad6380","tooltip":""}},"b437981acb894f97ad45daaebe2734c7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_fb027db34fd740c2a4758d650ae3f73c","placeholder":"","style":"IPY_MODEL_1a30ac8b519948bbad72886049b53d55","value":"Login successful"}},"bc10c6804346449b8e349728a1acb8d2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_988c83c85f7d44d0be949de6eedcf977","placeholder":"","style":"IPY_MODEL_53919e13e42441d9b8cf5eb4f2effe96","value":" Copy a token from your Hugging Face\ntokens page and paste it below. Immediately click login after copying\nyour token or it might be stored in plain text in this notebook file. "}},"bf5c88fe90f0462b95aa8a81467c1e9d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c7fbfffbbc304f0ba025e03beb8f638a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"cd40e31c191044b7a0f8fa4694ad6380":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":""}},"ecbb880cf0044404ab9bfc5995656807":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f23cc133109c4ecb9b383f118bcc71aa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_49cb317b141a43b7b8ce342e2d62ab03","placeholder":"","style":"IPY_MODEL_abc23089f4ef4d2a9f8a104fb1dba14a","value":"Your token has been saved in your configured git credential helpers (store)."}},"fb027db34fd740c2a4758d650ae3f73c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}}}},"nbformat":4,"nbformat_minor":0}
diff --git a/tutorials/applying_a_pipeline.ipynb b/tutorials/applying_a_pipeline.ipynb
index c1080071d..945caab4e 100644
--- a/tutorials/applying_a_pipeline.ipynb
+++ b/tutorials/applying_a_pipeline.ipynb
@@ -1,400 +1 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Applying a pretrained pipeline\n",
- "\n",
- "In this tutorial, you will learn how to apply `pyannote.audio` pipelines on an audio file.\n",
- "\n",
- "A pipeline takes an audio file as input and returns a labeled temporal segmentation of the audio file. \n",
- "\n",
- "More precisely, it usually applies a pretrained model (= neural network) on the audio file, post-processes the output of the model, and returns its output as a [`pyannote.core.Annotation`](http://pyannote.github.io/pyannote-core/structure.html#annotation) instance. It should become clearer as you keep reading..."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Loading pipeline from 🤗 hub\n",
- "\n",
- "A bunch of pretrained pipelines are available on [🤗 Huggingface model hub](https://hf.co/models?other=pyannote-audio-pipeline) and can be listed by looking for the [`pyannote-audio-pipeline`](https://hf.co/models?other=pyannote-audio-pipeline) tag."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "['pyannote/overlapped-speech-detection',\n",
- " 'pyannote/speaker-diarization',\n",
- " 'pyannote/speaker-segmentation',\n",
- " 'pyannote/voice-activity-detection']"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from huggingface_hub import HfApi\n",
- "available_pipelines = [p.modelId for p in HfApi().list_models(filter=\"pyannote-audio-pipeline\")]\n",
- "list(filter(lambda p: p.startswith(\"pyannote/\"), available_pipelines))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Official [pyannote.audio](https://github.com/pyannote/pyannote-audio) pipelines (i.e. those under the [`pyannote` organization](https://hf.co/pyannote) umbrella) are open-source, but gated. It means that you have to first accept users conditions on their respective Huggingface page to access the pretrained weights and hyper-parameters. Despite this initial process, those pipelines can perfectly be downloaded for later offline use: keep reading this tutorial until the end to learn how to do that.\n",
- "\n",
- "For instance, to load the speaker diarization pipeline used in this tutorial, you have to visit [hf.co/pyannote/speaker-diarization](https://hf.co/pyannote/speaker-diarization), accept the terms, visit [hf.co/pyannote/segmentation](https://hf.co/pyannote/segmentation) (used internally by the speaker diarization pipeline), accept the terms, and log in using `notebook_login` below:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "9466934e67254fe6a7ff67b727a3f3ab",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HTML(value=' "
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# we visualize [0, 30] time range\n",
- "from pyannote.core import notebook, Segment\n",
- "notebook.crop = Segment(0, 30)\n",
- "dia"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When available, the reference annotation can be visualized too, for comparison:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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lltuiSlTpkRExA033BBTpkyJjh07Rq9eveq8sdqmTZs444wzjtj+Aw88EAcPHozTTjutZluWZdG2bdvYuXNndO3atWb77NmzY+jQoXH11VdHlmU1P9T833r27HnU/iIiBgwYEF26dImzzjor3n333bjsssviL3/5yxE/Yf/h9j/8yffKysqaT8h37949ioqKjnpMU+v58vqC9NtQxlrd9o93HF1//fWxbNmyWLVqVfTp0+eYbQMAAAAALUPev3nRtVO7Jr3ky+DBg2Pfvn0117t37x5nnHFG9O7du8HfLDh48GAsXLgw7r777lqfXv/zn/8c/fv3j4cffrjObb73ve/FbbfdFldffXVePmF+7bXXxuHDh+P+++8/ruNHjRoVy5cvr7Xtt7/9bZx//vkREdGuXbsYPnx4nWOWL19ec0xTKyovb9JLvhhrRx9rEe+HLzNmzIhHH300nn766RgwYMBJ1wkAAAAANB95/+ZF6qqqquKLX/xiTJ06NYYOHRolJSWxdu3auOuuu2LChAnH3U6WZfWeo7+ioiJ+9atfxc6dO+OrX/1qlJWV1dr/hS98IR544IGYMWNGndveeOONUVRUVPNm8NVXX12zb9euXXX6KykpiU6dOtVbX5s2bWLmzJlx++23x3XXXRcdO3Y86v355je/GRdeeGHceeedMWHChHj88cfjd7/7XaxZs6bmmFmzZsW1114bI0aMiFGjRsVPf/rT2Lx5c0ybNu2obbdWxlr9jmesTZ8+PX7xi1/E448/HiUlJTX1lJWVRYcOHY7aPgAAAADQAmStzLvvvpvdeOON2bBhw7KysrKsY8eO2cCBA7Pvfe972dtvv51lWZb1798/u/fee4/Yxvz587OIqPfy1ltvZZ///Oezz372s/Xedt26dVlEZOvWrctee+21LCKyl156qdYxd999d1ZUVJQtXLgwy7LsiH3NnTs3y7Ise+aZZ7KIyHbu3Fmrnb1792Zdu3bN7rzzzuN6bH75y19mAwcOzNq2bZudffbZ2ZIlS+oc8+Mf/zjr379/1q5du2zYsGHZypUrj6vt1shYO7JjjbUj1TF//vzjah8AAAAAaN5yWZZljRuPAAAAAAAAHL+8/+YFAAAAAADAyRBetBKdO3c+4mX16tWFLo8WxFgDAAAAAE6W00a1Eps2bTrivtNOO82PIJM3xhoAAAAAcLKEFwAAAAAAQFKcNgoAAAAAAEiK8AIAAAAAAEjKKSd6w8OHD8ebb74ZJSUlkcvl8lkTAAAAAADQzGRZFtXV1dG7d+9o0+bkvjtxwuHFm2++GX379j2pzgEAAAAAgJZly5Yt0adPn5Nq44TDi5KSkpoiSktLT6oIAAAAAACgeduzZ0/07du3Jj84GSccXnxwqqjS0lLhBQAAAAAAEBGRl5+a8IPdAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUoQXAIk6tG1b7Ln7nji0bVuzaHdH9f742TObYkf1/ry2m0/NocbUtZbHsLXcT1o+Y5nm7khjuLHWM9CUTmYcm98BGp+5tvCEFwCJOlRZGdX33BuHKiubRbs7qvfHAyv+mfR/6s2hxtS1lsewtdxPWj5jmebuSGO4sdYz0JROZhyb3wEan7m28IQXAAAAAABAUoQXAAAAAABAUoQXAAAAAABAUk4pdAEAHN3hXbvjUFVVXttrTNXvvBc79x1o1D5OVPU77xW6hBYj5ec5H4wVWpqW/pql5TrWfJzvdRI0pXysy83vAI3H34WFJ7wASFzVlVcVuoQGuX7h2kKXQBPwPEPz4jVLS9Xc1kmQb+Z3AFoyp40CAAAAAACSIrwAAAAAAACSIrwAAAAAAACS4jcvABJXvuiRaDt4UN7ae++VvzXq+aH/7ysj4oyeJY3W/snYtLXaeYHzJOXnOR+MFVqalv6apeU61nyc73USNKV8rMvN7wCNx9+FhSe8AEhcmy5lUVRenrf2DnUpy1tb9Snp0Da6dmrXqH2cqJIObQtdQouR8vOcD8YKLU1Lf83Sch1rPs73OgmaUj7W5eZ3gMbj78LCc9ooAAAAAAAgKcILAAAAAAAgKcILAAAAAAAgKcILAAAAAAAgKcILgEQVVVREyaz/iaKKimbRbveS4vjqRadH95LivLabT82hxtS1lsewtdxPWj5jmebuSGO4sdYz0JROZhyb3wEan7m28HJZlmUncsM9e/ZEWVlZ7N69O0pLS/NdFwAAAAAA0IzkMzfwzQsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAAAAAACApwgsAWoVD27bFnrvviUPbthW6lBapqR9fzyfkl9cULcWO6v3xs2c2xY7q/c2iXQCgftanzdehysq8tSW8AKBVOFRZGdX33JvX/0T5j6Z+fD2fkF9eU7QUO6r3xwMr/tko4UVjtAsA1M/6tPk6tH173toSXgAAAAAAAEkRXgAAAAAAAEk5pdAFAEBTOrxrdxyqqip0GS3O4V27C9av5xNOXqFew9BYqt95L3buO5DX9gCApudvvubn8O49eWtLeAFAq1J15VWFLoE88nwCUJ/rF64tdAkAQB74m6/5qT58OG9tOW0UAAAAAACQFOEFAAAAAACQFOEFAAAAAACQFL95AUCrUr7okWg7eFChy2hx3nvlbwU5F6nnE/KjUK9haCz/95URcUbPkry1t2lrtd/RAIAC8Ddf89P2xbUR48flpS3hBQCtSpsuZVFUXl7oMlqcQ13KCtKv5xPyo1CvYWgsJR3aRtdO7fLaHgDQ9PzN1/y0KSvNX1t5awkAAAAAACAP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",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pyannote.database.util import load_rttm\n",
- "REFERENCE = f\"{ROOT_DIR}/tutorials/assets/sample.rttm\"\n",
- "reference = load_rttm(REFERENCE)[\"sample\"]\n",
- "\n",
- "# map hypothesized and reference speakers for visualization purposes\n",
- "pipeline.optimal_mapping(dia, reference)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Processing a file from memory\n",
- "\n",
- "In case the audio file is not stored on disk, pipelines can also process audio provided as a `{\"waveform\": ..., \"sample_rate\": ...}` dictionary. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "type(waveform)=\n",
- "waveform.shape=torch.Size([1, 480000])\n",
- "waveform.dtype=torch.float32\n"
- ]
- }
- ],
- "source": [
- "import torchaudio\n",
- "waveform, sample_rate = torchaudio.load(AUDIO_FILE)\n",
- "\n",
- "print(f\"{type(waveform)=}\")\n",
- "print(f\"{waveform.shape=}\")\n",
- "print(f\"{waveform.dtype=}\")\n",
- "\n",
- "audio_in_memory = {\"waveform\": waveform, \"sample_rate\": sample_rate}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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bPHixalUKu2+mpqaunpZQCdat25dzjzzzIwcOTKVSiWrVq1qd321Ws3ixYszcuTIDBw4MKeddlr+8pe/dM1igU7zVnvB3Llz95kRTj755K5ZLFBzS5Ysyfvf//7U1dVl2LBhmTlzZh566KF2tzETQM/3dvYCMwH0bMuWLctxxx2X+vr61NfXZ9KkSfntb3/bdn2t5oEOx4uVK1dm4cKF+epXv5r7778/H/7whzN9+vRs3ry5w3cOdF/HHHNMtm7d2va1adOmrl4S0In27NmT448/Ptdcc80bXr906dJcffXVueaaa3LvvfemqakpU6ZMybPPPvsOrxToTG+1FyTJtGnT2s0It9566zu4QqAzrV27NhdccEHuueee3H777XnppZcyderU7Nmzp+02ZgLo+d7OXpCYCaAnGzVqVL71rW9lw4YN2bBhQ04//fTMmDGjLVDUah6oVKvVakd+YOLEiTnhhBOybNmytmPjx4/PzJkzs2TJkg7dOdA9LV68OKtWrcrGjRu7eilAF6hUKrn55pszc+bMJK/+RcXIkSOzcOHCXHrppUmS1tbWDB8+PN/+9rdz/vnnd+Fqgc7y+r0gefWvLHft2rXPKzKAnumf//xnhg0blrVr1+YjH/mImQB6qdfvBYmZAHqjxsbGfOc738m8efNqNg906JUXL7zwQu67775MnTq13fGpU6fmrrvu6sipgG7u4YcfzsiRIzN27Nh8+tOfzt///veuXhLQRR577LFs27at3XzQv3//nHrqqeYD6IXWrFmTYcOG5aijjsr8+fOzffv2rl4S0El2796d5NVfViRmAuitXr8XvMZMAL3Dyy+/nBUrVmTPnj2ZNGlSTeeBDsWLHTt25OWXX87w4cPbHR8+fHi2bdvWoTsGuq+JEyfmhhtuyG233Zaf/OQn2bZtW0455ZTs3Lmzq5cGdIHXZgDzATB9+vTceOONueOOO/Ld73439957b04//fS0trZ29dKAGqtWq7nooovyoQ99KBMmTEhiJoDe6I32gsRMAL3Bpk2bMnjw4PTv3z8LFizIzTffnKOPPrqm80Df/VlYpVJpd7lare5zDOi5pk+f3vb9sccem0mTJuXwww/P9ddfn4suuqgLVwZ0JfMBMHv27LbvJ0yYkJNOOiljxozJb37zm5x11llduDKg1i688MI88MADufPOO/e5zkwAvcd/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",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "vad = Pipeline.from_pretrained(\"pyannote/voice-activity-detection\", use_auth_token=True)\n",
- "vad(audio_in_memory)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Offline use\n",
- "\n",
- "Gating models and pipelines allows [me](https://herve.niderb.fr) to know a bit more about `pyannote.audio` user base and eventually help me write grant proposals to make `pyannote.audio` even better. Please fill this form as precisely as possible. \n",
- "\n",
- "For instance, before gating `pyannote/speaker-diarization`, I had no idea that so many people were relying on it in production. Hint: sponsors are more than welcome! maintaining open source libraries is time consuming.\n",
- "\n",
- "That being said: this whole authentication process does not prevent you from using official `pyannote.audio` models and pipelines offline (i.e. without going through the authentication process in every `docker run ...` or whatever you are using in production).\n",
- "\n",
- "* Step 1: download `config.yaml` of [`pyannote/voice-activity-detection`](https://hf.co/pyannote/voice-activity-detection) pipeline\n",
- "\n",
- "![](assets/download-pipeline.png)\n",
- "\n",
- "* Step 2: download the `pytorch_model.bin` model\n",
- "\n",
- "![](assets/download-model.png)\n",
- "\n",
- "* Step 3: edit `config.yaml` to point to the local model\n",
- "\n",
- "```diff\n",
- "pipeline:\n",
- " name: pyannote.audio.pipelines.VoiceActivityDetection\n",
- " params:\n",
- "- segmentation: pyannote/segmentation@Interspeech2021\n",
- "+ segmentation: pytorch_model.bin\n",
- "\n",
- "params:\n",
- " min_duration_off: 0.09791355693027545\n",
- " min_duration_on: 0.05537587440407595\n",
- " offset: 0.4806866463041527\n",
- " onset: 0.8104268538848918\n",
- "```\n",
- "\n",
- "* Step 4: load the pipeline"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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bPHixalUKu2+mpqaunpZQCdat25dzjzzzIwcOTKVSiWrVq1qd321Ws3ixYszcuTIDBw4MKeddlr+8pe/dM1igU7zVnvB3Llz95kRTj755K5ZLFBzS5Ysyfvf//7U1dVl2LBhmTlzZh566KF2tzETQM/3dvYCMwH0bMuWLctxxx2X+vr61NfXZ9KkSfntb3/bdn2t5oEOx4uVK1dm4cKF+epXv5r7778/H/7whzN9+vRs3ry5w3cOdF/HHHNMtm7d2va1adOmrl4S0In27NmT448/Ptdcc80bXr906dJcffXVueaaa3LvvfemqakpU6ZMybPPPvsOrxToTG+1FyTJtGnT2s0It9566zu4QqAzrV27NhdccEHuueee3H777XnppZcyderU7Nmzp+02ZgLo+d7OXpCYCaAnGzVqVL71rW9lw4YN2bBhQ04//fTMmDGjLVDUah6oVKvVakd+YOLEiTnhhBOybNmytmPjx4/PzJkzs2TJkg7dOdA9LV68OKtWrcrGjRu7eilAF6hUKrn55pszc+bMJK/+RcXIkSOzcOHCXHrppUmS1tbWDB8+PN/+9rdz/vnnd+Fqgc7y+r0gefWvLHft2rXPKzKAnumf//xnhg0blrVr1+YjH/mImQB6qdfvBYmZAHqjxsbGfOc738m8efNqNg906JUXL7zwQu67775MnTq13fGpU6fmrrvu6sipgG7u4YcfzsiRIzN27Nh8+tOfzt///veuXhLQRR577LFs27at3XzQv3//nHrqqeYD6IXWrFmTYcOG5aijjsr8+fOzffv2rl4S0El2796d5NVfViRmAuitXr8XvMZMAL3Dyy+/nBUrVmTPnj2ZNGlSTeeBDsWLHTt25OWXX87w4cPbHR8+fHi2bdvWoTsGuq+JEyfmhhtuyG233Zaf/OQn2bZtW0455ZTs3Lmzq5cGdIHXZgDzATB9+vTceOONueOOO/Ld73439957b04//fS0trZ29dKAGqtWq7nooovyoQ99KBMmTEhiJoDe6I32gsRMAL3Bpk2bMnjw4PTv3z8LFizIzTffnKOPPrqm80Df/VlYpVJpd7lare5zDOi5pk+f3vb9sccem0mTJuXwww/P9ddfn4suuqgLVwZ0JfMBMHv27LbvJ0yYkJNOOiljxozJb37zm5x11llduDKg1i688MI88MADufPOO/e5zkwAvcd/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",
- "text/plain": [
- ""
- ]
- },
- "execution_count": 21,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# look ma: no hands!\n",
- "offline_vad = Pipeline.from_pretrained(\"config.yaml\")\n",
- "offline_vad(audio_in_memory)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "metadata": {},
- "outputs": [],
- "source": [
- "# just checking output is the same\n",
- "assert (vad(audio_in_memory) == offline_vad(audio_in_memory))"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3.9.13 ('pyannote-mps')",
- "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.9.13"
- },
- "vscode": {
- "interpreter": {
- "hash": "36a3a48a52702f18671693adf589423ec3f7db45d50f6ee539f1b0696bb58d43"
- }
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
+{"cells":[{"cell_type":"markdown","metadata":{},"source":["****"]},{"cell_type":"markdown","metadata":{"id":"uiNbotxCeq4b"},"source":["# Applying a pretrained pipeline\n","\n","In this tutorial, you will learn how to apply `pyannote.audio` pipelines on an audio file.\n","\n","A pipeline takes an audio file as input and returns a labeled temporal segmentation of the audio file.\n","\n","More precisely, it usually applies a pretrained model (= neural network) on the audio file, post-processes the output of the model, and returns its output as a [`pyannote.core.Annotation`](http://pyannote.github.io/pyannote-core/structure.html#annotation) instance. It should become clearer as you keep reading..."]},{"cell_type":"markdown","metadata":{"id":"z_4VUpZxesS2"},"source":["## Tutorial setup"]},{"cell_type":"markdown","metadata":{"id":"gbonpHYte3FC"},"source":["### `Google Colab` setup\n"]},{"cell_type":"markdown","metadata":{"id":"hxhhcj8Fe7v7"},"source":["If you are running this tutorial on `Colab`, execute the following commands in order to setup `Colab` environment. These commands will install `pyannote.audio`, and download resources used in this tutorial."]},{"cell_type":"code","execution_count":4,"metadata":{"executionInfo":{"elapsed":17283,"status":"ok","timestamp":1704808539241,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"NFdANMKsfD1p"},"outputs":[],"source":["!pip install -qq pyannote.audio==3.1.1\n","!pip install -qq ipython==7.34.0\n","!wget -q \"https://github.com/pyannote/pyannote-audio/raw/develop/tutorials/assets/sample.wav\"\n","!wget -q \"https://github.com/pyannote/pyannote-audio/raw/develop/tutorials/assets/sample.rttm\"\n","!wget -q -P ./assets/ \"https://github.com/pyannote/pyannote-audio/blob/develop/tutorials/assets/download-model.png\"\n","!wget -q -P ./assets/ \"https://github.com/pyannote/pyannote-audio/blob/develop/tutorials/assets/download-pipeline.png\""]},{"cell_type":"markdown","metadata":{"id":"PScZ6o_9gkfo"},"source":["⚠ Restart the runtime (Runtime > Restart session)."]},{"cell_type":"code","execution_count":13,"metadata":{"executionInfo":{"elapsed":458,"status":"ok","timestamp":1704809048938,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"ZU_QIx1UhcV6"},"outputs":[],"source":["AUDIO_FILE = \"sample.wav\"\n","REFERENCE = \"sample.rttm\""]},{"cell_type":"markdown","metadata":{"id":"d-qKbc9shI6o"},"source":["### Non `Google Colab` setup"]},{"cell_type":"markdown","metadata":{"id":"0KEh-IGqho6F"},"source":["If you are not using Colab, clone `pyannote.audio` [GitHub repository](https://github.com/pyannote/pyannote-audio) and update ROOT_DIR accordingly"]},{"cell_type":"code","execution_count":10,"metadata":{"id":"DuoohiL6hOiJ"},"outputs":[],"source":["ROOT_DIR = \"/pyannote-audio\"\n","AUDIO_FILE = f\"{ROOT_DIR}/tutorials/assets/sample.wav\"\n","REFERENCE = f\"{ROOT_DIR}/tutorials/assets/sample.rttm\""]},{"cell_type":"markdown","metadata":{"id":"yA9JsY84eq4e"},"source":["## Loading pipeline from 🤗 hub\n","\n","A bunch of pretrained pipelines are available on [🤗 Huggingface model hub](https://hf.co/models?other=pyannote-audio-pipeline) and can be listed by looking for the [`pyannote-audio-pipeline`](https://hf.co/models?other=pyannote-audio-pipeline) tag."]},{"cell_type":"code","execution_count":2,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2323,"status":"ok","timestamp":1704808592263,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"eAXGgYt8eq4f","outputId":"86772355-3bf0-42e5-c478-2d35a80853e9"},"outputs":[{"data":{"text/plain":["['pyannote/overlapped-speech-detection',\n"," 'pyannote/speaker-diarization',\n"," 'pyannote/speaker-segmentation',\n"," 'pyannote/voice-activity-detection',\n"," 'pyannote/speaker-diarization-3.0',\n"," 'pyannote/speaker-diarization-3.1']"]},"execution_count":2,"metadata":{},"output_type":"execute_result"}],"source":["from huggingface_hub import HfApi\n","available_pipelines = [p.modelId for p in HfApi().list_models(filter=\"pyannote-audio-pipeline\")]\n","list(filter(lambda p: p.startswith(\"pyannote/\"), available_pipelines))"]},{"cell_type":"markdown","metadata":{"id":"fry3qMrJeq4h"},"source":["Official [pyannote.audio](https://github.com/pyannote/pyannote-audio) pipelines (i.e. those under the [`pyannote` organization](https://hf.co/pyannote) umbrella) are open-source, but gated. It means that you have to first accept users conditions on their respective Huggingface page to access the pretrained weights and hyper-parameters. Despite this initial process, those pipelines can perfectly be downloaded for later offline use: keep reading this tutorial until the end to learn how to do that.\n","\n","For instance, to load the speaker diarization pipeline used in this tutorial, you have to visit [hf.co/pyannote/speaker-diarization](https://hf.co/pyannote/speaker-diarization), accept the terms, visit [hf.co/pyannote/segmentation](https://hf.co/pyannote/segmentation) (used internally by the speaker diarization pipeline), accept the terms, and log in using `notebook_login` below:"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":145,"referenced_widgets":["6fe26270a8794dea85b9ac8dedde6353","f9969c7acd834359bd67e83c31b82c0b","ef6be001daaa465598bdf20c304bae0b","a8e61b300a324911b1d3babf6b1ebac1","45c2352ba41b46288c8ba74c661e1f85","78f428e1d8ac4c78bd84d208a78b1fe5","9d7b5e47af9448c98a2a434f02b54633","253408a6cab947c7b9ae40a14e255328","a435c85128f148cb80152d03825710e2","90533da4fc1341a28bc247bc9fbbbe9e","6556790d1997431a8476447297e3f595","5253489738b249f69b30f1c84884a95a","3f500b1182a945c3b8b546b1bd04f98e","c3b3069a93994e55b993cab04c066f17","f77186e2976d4a7daa798fd9f0f7b4cb","7ffa4930e0a7421e9464abff87bbde7f","1dd6bfb824ba4919ba392e0d4cd5ac82","7c23cd10c573438c840148ba1afaa5f3","bc4d3f45eaf04cccb7a655ef87d7a927","36f60aa99ea84b739f066c6ee216f159","5033834cc66f49efaa16b240245ec1d3","0b127e22a6de4339aecc1e76a6719d7f","8a7afaf126ac49dcaf24d64c2d918086","1b5f49211db54348924a05482ca7379d","1f3be36a57074214a5f92e08165e41be","275642719b694328ad3b0fb06b53e42a","ae378b480ed747438bcbe147a7e8d277","b22a1d21940e4995b72642b003ae1301","58e423b86bf349aa89fc81a2b0d0f697","a3ebe0f0e6e44522a2545db0ed47af62","dc9c065286e544df921e5bc4a51faf64","16244ab1dc76493d9fafad80a9b65700"]},"executionInfo":{"elapsed":418,"status":"ok","timestamp":1704808601143,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"IdXJumYveq4i","outputId":"cb87e106-b30f-4ec8-e726-d797ca98698b"},"outputs":[],"source":["from huggingface_hub import notebook_login\n","notebook_login()"]},{"cell_type":"markdown","metadata":{"id":"ym2671Fweq4j"},"source":["Once authenticated, you can load the pipeline (and the internal models)..."]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":266,"referenced_widgets":["5a2a95f41f014663b5d131635844e3c8","f8df65e5ad6444648681230f415b8d08","17e14569a3f74cbf991b582c27fdf280","4e0ca7f084804d30a89cb9dc439b6cdc","d304f698c6f34f3692548267ca0aba47","3f69734124f7449da0efffbbfd1153fe","686b58e0ccee468f938ea5659f3a9623","e98b1f7ec5e04e748069340fa2fcec2d","616f35eccdd34bcdb5c9f700103ff538","185457147fe44751a1c6e7ae6ad23570","b02b253086e34249ae1d896a75a08960","0b191fb0d6db4f1a98a641dc50445f1e","4a589ea883de4409b7a8275127747fa7","b5f4829158cf4a5c8350966d8eacbf60","7cab72ad0ace45d58d6954021082ace7","5440ac4cffa0438c99c0daeca27a4087","0d0dfc2576784812b6abf673752fa812","84e416e01cfa4a79b0294a44cfd77f32","b33021db4313476ab8bcb85bb1b190d7","6d5431955c09424a96e825aa9bba1b62","54eacc5604f64f658617cde596a728dd","1749a0e7fc6847849ab40ac7f764b699","ff048516fdba44a48a69c51a82aa7aaa","775611277f1948a5ab95641c4e92ff2e","c955f8144b46451493474e02726b5deb","c9eeb26bd5e049f89205e494d54e3818","d4d428f0b0c44756a128adae747716d2","70d672feec1c452aa49a40a3b8c1a4f0","e8b3188ee4934ab4becbc431fc4ccb0b","754a843fd634446b8d246998eaded1fa","1e53e26668aa4f8dabdd6973b79b5b9f","cf5ae82d36384a728d8ca893cc27392b","5cc77ca8ba304ad88342ed6ced6c6a4a","6412ef268e11484f8bbcdb510f66ee21","a987408c2f994329a9a80208b22e3c52","9446f61936c4421d9610464984890353","a80c0fb6a1254bb9a00741c1346b9d9a","b55e95f31216480fa6c81bd1b57ad729","517a1b1faec045f7847ca84f0538f4e1","008a47e4d1174b188e75232fed325398","30864d7b4d074994ba643c73875a67b8","b852998433e24f7fad1fe27e249085f9","46ac2d0bfedc47c8836e8dde0fc91662","58b140d0453a4a219bc64e0152cc5c5e","3bb60a8db7c0406f8debdc8dd88bcdb4","bf644ae3e2894787bb416740749200cd","0fccc53081a34d58a46912d1ceae0533","39cd6fe37b6f4476b6032c29f026d570","87a0e712c0b045449b98ee368c62fff2","2be7c1f5fe32462f8d1cd7ea57cfbf3a","d6135ce9cfaa4f8496a70cee4f1e89a7","00ac431507a54c0d9a41244013b1c0f3","6f318bc3e900434a9134a79e4057f666","7580595b498a4c50b748af9df67132e2","3f1d750804a54d78a6abff2623441360"]},"executionInfo":{"elapsed":30028,"status":"ok","timestamp":1704808674003,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"1NihzPUPeq4k","outputId":"04275648-23ef-4453-9bf4-8d8dfadd99e0"},"outputs":[],"source":["from pyannote.audio import Pipeline\n","pipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\", use_auth_token=True)"]},{"cell_type":"markdown","metadata":{"id":"cZhtRXAHeq4l"},"source":["## Processing a file from disk"]},{"cell_type":"markdown","metadata":{"id":"X7hQRbzeeq4m"},"source":["... and apply it to an audio file. \n","\n","The pipeline will automatically use GPUs when available.\n","On CPU it might take a long while (up to 10x RT)."]},{"cell_type":"code","execution_count":9,"metadata":{"executionInfo":{"elapsed":82100,"status":"ok","timestamp":1704808982782,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"digxFLaueq4n"},"outputs":[],"source":["dia = pipeline(AUDIO_FILE)"]},{"cell_type":"markdown","metadata":{"id":"9WTsQVjjeq4o"},"source":["## Visualizing the output\n","\n","Most pipelines return a [`pyannote.core.Annotation`](http://pyannote.github.io/pyannote-core/structure.html#annotation) instance..."]},{"cell_type":"code","execution_count":10,"metadata":{"executionInfo":{"elapsed":1079,"status":"ok","timestamp":1704809008347,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"Ch7SaA4-eq4p"},"outputs":[],"source":["from pyannote.core import Annotation\n","assert isinstance(dia, Annotation)"]},{"cell_type":"markdown","metadata":{"id":"T4BsOhmXeq4p"},"source":["... whose [API](https://pyannote.github.io/pyannote-core/structure.html#annotation) you can use to print the result:"]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":610,"status":"ok","timestamp":1704809011691,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"OzEPn1hqeq4p","outputId":"e61015ad-c0df-4890-acc6-f65c87d7c30d"},"outputs":[{"name":"stdout","output_type":"stream","text":[" 6.7 7.2 SPEAKER_01\n"," 7.2 7.2 SPEAKER_02\n"," 7.6 8.3 SPEAKER_01\n"," 8.3 9.9 SPEAKER_02\n"," 9.9 10.9 SPEAKER_01\n","10.5 14.7 SPEAKER_02\n","10.9 11.0 SPEAKER_00\n","14.3 17.9 SPEAKER_00\n","18.0 21.5 SPEAKER_02\n","18.2 18.4 SPEAKER_00\n","21.8 28.5 SPEAKER_00\n","27.9 30.0 SPEAKER_02\n"]}],"source":["for speech_turn, track, speaker in dia.itertracks(yield_label=True):\n"," print(f\"{speech_turn.start:4.1f} {speech_turn.end:4.1f} {speaker}\")"]},{"cell_type":"markdown","metadata":{"id":"PqiV2D2geq4q"},"source":["If you happen to be running this example in a _Jupyter notebook_, `dia` can be [visualized directly](http://pyannote.github.io/pyannote-core/visualization.html):"]},{"cell_type":"code","execution_count":12,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":220},"executionInfo":{"elapsed":841,"status":"ok","timestamp":1704809016036,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"80D-4Yhreq4r","outputId":"ee02c234-ebc6-40f3-94b1-0838fac05f81"},"outputs":[{"data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAABi8AAADyCAYAAAA1MlYeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAheUlEQVR4nO3df5TVdZ0/8Ocw/FznhwIyIzogpqIYqFkhZeaigsjx+INstdVETU8eZI9ayeqSaKa29G1LV+0n/tgQdS21snWtXDAL1NWWCCs2WVp1lUEHGX7UgMJ8//AwOUHAwB3uZ+DxOOeeM3M/n8/787oz73nf99znve9PRWtra2sAAAAAAAAKolu5CwAAAAAAAHgn4QUAAAAAAFAowgsAAAAAAKBQhBcAAAAAAEChCC8AAAAAAIBCEV4AAAAAAACFIrwAAAAAAAAKRXgBAAAAAAAUivACAAAAAAAoFOEFAAAAAABQKMILAAAAAACgUIQXAAAAAABAoQgvAAAAAACAQhFeAAAAAAAAhSK8AAAAAAAACkV4AQAAAAAAFMpuGV689tprueSSSzJo0KD06tUr9fX1GTt2bH7+858nSfbff/9UVFSkoqIie+yxR97znvfkgQceaDv+2muvbdv+ztshhxyyybnuvffeVFZWZtKkSZtsmzNnTioqKrJixYq2+1555ZUMHz48xx57bJqbm9v22dxt6dKlm9RTWVmZhoaGXHzxxVm+fPk2/0xaWloyadKk9OvXL1VVVZkwYUIaGxvb7fPiiy9m/Pjx+au/+qsMGDAgn/nMZ/LWW29t8zl2N/rZpraln/3d3/1djjrqqPTq1StHHHHENre9u9LPNrW1fvbLX/4yZ599dhoaGtKnT58ceuihufnmm7e5fQAAAAA6X/dSN9i8trnUTW5Rba/aDh8zYcKErFu3LnfffXcOOOCANDY25vHHH09TU1PbPp/73Ody0UUXZeXKlfnSl76Uv/mbv8m+++6bD3zgA0mSww47LD/5yU/atdu9+6Y/zhkzZuTKK6/M17/+9XzpS19K7969/2Jdixcvzoknnphhw4blgQceSJ8+fdq2LVq0KDU1Ne32HzBgQNvXG+tZv359fvOb3+SCCy5Ic3Nz7r///m36mVx++eX54Q9/mAceeCC1tbW59NJLc8YZZ7S9ALp+/fqMHz8+9fX1mTt3bl599dV8/OMfT48ePXLjjTdu0zlKaf07flc7Q2W/fh0+Rj/b1Nb62UYXXHBBnn766SxYsGCb2u0sb6xZt1PPt9cePTt8jH62qa31s+eeey4DBgzIzJkz09DQkLlz5+biiy9OZWVlLr300m06BwAAAACdq+ThxbmPfqzUTW7R90/7YYf2X7FiRZ588snMmTMnH/7wh5MkgwcPzvvf//52+1VXV6e+vj719fW57bbbMnPmzPzgBz9oe7Gve/fuqa+v3+K5lixZkrlz5+a73/1uZs+enQcffDAf+9jmfz4LFizI2LFjM3r06Nx9992bvHA4YMCA7Lnnnn/xXO+sZ999982ZZ56ZO++8c4v1bdTc3JwZM2Zk1qxZGT16dJLkzjvvzKGHHpqnnnoqRx99dH70ox/l17/+dX7yk5+krq4uRxxxRK6//vpMmTIl1157bXr27PiLrjti6Ygjdur59v2/lzq0v362qW3pZ0lyyy23JHn7EwXlDi/GTZ+9U8/31HVjO7S/frapbelnF1xwQbtjDjjggMybNy8PPvig8AIAAACgIHa7ZaOqqqpSVVWVhx9+OGvXrt2mY7p3754ePXpk3bqOvQv7zjvvzPjx41NbW5tzzjknM2bM2Ox+c+fOzYc//OFMmDAhM2fO3Ow7njvi97//fR577LFtDhSee+65vPnmmznhhBPa7jvkkEMyaNCgzJs3L0kyb968DB8+PHV1dW37jB07NitXrszzzz+/Q/XuivSzTW1LP6Nj9LNNbW8/a25uTt++fXeoVgAAAABKZ7cLL7p375677rord999d/bcc8988IMfzNVXX/0X3+G9bt263HTTTWlubm57F2+S/OpXv2p74XDj7ZOf/GTb9g0bNuSuu+7KOeeckyQ566yz8rOf/SxLlizZ5Bynn356TjnllNx6662pqKjYbB377bdfu3Mddthh7bZvrKdPnz4ZMmRInn/++UyZMmWbfiZLly5Nz549N3kndF1dXds69EuXLm0XXGzcvnEb7elnm9qWfkbH6Geb2p5+Nnfu3Nx///25+OKLt+kcAAAAAHS+ki8b1RVMmDAh48ePz5NPPpmnnnoqjz76aKZPn55vfetbmThxYpJkypQpmTp1alpaWlJVVZUvfOELGT9+fFsbQ4cOzfe///127b5zDfcf//jHWbNmTU4++eQkSf/+/XPiiSfmjjvuyPXXX9/uuFNP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H8+oUaM6dGJg17B69eosXrw4++yzT7lLAcpkyJAhqa+vbzc/WLlyZZ5++mnzA9iNvfzyy2lqajJHgF1Ia2trLr300jz00EP5j//4jwwZMqTd9qOOOio9evRoNydYtGhRXnzxRXMC2EVsbRzYnPnz5yeJOQHs4jZs2JC1a9eWdD7Q4WWjrrjiipx33nl573vfm/e///35yle+kjVr1uT888/vaFNAF/TpT386p5xySgYPHpxXXnkl06ZNS2VlZc4+++xylwZ0otWrV7d7p9SSJUsyf/789O3bN4MGDcpll12Wz3/+8znooIMyZMiQfPazn83AgQNz2mmnla9ooKS2NA707ds31113XSZMmJD6+vosXrw4V155ZQ488MCMHTu2jFUDpTRp0qTMmjUr3/ve91JdXd22bnVtbW369OmT2traXHjhhbniiivSt2/f1NTUZPLkyRk1alSOPvroMlcPlMLWxoHFixdn1qxZOfnkk9OvX78sWLAgl19+eY499tiMGDGizNUDpXLVVVdl3LhxGTRoUFatWpVZs2Zlzpw5eeyxx0o6H6hobW1t7Whxt956a774xS9m6dKlOeKII3LLLbe0fQQM2LWdddZZ+elPf5qmpqbsvffeOeaYY3LDDTdYtxJ2cXPmzMlf//Vfb3L/eeedl7vuuiutra2ZNm1avvGNb2TFihU55phjcvvtt+fggw8uQ7VAZ9jSOPDVr341p512Wv7rv/4rK1asyMCBAzNmzJhcf/31qaurK0O1QGeoqKjY7P133nlnJk6cmCRpaWnJpz71qdx7771Zu3Ztxo4dm9tvv92yUbCL2No48NJLL+Wcc87JwoULs2bNmjQ0NOT000/P1KlTU1NTs5OrBTrLhRdemMcffzyvvvpqamtrM2LEiEyZMiUnnnhiktLNB7YrvAAAAAAAAOgsHbrmBQAAAAAAQGcTXgAAAAAAAIUivAAAAAAAAApFeAEAAAAAABSK8AIAAAAAACgU4QUAAAAAAFAowgsAAAAAAKBQhBcAAAAAAEChCC8AAIAtmjhxYk477bRylwEAAOxGupe7AAAAoHwqKiq2uH3atGm5+eab09raupMqAgAAEF4AAMBu7dVXX237+v77788111yTRYsWtd1XVVWVqqqqcpQGAADsxiwbBQAAu7H6+vq2W21tbSoqKtrdV1VVtcmyUccdd1wmT56cyy67LHvttVfq6uryzW9+M2vWrMn555+f6urqHHjggXn00UfbnWvhwoUZN25cqqqqUldXl3PPPTevv/76Tn7EAABAVyC8AAAAOuzuu+9O//7988wzz2Ty5Mm55JJLcuaZZ+YDH/hAfvGLX2TMmDE599xz84c//CFJsmLFiowePTpHHnlknn322fz7v/97Ghsb89GPfrTMjwQAACgi4QUAANBhhx9+eKZOnZqDDjooV111VXr37p3+/fvnoosuykEHHZRrrrkmTU1NWbBgQZLk1ltvzZFHHpkbb7wxhxxySI488sjccccdmT17dv77v/+7zI8GAAAoGte8AAAAOmzEiBFtX1dWVqZfv34ZPnx42311dXVJkmXLliVJfvnLX2b27NmbvX7G4sWLc/DBB3dyxQAAQFcivAAAADqsR48e7b6vqKhod19FRUWSZMOGDUmS1atX55RTTsk//uM/btLWPvvs04mVAgAAXZHwAgAA6HTvec978t3vfjf7779/unf3bwgAALBlrnkBAAB0ukmTJmX58uU5++yz85//+Z9ZvHhxHnvssZx//vlZv359ucsDAAAKRngBAAB0uoEDB+bnP/951q9fnzFjxmT48OG57LLLsueee6ZbN/+WAAAA7VW0tra2lrsIAAAAAACAjbzFCQAAAAAAKBThBQAAAAAAUCjCCwAAAAAAoFCEFwAAAAAAQKEILwAAAAAAgEIRXgAAAAAAAIUivAAAAAAAAApFeAEAAAAAABSK8AIAAAAAACgU4QUAAAAAAFAowgsAAAAAAKBQ/j9ABajFKnR58QAAAABJRU5ErkJggg==","text/plain":[""]},"execution_count":12,"metadata":{},"output_type":"execute_result"}],"source":["# we visualize [0, 30] time range\n","from pyannote.core import notebook, Segment\n","notebook.crop = Segment(0, 30)\n","dia"]},{"cell_type":"markdown","metadata":{"id":"TC_ZiDYoeq4s"},"source":["When available, the reference annotation can be visualized too, for comparison:"]},{"cell_type":"code","execution_count":14,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":220},"executionInfo":{"elapsed":1085,"status":"ok","timestamp":1704809060416,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"xlcEFiHUeq4s","outputId":"d30ad6ba-a0c6-416d-eb8c-5c8e93f309da"},"outputs":[{"data":{"image/png":"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TTflH//xHzNz5szmD5U/85nPZPLkyamsrExtbe0u31Tv0aNHjjjiiL/Z/pw5c7J+/foWF0PesWNHli9fnltvvTVduvzlRy9f//rXc/3112fcuHH5j//4j5x22mm7tDdkyJA9Xovg7fXs/AD81ltv3eUD7N2pq6vLtm3bsmHDhhbHWLt2bfP1Derq6vLcc8+12G/t2rXN6/a3J6//6H4/5ruhn/3F3vSznX7961/njDPOyFVXXZUZM2a8Y9sAAAAAQMdS8vCipmdNqZvcL4499tg8/vjjzf/u37//Hj803pN169blu9/9bh566KEWp93Zvn17Tj311Pzwhz/MWWed1by8oqIi3/jGN9KlS5ecffbZ+cEPftB8ked3a8aMGRk1alSmTJmSgQMH7nHbk046Kd27d8+CBQsyceLEJMnKlSvz8ssvZ+TIkUmSkSNH5vbbb89rr72WAQMGJPnzt/6rq6tz7LHH7lOt78aBB+zfC4SXin62536WJC+88EJGjRqVSZMm5fbbb9+n+gAAAACA9qnTnTZq3bp1ueCCC3L55Zdn+PDhqaqqyvPPP59Zs2bl3HPP3et23nrrrV3O019RUZHa2tp861vfSr9+/fLxj398l2/Sn3322ZkzZ06LD5V37vu1r30tXbt2bf5g+fTTT29e/9prr6WxsbHFPv369dvltD47jRw5MsOHD88dd9yR2bNn7/G+1NTU5Iorrsh1112Xvn37prq6OtOmTcvIkSNz8sknJ0nGjBmTY489NpdeemlmzZqVNWvWZMaMGZk6dWp69uy5x/Y7I/1sV3vTz1asWJFRo0Zl7Nixue6665rve9euXXPQQQftsX0AAAAAoOPodOFFZWVlRowYkS996UtZtWpV3nzzzdTX1+fKK6/MjTfeuNftvPDCCzn44INbLOvZs2caGxtz77335rzzztvtRZEnTpyYSy+9NG+88cYu6yoqKnL33XenS5cuGT9+fJ544onmNoYOHbrL9kuWLGn+0Hd3rr322kyePDnTp09PfX39Hu/Pl770pXTp0iUTJ07M1q1bM3bs2Nxzzz3N67t27ZonnngiU6ZMyciRI3PAAQdk0qRJ+exnP7vHdjsr/Wz33qmfffvb387rr7+eefPmZd68ec3LBw8enJdeemmPbQMAAAAAHUdFU1NTU7mLAAAAAAAA2KnLO28CAAAAAACw/wgv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6EMfynvf+94kf54T9OjRI3369GmxrTkBdEy7GweS5OKLL87gwYMzcODALF++PNOnT8/KlSvz6KOPlrFaoNR+9atfZeTIkWlsbExlZWUee+yxHHvssVm2bFnJ5gOtCi8Axo0b1/z38OHDM2LEiAwePDj//u//niuuuKKMlQEA5fT2U8QNGzYsw4cPz+GHH55FixbljDPOKGNlQFuYOnVqVqxY4fp30In9rXHgqquuav572LBhOfjgg3PGGWdk1apVOfzww/d3mUAbGTp0aJYtW5aGhoZ8+9vfzqRJk/L000+X9BitOm1U//7907Vr112uDL527drU1dWVtDCgfejTp0+OOuqo/P73vy93KUCZ7JwDmB8Ab3fYYYelf//+5gjQAV199dV54oknsnDhwhxyyCHNy+vq6rJt27Zs2LChxfbmBNDx/K1xYHdGjBiRJOYE0MH06NEjRxxxRE466aTceeedOf7443PXXXeVdD7QqvCiR48eOemkk7JgwYLmZTt27MiCBQsycuTIVh0Y6Bg2b96cVatW5eCDDy53KUCZDBkyJHV1dS3mBxs3bszPf/5z8wPoxP7v//4v69atM0eADqSpqSlXX311HnvssfzXf/1XhgwZ0mL9SSedlO7du7eYE6xcuTIvv/yyOQF0EO80DuzOsmXLksScADq4HTt2ZOvWrSWdD7T6tFHXXXddJk2alPe///354Ac/mC9/+cvZsmVLLrvsstY2BbRDn/70p3POOedk8ODBWb16dWbOnJmuXbvmoosuKndpQBvavHlzi29Kvfjii1m2bFn69u2bQYMG5Zprrsk///M/58gjj8yQIUNy0003ZeDAgZkwYUL5igZKak/jQN++fXPrrbdm4sSJqaury6pVq3L99dfniCOOyNixY8tYNVBKU6dOzfz58/Pd7343VVVVzeetrqmpSe/evVNTU5Mrrrgi1113Xfr27Zvq6upMmzYtI0eOzMknn1zm6oFSeKdxYNWqVZk/f37OPvvs9OvXL8uXL8+1116b0047LcOHDy9z9UCp3HDDDRk3blwGDRqUTZs2Zf78+Vm0aFGeeuqpks4HKpqamppaW9zs2bPzhS98IWvWrMkJJ5yQr3zlK80/AQM6tgsvvDA/+clPsm7duhx00EE59dRTc/vttztvJXRwixYtykc/+tFdlk+aNClz585NU1NTZs6cmW984xvZsGFDTj311Nxzzz056qijylAt0Bb2NA589atfzYQJE/I///M/2bBhQwYOHJgxY8bktttuS21tbRmqBdpCRUXFbpffd999mTx5cpKksbExn/rUp/Lggw9m69atGTt2bO655x6njYIO4p3GgVdeeSWXXHJJVqxYkS1btqS+vj7nnXdeZsyYkerq6v1cLdBWrrjiiixYsCCvvvpqampqMnz48EyfPj2jR49OUrr5wLsKLwAAAAAAANpKq655AQAAAAAA0NaEFwAAAAAAQKEILwAAAAAAgEIRXgAAAAAAAIUivAAAAAAAAApFeAEAAAAAABSK8AIAAAAAACgU4QUAAAAAAFAowgsAAGCPJk+enAkTJpS7DAAAoBPpVu4CAACA8qmoqNjj+pkzZ+auu+5KU1PTfqoIAABAeAEAAJ3aq6++2vz3ww8/nJtvvjkrV65sXlZZWZnKyspylAYAAHRiThsFAACdWF1dXfOtpqYmFRUVLZZVVlbuctqo008/PdOmTcs111yTAw88MLW1tfnmN7+ZLVu25LLLLktVVVWOOOKIPPnkky2OtWLFiowbNy6VlZWpra3NpZdemjfeeGM/32MAAKA9EF4AAACtdv/996d///557rnnMm3atEyZMiUXXHBBTjnllPziF7/ImDFjcumll+aPf/xjkmTDhg0ZNWpUTjzxxDz//PP5z//8z6xduzYf//jHy3xPAACAIhJeAAAArXb88cdnxowZOfLII3PDDTekV69e6d+/f6688soceeSRufnmm7Nu3bosX748STJ79uyceOKJueOOO3L00UfnxBNPzL333puFCxfmf//3f8t8bwAAgKJxzQsAAKDVhg8f3vx3165d069fvwwbNqx5WW1tbZLktddeS5L88pe/zMKFC3d7/YxVq1blqKOOauOKAQCA9kR4AQAAtFr37t1b/LuioqLFsoqKiiTJjh07kiSbN2/OOeeck89//vO7tHXwwQe3YaUAAEB7JLwAAADa3Pve97585zvfyaGHHppu3bwNAQAA9sw1LwAAgDY3derUrF+/PhdddFH++7//O6tWrcpTTz2Vyy67LNu3by93eQAAQMEILwAAgDY3cODA/OxnP8v27dszZsyYDBs2LNdcc0369OmTLl28LQEAAFqqaGpqaip3EQAAAAAAADv5ihMAAAAAAFAowgsAAAAAAKBQhBcAAAAAAEChCC8AAAAAAIBCEV4AAAAAAACFIrwAAAAAAAAKRXgBAAAAAAAUivACAAAAAAAoFOEFAAAAAABQKMILAAAAAACgUIQXAAAAAABAofx/KOKnS3lbHocAAAAASUVORK5CYII=","text/plain":[""]},"execution_count":14,"metadata":{},"output_type":"execute_result"}],"source":["from pyannote.database.util import load_rttm\n","\n","reference = load_rttm(REFERENCE)[\"sample\"]\n","\n","# map hypothesized and reference speakers for visualization purposes\n","pipeline.optimal_mapping(dia, reference)"]},{"cell_type":"markdown","metadata":{"id":"rfTV3nSSeq4t"},"source":["## Processing a file from memory\n","\n","In case the audio file is not stored on disk, pipelines can also process audio provided as a `{\"waveform\": ..., \"sample_rate\": ...}` dictionary."]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":410,"status":"ok","timestamp":1704809066383,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"Nha4sg76eq4u","outputId":"69192d82-c240-47d1-fe01-d373c2b4e500"},"outputs":[{"name":"stdout","output_type":"stream","text":["type(waveform)=\n","waveform.shape=torch.Size([1, 480000])\n","waveform.dtype=torch.float32\n"]}],"source":["import torchaudio\n","waveform, sample_rate = torchaudio.load(AUDIO_FILE)\n","\n","print(f\"{type(waveform)=}\")\n","print(f\"{waveform.shape=}\")\n","print(f\"{waveform.dtype=}\")\n","\n","audio_in_memory = {\"waveform\": waveform, \"sample_rate\": sample_rate}"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":388,"referenced_widgets":["514552137d7442368b39aaddce056bb8","f744ac29ccdd4d9d91050fabaed13e16","f18c80869ccc4ce1b2a215293d493e19","2c0b1ed212544e14b4934e036e8736d7","9988b4433d6e4c58a819a2e1b54f57b2","b8861f8cb72c4e65afac6519b7004170","668a49e70c2b4c8a9dcb534cb30714d6","9025d2b6c7b14162a692b98c3e86ec8a","6c361855da5e4eb78e311defb2ca2f2b","3be13f7f05da47b1ae3795ead9f2546a","07bb94f0dcda45a9a5e2d553fd239106","57ef34701b594a60a9fd269943b49888","1d051eb2d87e4671aa08039761c7899a","9537f195677745cba18618764b2290ab","4f0d63f098b0491097c6b72f3baee04f","f7be373f08c64c8bb5b6e070a7373cca","be8b64ce7f8247499c8bbcb62c5dd902","491c3dcba4474a52b860080fa7a627e7","4abbe0d8e0fa4e1b9d712743013b2d4e","661c7494ef2d47c794e6236e5f2c8978","6358920ecd46403a87cca46509465076","4f25b89365b24056b803119d415ac056","1d97d11a99454cc990cc5e374d0f8197","425146d4e0fb453486629d9d6af0a999","8fad50e0475341d9801e9f86e04e15c7","ea03f9526a7440a0a9a281ee877892fd","d1863b2c9ebc4efa9cac2dad7dfaf53a","8bda58a4c0c6430ca1470282ddbe8222","5d38b6ceec1844068f48da7bedf471fa","2a72c7660c2f498089c63c78eaa69fc8","05283cf0054d412c9a1ebfcc44bf41cb","b9d9acd287c345debdff1e72a85641af","91ca95844e084619b9ae01fe8176f875"]},"executionInfo":{"elapsed":12810,"status":"ok","timestamp":1704809082573,"user":{"displayName":"Clément PAGES","userId":"11757386314069785178"},"user_tz":-60},"id":"LvboMeeYeq4u","outputId":"225dd352-6367-4793-ae11-f8125d930c2b"},"outputs":[],"source":["vad = Pipeline.from_pretrained(\"pyannote/voice-activity-detection\", use_auth_token=True)"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[{"data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAABiIAAADyCAYAAADAzN2uAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAWJUlEQVR4nO3dfZCVdf3/8dfhRrzZG2SRXTZWF2/QTDDtV941Rt4Aak4o2r2JFY2KOqilaSplTRYTYk3ajU2pk/ptHNOyGW3KwMxRy8rIvt/IdpwRQ9FodhcxhOD8/nBc20BYZD+cZXk8ZnaGvc6153ofZs41n+XJua5KtVqtBgAAAAAAoIAhtR4AAAAAAAAYvIQIAAAAAACgGCECAAAAAAAoRogAAAAAAACKESIAAAAAAIBihAgAAAAAAKAYIQIAAAAAAChGiAAAAAAAAIoRIgAAAAAAgGKECAAAAAAAoBghAgAAAAAAKEaIAAAAAAAAihEiAAAAAACAYoQIAAAAAACgGCECAAAAAAAoRogAAAAAAACKGfQh4oUXXsg555yTPffcMyNGjEhLS0umTp2ahx56KEnS3t6eSqWSSqWS3XbbLYceemjuuOOOnp//3Oc+1/P4f34dcMABPftMnjx5o/ucffbZvWZZuHBhTjzxxDQ1NWXXXXfNgQcemIsvvjh///vfkySLFi1KpVJJZ2fnBq+jvb091113Xf//BQEAAAAAQEHDtvYJ1q1Y0R9z9MnQpqYt/pkZM2ZkzZo1ufnmm7P33ntn+fLluf/++7PiP+a++uqrM2vWrHR3d2f+/Pl5//vfnze96U058sgjkyRvectb8otf/KLX8w4b1vuvbtasWbn66qt7bdt11117/vztb3875557bs4888zceeedaW9vz9NPP51bbrkl8+fPz7XXXrvFrw0AAAAAAAa6rQ4Rz016az+M0Tdv+vvSLdq/s7MzDz74YBYtWpR3vetdSZK99tor73jHO3rtV19fn5aWlrS0tOT666/PD37wg9xzzz09IWLYsGFpaWnZ5LF23XXX193nmWeeyQUXXJALLrggCxYs6Nne3t6eo48+eqOfgAAAAAAAgMFgUF+aqa6uLnV1dbn77rvz8ssv9+lnhg0bluHDh2fNmjX9Nscdd9yRNWvW5JJLLtno4yNHjuy3YwEAAAAAwEAyqEPEsGHDctNNN+Xmm2/OyJEjc9RRR+Xyyy/P4sWLN7r/mjVrcs0116SrqyvHHHNMz/Y//elPPVHj1a//vv/DDTfcsME+t956a5LkySefTENDQ8aOHdunuceNG7fBcz399NNv8G8BAAAAAABqZ6svzTTQzZgxIyeddFIefPDBPPLII7n33nszb968fPe7383MmTOTJJdeemmuuOKKrF69OnV1dfnyl7+ck046qec59t9///zkJz/p9bwNDQ29vv/whz+cz372s722NTc3J0mq1WoqlUqfZ37wwQdTX1/fa9vkyZP7/PMAAAAAADBQbHWIaFn8eD+MUdbOO++c448/Pscff3yuvPLKfOITn8jcuXN7QsSnP/3pzJw5M3V1dWlubt4gGuy0007Zd999N3mMxsbG191nwoQJ6erqyrPPPtunT0WMHz9+g8s1/ffNsQEAAAAAYHuw1f+6PbSpqT/m2KYOPPDA3H333T3fjx49erOhYWucdtpp+cxnPpN58+b1uln1qzo7O90nAgAAAACAQWlQ/zf7FStW5PTTT8/HPvaxTJo0KfX19Xnssccyb968vPe97+3z8/z73//Oc88912tbpVLpufRSkrz00ksb7DNixIjsvvvuaWtry4IFC3Leeeelu7s7H/3oR9Pe3p5nnnkmt9xyS+rq6jJ//vyte7EAAAAAADAADeoQUVdXl8MOOywLFixIR0dH1q5dm7a2tsyaNSuXX355n5/nz3/+8waXVBoxYkRWr17d8/2NN96YG2+8sdc+U6dOzX333ZckOffcczNhwoR89atfzSmnnJJ//etfaW9vz3ve855cdNFFW/EqAQAAAABg4KpUq9VqrYcAAAAAAAAGpyG1HgAAAAAAABi8hAgAAAAAAKAYIQIAAAAAAChGiAAAAAAAAIoRIgAAAAAAgGKECAAAAAAAoJhhfdlp/fr1WbZsWerr61OpVErPBAAAAAAADGDVajUrV65Ma2trhgzZ9Gce+hQili1blra2tn4ZDgAAAAAAGByWLl2acePGbXKfPoWI+vr6nidsaGjY+skAAAAAAIDtVnd3d9ra2nr6wab0KUS8ejmmhoYGIQIAAAAAAEiSPt3Owc2qAQAAAACAYoQIAAAAAACgGCECAAAAAAAoRogAAAAAAACKESIAAAAAAIBihAgAAAAAAKAYIQIAAAAAAChGiAAAAAAAAIoRIgAAAAAAgGKECAAA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gGKECAAAAAAAoBghAgAAAAAAKEaIAAAAAAAAihEiYBv71a9+lZNPPjmtra2pVCq5++67ez1erVZz1VVXZezYsdlll11y3HHH5cknn6zNsAA1trlz5syZM1OpVHp9TZs2rTbDAtTQNddck7e//e2pr6/PmDFjMn369CxZsqTXPqtXr87s2bPT1NSUurq6zJgxI8uXL6/RxAC11Zfz5uTJkzdYa5599tk1mhhg+yZEwDa2atWqHHzwwbn++us3+vi8efPy9a9/Pd/61rfy6KOPZrfddsvUqVOzevXqbTwpQO1t7pyZJNOmTcuzzz7b83X77bdvwwkBBoYHHnggs2fPziOPPJKf//znWbt2baZMmZJVq1b17HPhhRfmnnvuyR133JEHHnggy5Yty6mnnlrDqQFqpy/nzSSZNWtWr7XmvHnzajQxwPatUq1Wq7UeAnZUlUold911V6ZPn57klU9DtLa25uKLL86nPvWpJElXV1eam5tz00035QMf+EANpwWorf8+ZyavfCKis7Nzg09KAOzoXnjhhYwZMyYPPPBAjj766HR1dWWPPfbIbbfdltNOOy1J8pe//CVvfvOb8/DDD+fwww+v8cQAtfXf583klU9EvPWtb811111X2+EABgGfiIAB5Kmnnspzzz2X4447rmdbY2NjDjvssDz88MM1nAxg4Fq0aFHGjBmT/fffP+ecc05WrFhR65EAaq6rqytJMmrUqCTJ7373u6xdu7bXOvOAAw7InnvuaZ0JkA3Pm6+69dZbM3r06Bx00EG57LLL8tJLL9ViPIDt3rBaDwC85rnnnkuSNDc399re3Nzc8xgAr5k2bVpOPfXUjB8/Ph0dHbn88stzwgkn5OGHH87QoUNrPR5ATaxfvz5z5szJUUcdlYMOOijJK+vMnXbaKSNHjuy1r3UmwMbPm0nyoQ99KHvttVdaW1uzePHiXHrppVmyZEl+9KMf1XBagO2TEAEAbLf+85J1EydOzKRJk7LPPvtk0aJFOfbYY2s4GUDtzJ49O0888UR+/etf13oUgO3C6503P/nJT/b8eeLEiRk7dmyOPfbYdHR0ZJ999tnWYwJs11yaCQaQlpaWJMny5ct7bV++fHnPYwC8vr333jujR4/O3/72t1qPAlAT5513Xn76059m4cKFGTduXM/2lpaWrFmzJp2dnb32t84EdnSvd97cmMMOOyxJrDUB3gAhAgaQ8ePHp6WlJffff3/Ptu7u7jz66KM54ogjajgZwPbhmWeeyYoVKzJ27NhajwKwTVWr1Zx33nm566678stf/jLjx4/v9fjb3va2DB8+vNc6c8mSJXn66aetM4Ed0ubOmxvz+OOPJ4m1JsAb4NJMsI29+OKLvf73xFNPPZXHH388o0aNyp577pk5c+bki1/8Yvbbb7+MHz8+V155ZVpbWzN9+vTaDQ1QI5s6Z44aNSqf//znM2PGjLS0tKSjoyOXXHJJ9t1330ydOrWGUwNse7Nnz85tt92WH//4x6mvr++570NjY2N22WWXNDY25uMf/3guuuiijBo1Kg0NDTn//PNzxBFH5PDDD6/x9ADb3ubOmx0dHbntttty4oknpqmpKYsXL86FF16Yo48+OpMmTarx9ADbn0q1Wq3WegjYkSxatCjvfve7N9h+5pln5qabbkq1Ws3cuXPzne98J52dnXnnO9+ZG264IRMmTKjBtAC1talz5je/+c1Mnz49f/jDH9LZ2ZnW1tZMmTIlX/jCF9Lc3FyDaQFqp1KpbHT797///cycOTNJsnr16lx88cW5/fbb8/LLL2fq1Km54YYbXJoJ2CFt7ry5dOnSfOQjH8kTTzyRVatWpa2tLaecckquuOKKNDQ0bONpAbZ/QgQAAAAAAFCMe0QAAAAAAADFCBEAAAAAAEAxQgQAAAAAAFCMEAEAAAAAABQjRAAAAAAAAMUIEQAAAAAAQDFCBAAAAAAAUIwQAQAA9DJz5sxMnz691mMAAACDxLBaDwAAAGw7lUplk4/PnTs3X/va11KtVrfRRAAAwGAnRAAAwA7k2Wef7fnzD3/4w1x11VVZsmRJz7a6urrU1dXVYjQAAGCQcmkmAADYgbS0tPR8NTY2plKp9NpWV1e3waWZJk+enPPPPz9z5szJ7rvvnubm5tx4441ZtWpVzjrrrNTX12fffffNvffe2+tYTzzxRE444YTU1dWlubk5Z5xxRv7xj39s41cMAADUmhABAABs1s0335zRo0fnN7/5Tc4///ycc845Of3003PkkUfm97//faZMmZIzzjgjL730UpKks7MzxxxzTA455JA89thjue+++7J8+fK8733vq/ErAQAAtjUhAgAA2KyDDz44V1xxRfbbb79cdtll2XnnnTN69OjMmjUr++23X6666qqsWLEiixcvTpJ84xvfyCGHHJIvfelLOeCAA3LIIYfke9/7XhYuXJi//vWvNX41AADAtuQeEQAAwGZNmjSp589Dhw5NU1NTJk6c2LOtubk5SfL8888nSf74xz9m4cKFG73fREdHRyZMmFB4YgAAYKAQIgAAgM0aPnx4r+8rlUqvbZVKJUmyfv36JMmLL76Yk08+OV/5ylc2eK6xY8cWnBQAABhohAgAAKDfHXroobnzzjvT3t6eYcP82gEAADsy94gAAAD63ezZs/PPf/4zH/zgB/Pb3/42HR0d+dnPfpazzjor69atq/V4AADANiREAAAA/a61tTUPPfRQ1q1blylTpmTixImZM2dORo4cmSFD/BoCAAA7kkq1Wq3WeggAAAAAAGBw8l+RAAAAAACAYoQIAAAAAACgGCECAAAAAAAoRogAAAAAAACKESIAAAAAAIBihAgAAAAAAKAYIQIAAAAAAChGiAAAAAAAAIoRIgAAAAAAgGKECAAAAAAAoBghAgAAAAAAKEaIAAAAAAAAivn/OkPb8btR7hwAAAAASUVORK5CYII=","text/plain":[""]},"execution_count":12,"metadata":{},"output_type":"execute_result"}],"source":["vad(audio_in_memory)"]},{"cell_type":"markdown","metadata":{"id":"LllNe0s3eq4u"},"source":["## Offline use\n","\n","Gating models and pipelines allows [me](https://herve.niderb.fr) to know a bit more about `pyannote.audio` user base and eventually help me write grant proposals to make `pyannote.audio` even better. Please fill this form as precisely as possible.\n","\n","For instance, before gating `pyannote/speaker-diarization`, I had no idea that so many people were relying on it in production. Hint: sponsors are more than welcome! maintaining open source libraries is time consuming.\n","\n","That being said: this whole authentication process does not prevent you from using official `pyannote.audio` models and pipelines offline (i.e. without going through the authentication process in every `docker run ...` or whatever you are using in production).\n","\n","* Step 1: download `config.yaml` of [`pyannote/voice-activity-detection`](https://hf.co/pyannote/voice-activity-detection) pipeline\n","\n","![](https://github.com/pyannote/pyannote-audio/blob/develop/tutorials/assets/download-pipeline.png?raw=1)\n","\n","* Step 2: download the `pytorch_model.bin` model\n","\n","![](https://github.com/pyannote/pyannote-audio/blob/develop/tutorials/assets/download-model.png?raw=1)\n","\n","* Step 3: edit `config.yaml` to point to the local model\n","\n","```diff\n","pipeline:\n"," name: pyannote.audio.pipelines.VoiceActivityDetection\n"," params:\n","- segmentation: pyannote/segmentation@Interspeech2021\n","+ segmentation: pytorch_model.bin\n","\n","params:\n"," min_duration_off: 0.09791355693027545\n"," min_duration_on: 0.05537587440407595\n"," offset: 0.4806866463041527\n"," onset: 0.8104268538848918\n","```\n","\n","* Step 4: load the pipeline"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"a1bZGOoEeq4v","outputId":"a8851164-100c-4cc1-afd2-d387a5fc4fd5"},"outputs":[{"data":{"image/png":"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bPHixalUKu2+mpqaunpZQCdat25dzjzzzIwcOTKVSiWrVq1qd321Ws3ixYszcuTIDBw4MKeddlr+8pe/dM1igU7zVnvB3Llz95kRTj755K5ZLFBzS5Ysyfvf//7U1dVl2LBhmTlzZh566KF2tzETQM/3dvYCMwH0bMuWLctxxx2X+vr61NfXZ9KkSfntb3/bdn2t5oEOx4uVK1dm4cKF+epXv5r7778/H/7whzN9+vRs3ry5w3cOdF/HHHNMtm7d2va1adOmrl4S0In27NmT448/Ptdcc80bXr906dJcffXVueaaa3LvvfemqakpU6ZMybPPPvsOrxToTG+1FyTJtGnT2s0It9566zu4QqAzrV27NhdccEHuueee3H777XnppZcyderU7Nmzp+02ZgLo+d7OXpCYCaAnGzVqVL71rW9lw4YN2bBhQ04//fTMmDGjLVDUah6oVKvVakd+YOLEiTnhhBOybNmytmPjx4/PzJkzs2TJkg7dOdA9LV68OKtWrcrGjRu7eilAF6hUKrn55pszc+bMJK/+RcXIkSOzcOHCXHrppUmS1tbWDB8+PN/+9rdz/vnnd+Fqgc7y+r0gefWvLHft2rXPKzKAnumf//xnhg0blrVr1+YjH/mImQB6qdfvBYmZAHqjxsbGfOc738m8efNqNg906JUXL7zwQu67775MnTq13fGpU6fmrrvu6sipgG7u4YcfzsiRIzN27Nh8+tOfzt///veuXhLQRR577LFs27at3XzQv3//nHrqqeYD6IXWrFmTYcOG5aijjsr8+fOzffv2rl4S0El2796d5NVfViRmAuitXr8XvMZMAL3Dyy+/nBUrVmTPnj2ZNGlSTeeBDsWLHTt25OWXX87w4cPbHR8+fHi2bdvWoTsGuq+JEyfmhhtuyG233Zaf/OQn2bZtW0455ZTs3Lmzq5cGdIHXZgDzATB9+vTceOONueOOO/Ld73439957b04//fS0trZ29dKAGqtWq7nooovyoQ99KBMmTEhiJoDe6I32gsRMAL3Bpk2bMnjw4PTv3z8LFizIzTffnKOPPrqm80Df/VlYpVJpd7lare5zDOi5pk+f3vb9sccem0mTJuXwww/P9ddfn4suuqgLVwZ0JfMBMHv27LbvJ0yYkJNOOiljxozJb37zm5x11llduDKg1i688MI88MADufPOO/e5zkwAvcd/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","text/plain":[""]},"execution_count":21,"metadata":{},"output_type":"execute_result"}],"source":["# look ma: no hands!\n","offline_vad = Pipeline.from_pretrained(\"config.yaml\")\n","offline_vad(audio_in_memory)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"eepjEec8eq4w"},"outputs":[],"source":["# just checking output is the same\n","assert (vad(audio_in_memory) == offline_vad(audio_in_memory))"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"T4","provenance":[{"file_id":"https://github.com/pyannote/pyannote-audio/blob/develop/tutorials/applying_a_pipeline.ipynb","timestamp":1704808199718}]},"kernelspec":{"display_name":"Python 3","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.13"},"vscode":{"interpreter":{"hash":"36a3a48a52702f18671693adf589423ec3f7db45d50f6ee539f1b0696bb58d43"}},"widgets":{"application/vnd.jupyter.widget-state+json":{"008a47e4d1174b188e75232fed325398":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"00ac431507a54c0d9a41244013b1c0f3":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"05283cf0054d412c9a1ebfcc44bf41cb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"07bb94f0dcda45a9a5e2d553fd239106":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"0b127e22a6de4339aecc1e76a6719d7f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ae378b480ed747438bcbe147a7e8d277","placeholder":"","style":"IPY_MODEL_b22a1d21940e4995b72642b003ae1301","value":"Your token has been saved in your configured git credential helpers (store)."}},"0b191fb0d6db4f1a98a641dc50445f1e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_4a589ea883de4409b7a8275127747fa7","IPY_MODEL_b5f4829158cf4a5c8350966d8eacbf60","IPY_MODEL_7cab72ad0ace45d58d6954021082ace7"],"layout":"IPY_MODEL_5440ac4cffa0438c99c0daeca27a4087"}},"0d0dfc2576784812b6abf673752fa812":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0fccc53081a34d58a46912d1ceae0533":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_00ac431507a54c0d9a41244013b1c0f3","max":221,"min":0,"orientation":"horizontal","style":"IPY_MODEL_6f318bc3e900434a9134a79e4057f666","value":221}},"16244ab1dc76493d9fafad80a9b65700":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"1749a0e7fc6847849ab40ac7f764b699":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"17e14569a3f74cbf991b582c27fdf280":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_e98b1f7ec5e04e748069340fa2fcec2d","max":469,"min":0,"orientation":"horizontal","style":"IPY_MODEL_616f35eccdd34bcdb5c9f700103ff538","value":469}},"185457147fe44751a1c6e7ae6ad23570":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"1b5f49211db54348924a05482ca7379d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_dc9c065286e544df921e5bc4a51faf64","placeholder":"","style":"IPY_MODEL_16244ab1dc76493d9fafad80a9b65700","value":"Login successful"}},"1d051eb2d87e4671aa08039761c7899a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_be8b64ce7f8247499c8bbcb62c5dd902","placeholder":"","style":"IPY_MODEL_491c3dcba4474a52b860080fa7a627e7","value":"pytorch_model.bin: 100%"}},"1d97d11a99454cc990cc5e374d0f8197":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_425146d4e0fb453486629d9d6af0a999","IPY_MODEL_8fad50e0475341d9801e9f86e04e15c7","IPY_MODEL_ea03f9526a7440a0a9a281ee877892fd"],"layout":"IPY_MODEL_d1863b2c9ebc4efa9cac2dad7dfaf53a"}},"1dd6bfb824ba4919ba392e0d4cd5ac82":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"1e53e26668aa4f8dabdd6973b79b5b9f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"1f3be36a57074214a5f92e08165e41be":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"253408a6cab947c7b9ae40a14e255328":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"275642719b694328ad3b0fb06b53e42a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"2a72c7660c2f498089c63c78eaa69fc8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2be7c1f5fe32462f8d1cd7ea57cfbf3a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2c0b1ed212544e14b4934e036e8736d7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_3be13f7f05da47b1ae3795ead9f2546a","placeholder":"","style":"IPY_MODEL_07bb94f0dcda45a9a5e2d553fd239106","value":" 277/277 [00:00<00:00, 14.5kB/s]"}},"30864d7b4d074994ba643c73875a67b8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"36f60aa99ea84b739f066c6ee216f159":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"39cd6fe37b6f4476b6032c29f026d570":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_7580595b498a4c50b748af9df67132e2","placeholder":"","style":"IPY_MODEL_3f1d750804a54d78a6abff2623441360","value":" 221/221 [00:00<00:00, 14.0kB/s]"}},"3bb60a8db7c0406f8debdc8dd88bcdb4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_bf644ae3e2894787bb416740749200cd","IPY_MODEL_0fccc53081a34d58a46912d1ceae0533","IPY_MODEL_39cd6fe37b6f4476b6032c29f026d570"],"layout":"IPY_MODEL_87a0e712c0b045449b98ee368c62fff2"}},"3be13f7f05da47b1ae3795ead9f2546a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"3f1d750804a54d78a6abff2623441360":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"3f500b1182a945c3b8b546b1bd04f98e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"3f69734124f7449da0efffbbfd1153fe":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"425146d4e0fb453486629d9d6af0a999":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_8bda58a4c0c6430ca1470282ddbe8222","placeholder":"","style":"IPY_MODEL_5d38b6ceec1844068f48da7bedf471fa","value":"config.yaml: 100%"}},"45c2352ba41b46288c8ba74c661e1f85":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"Login","disabled":false,"icon":"","layout":"IPY_MODEL_c3b3069a93994e55b993cab04c066f17","style":"IPY_MODEL_f77186e2976d4a7daa798fd9f0f7b4cb","tooltip":""}},"46ac2d0bfedc47c8836e8dde0fc91662":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"491c3dcba4474a52b860080fa7a627e7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4a589ea883de4409b7a8275127747fa7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_0d0dfc2576784812b6abf673752fa812","placeholder":"","style":"IPY_MODEL_84e416e01cfa4a79b0294a44cfd77f32","value":"pytorch_model.bin: 100%"}},"4abbe0d8e0fa4e1b9d712743013b2d4e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4e0ca7f084804d30a89cb9dc439b6cdc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_185457147fe44751a1c6e7ae6ad23570","placeholder":"","style":"IPY_MODEL_b02b253086e34249ae1d896a75a08960","value":" 469/469 [00:00<00:00, 34.3kB/s]"}},"4f0d63f098b0491097c6b72f3baee04f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6358920ecd46403a87cca46509465076","placeholder":"","style":"IPY_MODEL_4f25b89365b24056b803119d415ac056","value":" 17.7M/17.7M [00:00<00:00, 66.5MB/s]"}},"4f25b89365b24056b803119d415ac056":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5033834cc66f49efaa16b240245ec1d3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_1f3be36a57074214a5f92e08165e41be","placeholder":"","style":"IPY_MODEL_275642719b694328ad3b0fb06b53e42a","value":"Token is valid (permission: write)."}},"514552137d7442368b39aaddce056bb8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_f744ac29ccdd4d9d91050fabaed13e16","IPY_MODEL_f18c80869ccc4ce1b2a215293d493e19","IPY_MODEL_2c0b1ed212544e14b4934e036e8736d7"],"layout":"IPY_MODEL_9988b4433d6e4c58a819a2e1b54f57b2"}},"517a1b1faec045f7847ca84f0538f4e1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5253489738b249f69b30f1c84884a95a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5440ac4cffa0438c99c0daeca27a4087":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"54eacc5604f64f658617cde596a728dd":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"57ef34701b594a60a9fd269943b49888":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_1d051eb2d87e4671aa08039761c7899a","IPY_MODEL_9537f195677745cba18618764b2290ab","IPY_MODEL_4f0d63f098b0491097c6b72f3baee04f"],"layout":"IPY_MODEL_f7be373f08c64c8bb5b6e070a7373cca"}},"58b140d0453a4a219bc64e0152cc5c5e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"58e423b86bf349aa89fc81a2b0d0f697":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5a2a95f41f014663b5d131635844e3c8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_f8df65e5ad6444648681230f415b8d08","IPY_MODEL_17e14569a3f74cbf991b582c27fdf280","IPY_MODEL_4e0ca7f084804d30a89cb9dc439b6cdc"],"layout":"IPY_MODEL_d304f698c6f34f3692548267ca0aba47"}},"5cc77ca8ba304ad88342ed6ced6c6a4a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5d38b6ceec1844068f48da7bedf471fa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"616f35eccdd34bcdb5c9f700103ff538":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"6358920ecd46403a87cca46509465076":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6412ef268e11484f8bbcdb510f66ee21":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_a987408c2f994329a9a80208b22e3c52","IPY_MODEL_9446f61936c4421d9610464984890353","IPY_MODEL_a80c0fb6a1254bb9a00741c1346b9d9a"],"layout":"IPY_MODEL_b55e95f31216480fa6c81bd1b57ad729"}},"6556790d1997431a8476447297e3f595":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"661c7494ef2d47c794e6236e5f2c8978":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"668a49e70c2b4c8a9dcb534cb30714d6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"686b58e0ccee468f938ea5659f3a9623":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"6c361855da5e4eb78e311defb2ca2f2b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"6d5431955c09424a96e825aa9bba1b62":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"6f318bc3e900434a9134a79e4057f666":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"6fe26270a8794dea85b9ac8dedde6353":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_5033834cc66f49efaa16b240245ec1d3","IPY_MODEL_0b127e22a6de4339aecc1e76a6719d7f","IPY_MODEL_8a7afaf126ac49dcaf24d64c2d918086","IPY_MODEL_1b5f49211db54348924a05482ca7379d"],"layout":"IPY_MODEL_9d7b5e47af9448c98a2a434f02b54633"}},"70d672feec1c452aa49a40a3b8c1a4f0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"754a843fd634446b8d246998eaded1fa":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7580595b498a4c50b748af9df67132e2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"775611277f1948a5ab95641c4e92ff2e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_70d672feec1c452aa49a40a3b8c1a4f0","placeholder":"","style":"IPY_MODEL_e8b3188ee4934ab4becbc431fc4ccb0b","value":"config.yaml: 100%"}},"78f428e1d8ac4c78bd84d208a78b1fe5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_7ffa4930e0a7421e9464abff87bbde7f","placeholder":"","style":"IPY_MODEL_1dd6bfb824ba4919ba392e0d4cd5ac82","value":"\nPro Tip: If you don't already have one, you can create a dedicated\n'notebooks' token with 'write' access, that you can then easily reuse for all\nnotebooks. "}},"7c23cd10c573438c840148ba1afaa5f3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_bc4d3f45eaf04cccb7a655ef87d7a927","placeholder":"","style":"IPY_MODEL_36f60aa99ea84b739f066c6ee216f159","value":"Connecting..."}},"7cab72ad0ace45d58d6954021082ace7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_54eacc5604f64f658617cde596a728dd","placeholder":"","style":"IPY_MODEL_1749a0e7fc6847849ab40ac7f764b699","value":" 5.91M/5.91M [00:00<00:00, 88.7MB/s]"}},"7ffa4930e0a7421e9464abff87bbde7f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"84e416e01cfa4a79b0294a44cfd77f32":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"87a0e712c0b045449b98ee368c62fff2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8a7afaf126ac49dcaf24d64c2d918086":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_58e423b86bf349aa89fc81a2b0d0f697","placeholder":"","style":"IPY_MODEL_a3ebe0f0e6e44522a2545db0ed47af62","value":"Your token has been saved to /root/.cache/huggingface/token"}},"8bda58a4c0c6430ca1470282ddbe8222":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8fad50e0475341d9801e9f86e04e15c7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_2a72c7660c2f498089c63c78eaa69fc8","max":1980,"min":0,"orientation":"horizontal","style":"IPY_MODEL_05283cf0054d412c9a1ebfcc44bf41cb","value":1980}},"9025d2b6c7b14162a692b98c3e86ec8a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"90533da4fc1341a28bc247bc9fbbbe9e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"91ca95844e084619b9ae01fe8176f875":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"9446f61936c4421d9610464984890353":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_30864d7b4d074994ba643c73875a67b8","max":26645418,"min":0,"orientation":"horizontal","style":"IPY_MODEL_b852998433e24f7fad1fe27e249085f9","value":26645418}},"9537f195677745cba18618764b2290ab":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_4abbe0d8e0fa4e1b9d712743013b2d4e","max":17739960,"min":0,"orientation":"horizontal","style":"IPY_MODEL_661c7494ef2d47c794e6236e5f2c8978","value":17739960}},"9988b4433d6e4c58a819a2e1b54f57b2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9d7b5e47af9448c98a2a434f02b54633":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":"center","align_self":null,"border":null,"bottom":null,"display":"flex","flex":null,"flex_flow":"column","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50%"}},"a3ebe0f0e6e44522a2545db0ed47af62":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a435c85128f148cb80152d03825710e2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a80c0fb6a1254bb9a00741c1346b9d9a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_46ac2d0bfedc47c8836e8dde0fc91662","placeholder":"","style":"IPY_MODEL_58b140d0453a4a219bc64e0152cc5c5e","value":" 26.6M/26.6M [00:00<00:00, 104MB/s]"}},"a8e61b300a324911b1d3babf6b1ebac1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"Add token as git credential?","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_5253489738b249f69b30f1c84884a95a","style":"IPY_MODEL_3f500b1182a945c3b8b546b1bd04f98e","value":true}},"a987408c2f994329a9a80208b22e3c52":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_517a1b1faec045f7847ca84f0538f4e1","placeholder":"","style":"IPY_MODEL_008a47e4d1174b188e75232fed325398","value":"pytorch_model.bin: 100%"}},"ae378b480ed747438bcbe147a7e8d277":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b02b253086e34249ae1d896a75a08960":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"b22a1d21940e4995b72642b003ae1301":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"b33021db4313476ab8bcb85bb1b190d7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b55e95f31216480fa6c81bd1b57ad729":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b5f4829158cf4a5c8350966d8eacbf60":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_b33021db4313476ab8bcb85bb1b190d7","max":5905440,"min":0,"orientation":"horizontal","style":"IPY_MODEL_6d5431955c09424a96e825aa9bba1b62","value":5905440}},"b852998433e24f7fad1fe27e249085f9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"b8861f8cb72c4e65afac6519b7004170":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b9d9acd287c345debdff1e72a85641af":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bc4d3f45eaf04cccb7a655ef87d7a927":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"be8b64ce7f8247499c8bbcb62c5dd902":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bf644ae3e2894787bb416740749200cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_2be7c1f5fe32462f8d1cd7ea57cfbf3a","placeholder":"","style":"IPY_MODEL_d6135ce9cfaa4f8496a70cee4f1e89a7","value":"config.yaml: 100%"}},"c3b3069a93994e55b993cab04c066f17":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c955f8144b46451493474e02726b5deb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_754a843fd634446b8d246998eaded1fa","max":399,"min":0,"orientation":"horizontal","style":"IPY_MODEL_1e53e26668aa4f8dabdd6973b79b5b9f","value":399}},"c9eeb26bd5e049f89205e494d54e3818":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_cf5ae82d36384a728d8ca893cc27392b","placeholder":"","style":"IPY_MODEL_5cc77ca8ba304ad88342ed6ced6c6a4a","value":" 399/399 [00:00<00:00, 24.8kB/s]"}},"cf5ae82d36384a728d8ca893cc27392b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d1863b2c9ebc4efa9cac2dad7dfaf53a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d304f698c6f34f3692548267ca0aba47":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d4d428f0b0c44756a128adae747716d2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d6135ce9cfaa4f8496a70cee4f1e89a7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"dc9c065286e544df921e5bc4a51faf64":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e8b3188ee4934ab4becbc431fc4ccb0b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e98b1f7ec5e04e748069340fa2fcec2d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ea03f9526a7440a0a9a281ee877892fd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b9d9acd287c345debdff1e72a85641af","placeholder":"","style":"IPY_MODEL_91ca95844e084619b9ae01fe8176f875","value":" 1.98k/1.98k [00:00<00:00, 122kB/s]"}},"ef6be001daaa465598bdf20c304bae0b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"PasswordModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"PasswordModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"PasswordView","continuous_update":true,"description":"Token:","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_90533da4fc1341a28bc247bc9fbbbe9e","placeholder":"","style":"IPY_MODEL_6556790d1997431a8476447297e3f595","value":""}},"f18c80869ccc4ce1b2a215293d493e19":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_9025d2b6c7b14162a692b98c3e86ec8a","max":277,"min":0,"orientation":"horizontal","style":"IPY_MODEL_6c361855da5e4eb78e311defb2ca2f2b","value":277}},"f744ac29ccdd4d9d91050fabaed13e16":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b8861f8cb72c4e65afac6519b7004170","placeholder":"","style":"IPY_MODEL_668a49e70c2b4c8a9dcb534cb30714d6","value":"config.yaml: 100%"}},"f77186e2976d4a7daa798fd9f0f7b4cb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":""}},"f7be373f08c64c8bb5b6e070a7373cca":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f8df65e5ad6444648681230f415b8d08":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_3f69734124f7449da0efffbbfd1153fe","placeholder":"","style":"IPY_MODEL_686b58e0ccee468f938ea5659f3a9623","value":"config.yaml: 100%"}},"f9969c7acd834359bd67e83c31b82c0b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_253408a6cab947c7b9ae40a14e255328","placeholder":"","style":"IPY_MODEL_a435c85128f148cb80152d03825710e2","value":" Copy a token from your Hugging Face\ntokens page and paste it below. Immediately click login after copying\nyour token or it might be stored in plain text in this notebook file. "}},"ff048516fdba44a48a69c51a82aa7aaa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_775611277f1948a5ab95641c4e92ff2e","IPY_MODEL_c955f8144b46451493474e02726b5deb","IPY_MODEL_c9eeb26bd5e049f89205e494d54e3818"],"layout":"IPY_MODEL_d4d428f0b0c44756a128adae747716d2"}}}}},"nbformat":4,"nbformat_minor":0}
diff --git a/tutorials/assets/download-model.png b/tutorials/assets/download-model.png
index 4ca5350f5..810500178 100644
Binary files a/tutorials/assets/download-model.png and b/tutorials/assets/download-model.png differ
diff --git a/tutorials/community/offline_usage_speaker_diarization.ipynb b/tutorials/community/offline_usage_speaker_diarization.ipynb
new file mode 100644
index 000000000..932742628
--- /dev/null
+++ b/tutorials/community/offline_usage_speaker_diarization.ipynb
@@ -0,0 +1,172 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Offline Speaker Diarization (speaker-diarization-3.1)\n",
+ "\n",
+ "This notebooks gives a short introduction how to use the [speaker-diarization-3.1](https://huggingface.co/pyannote/speaker-diarization-3.1) pipeline with local models.\n",
+ "\n",
+ "In order to use local models, you first need to download them from huggingface and place them in a local folder. \n",
+ "Then you need to create a local config file, similar to the one in HF, but with local model paths.\n",
+ "\n",
+ "❗ **Naming of the model files is REALLY important! See end of notebook for details.** ❗\n",
+ "\n",
+ "## Get the models\n",
+ "\n",
+ "1. Install the `pyannote-audio` package: `!pip install pyannote.audio`\n",
+ "2. Create a huggingface account https://huggingface.co/join\n",
+ "3. Accept [pyannote/segmentation-3.0](https://hf.co/pyannote/segmentation-3.0) user conditions\n",
+ "4. Create a local folder `models`, place all downloaded files there\n",
+ " 1. [wespeaker-voxceleb-resnet34-LM](https://huggingface.co/pyannote/wespeaker-voxceleb-resnet34-LM/blob/main/pytorch_model.bin), to be placed in `models/pyannote_model_wespeaker-voxceleb-resnet34-LM.bin`\n",
+ " 2. [segmentation-3.0](https://huggingface.co/pyannote/segmentation-3.0/blob/main/pytorch_model.bin), to be placed in `models/pyannote_model_segmentation-3.0.bin`\n",
+ "\n",
+ "Running `ls models` should show the following files:\n",
+ "```\n",
+ "pyannote_model_segmentation-3.0.bin (5.7M)\n",
+ "pyannote_model_wespeaker-voxceleb-resnet34-LM.bin (26MB)\n",
+ "```\n",
+ "\n",
+ "❗ **make sure the 'wespeaker-voxceleb-resnet34-LM' model is named 'pyannote_model_wespeaker-voxceleb-resnet34-LM.bin'** ❗"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Config for local models\n",
+ "\n",
+ "Create a local config, similar to the one in HF: [speaker-diarization-3.1/blob/main/config.yaml](https://huggingface.co/pyannote/speaker-diarization-3.1/blob/main/config.yaml), but with local model paths\n",
+ "\n",
+ "Contents of `models/pyannote_diarization_config.yaml`:\n",
+ "\n",
+ "```yaml\n",
+ "version: 3.1.0\n",
+ "\n",
+ "pipeline:\n",
+ " name: pyannote.audio.pipelines.SpeakerDiarization\n",
+ " params:\n",
+ " clustering: AgglomerativeClustering\n",
+ " # embedding: pyannote/wespeaker-voxceleb-resnet34-LM # if you want to use the HF model\n",
+ " embedding: models/pyannote_model_wespeaker-voxceleb-resnet34-LM.bin # if you want to use the local model\n",
+ " embedding_batch_size: 32\n",
+ " embedding_exclude_overlap: true\n",
+ " # segmentation: pyannote/segmentation-3.0 # if you want to use the HF model\n",
+ " segmentation: models/pyannote_model_segmentation-3.0.bin # if you want to use the local model\n",
+ " segmentation_batch_size: 32\n",
+ "\n",
+ "params:\n",
+ " clustering:\n",
+ " method: centroid\n",
+ " min_cluster_size: 12\n",
+ " threshold: 0.7045654963945799\n",
+ " segmentation:\n",
+ " min_duration_off: 0.0\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Loading the local pipeline\n",
+ "\n",
+ "**Hint**: The paths in the config are relative to the current working directory, not relative to the config file.\n",
+ "If you want to start your notebook/script from a different directory, you can use `os.chdir` temporarily, to 'emulate' config-relative paths.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from pathlib import Path\n",
+ "from pyannote.audio import Pipeline\n",
+ "\n",
+ "def load_pipeline_from_pretrained(path_to_config: str | Path) -> Pipeline:\n",
+ " path_to_config = Path(path_to_config)\n",
+ "\n",
+ " print(f\"Loading pyannote pipeline from {path_to_config}...\")\n",
+ " # the paths in the config are relative to the current working directory\n",
+ " # so we need to change the working directory to the model path\n",
+ " # and then change it back\n",
+ "\n",
+ " cwd = Path.cwd().resolve() # store current working directory\n",
+ "\n",
+ " # first .parent is the folder of the config, second .parent is the folder containing the 'models' folder\n",
+ " cd_to = path_to_config.parent.parent.resolve()\n",
+ "\n",
+ " print(f\"Changing working directory to {cd_to}\")\n",
+ " os.chdir(cd_to)\n",
+ "\n",
+ " pipeline = Pipeline.from_pretrained(path_to_config)\n",
+ "\n",
+ " print(f\"Changing working directory back to {cwd}\")\n",
+ " os.chdir(cwd)\n",
+ "\n",
+ " return pipeline\n",
+ "\n",
+ "PATH_TO_CONFIG = \"path/to/your/pyannote_diarization_config.yaml\"\n",
+ "pipeline = load_pipeline_from_pretrained(PATH_TO_CONFIG)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Notes on file naming (pyannote-audio 3.1.1)\n",
+ "\n",
+ "Pyannote uses some internal logic to determine the model type.\n",
+ "\n",
+ "The funtion `def PretrainedSpeakerEmbedding(...` in (speaker_verification.py)[https://github.com/pyannote/pyannote-audio/blob/develop/pyannote/audio/pipelines/speaker_verification.py#L712] uses the the file path of the model to infer the model type.\n",
+ "\n",
+ "```python\n",
+ "def PretrainedSpeakerEmbedding(\n",
+ " embedding: PipelineModel,\n",
+ " device: torch.device = None,\n",
+ " use_auth_token: Union[Text, None] = None,\n",
+ "):\n",
+ " #...\n",
+ " if isinstance(embedding, str) and \"pyannote\" in embedding:\n",
+ " return PyannoteAudioPretrainedSpeakerEmbedding(\n",
+ " embedding, device=device, use_auth_token=use_auth_token\n",
+ " )\n",
+ "\n",
+ " elif isinstance(embedding, str) and \"speechbrain\" in embedding:\n",
+ " return SpeechBrainPretrainedSpeakerEmbedding(\n",
+ " embedding, device=device, use_auth_token=use_auth_token\n",
+ " )\n",
+ "\n",
+ " elif isinstance(embedding, str) and \"nvidia\" in embedding:\n",
+ " return NeMoPretrainedSpeakerEmbedding(embedding, device=device)\n",
+ "\n",
+ " elif isinstance(embedding, str) and \"wespeaker\" in embedding:\n",
+ " return ONNXWeSpeakerPretrainedSpeakerEmbedding(embedding, device=device) # <-- this is called, but the wespeaker-voxceleb-resnet34-LM is not an ONNX model\n",
+ "\n",
+ " else:\n",
+ " # fallback to pyannote in case we are loading a local model\n",
+ " return PyannoteAudioPretrainedSpeakerEmbedding(\n",
+ " embedding, device=device, use_auth_token=use_auth_token\n",
+ " )\n",
+ "```\n",
+ "\n",
+ "The [wespeaker-voxceleb-resnet34-LM](https://huggingface.co/pyannote/wespeaker-voxceleb-resnet34-LM/blob/main/pytorch_model.bin) model is not an ONNX model, but a `PyannoteAudioPretrainedSpeakerEmbedding`. So if `wespeaker` is in the file name, the code will infer the model type incorrectly. If `pyannote` is somewhere in the file name, the model type will be inferred correctly, as the first if statement will be true..."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.11.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tutorials/intro.ipynb b/tutorials/intro.ipynb
index 572ea2f6d..328ddceaf 100644
--- a/tutorials/intro.ipynb
+++ b/tutorials/intro.ipynb
@@ -10,15 +10,6 @@
""
]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "9-KmdPlBYnp6"
- },
- "source": [
- ""
- ]
- },
{
"cell_type": "markdown",
"metadata": {
@@ -622,7 +613,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.5"
+ "version": "3.10.13"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
diff --git a/tutorials/overlapped_speech_detection.ipynb b/tutorials/overlapped_speech_detection.ipynb
index 1ad5d4090..9211f0626 100644
--- a/tutorials/overlapped_speech_detection.ipynb
+++ b/tutorials/overlapped_speech_detection.ipynb
@@ -1,13 +1,41 @@
{
"cells": [
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"metadata": {},
- "outputs": [],
"source": [
- "# TODO: switch to AMI\n",
- "PROTOCOL = 'Debug.SpeakerDiarization.Debug'"
+ ""
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Finetuning a segmentation model on an overlapped speech detection task with `pyannote.audio`\n",
+ "\n",
+ "Overlapped speech detection (OSD) is the task of detecting regions where at least two speakers are speaking at the same time. In this notebook, we will finetune a segmentation model on the OSD task, then evaluate an OSD pipeline on AMI database."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Tutorial setup"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### `Google Colab` setup"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you are running this tutorial on `Colab`, execute the following commands in order to setup `Colab` environment. These commands will install `pyannote.audio` and download a mini version of the `AMI` corpus."
]
},
{
@@ -16,17 +44,49 @@
"metadata": {},
"outputs": [],
"source": [
- "# TODO: update this tutorial to do fine tuning of a model pretrained on DIHARD"
+ "!pip install -qq pyannote.audio==3.1.1\n",
+ "!pip install -qq ipython==7.34.0\n",
+ "!git clone https://github.com/pyannote/AMI-diarization-setup.git\n",
+ "%cd ./AMI-diarization-setup/pyannote/\n",
+ "!bash ./download_ami_mini.sh\n",
+ "%cd /content"
]
},
{
- "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Overlapped speech detection with `pyannote.audio`\n",
- "\n",
- "Overlapped speech detection (OSD) is the task of detecting regions where at least two speakers are speaking at the same time. In this notebook, we will train and evaluate an OSD pipeline on Debug database."
+ "⚠ Restart the runtime (Runtime > Restart session)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Non `Google Colab` setup"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you are not using `Colab`, this tutorial assumes that\n",
+ "* `pyannote.audio` has been installed\n",
+ "* the [AMI corpus](https://groups.inf.ed.ac.uk/ami/corpus/) has already been [setup for use with `pyannote`](https://github.com/pyannote/AMI-diarization-setup/tree/main/pyannote)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Protocol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Firstly, we define a protocol, here `AMI.SpeakerDiarization.mini`"
]
},
{
@@ -35,8 +95,10 @@
"metadata": {},
"outputs": [],
"source": [
- "from pyannote.database import get_protocol, FileFinder\n",
- "protocol = get_protocol(PROTOCOL, preprocessors={\"audio\": FileFinder()})"
+ "from pyannote.database import registry, FileFinder\n",
+ "\n",
+ "registry.load_database(\"AMI-diarization-setup/pyannote/database.yml\")\n",
+ "protocol = registry.get_protocol(\"AMI.SpeakerDiarization.mini\", preprocessors={\"audio\": FileFinder()})"
]
},
{
@@ -60,7 +122,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
@@ -79,9 +141,21 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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BRdcoF69eikoKEgff/yx3feB6jPr16/XqaeeqsjISKWnp+vpp582O2tAp3HXj5qbm3X//fdrxIgR6tatm3r16qVrrrlGe/bssYuDfoSjnaf5yNYtt9yioKAgPf/883af04/ARgQOeUuWLNHkyZO1fPlyLVy4UM3NzRozZowOHDhgDTNlyhR9+umn+uijj7RkyRLt2bNHl1xyifX7lpYWjRs3Tk1NTfrhhx/0zjvv6O2339bUqVO7IktAl1m5cqVeffVVjRw50u5z+hDgXmVlpU4++WSFhYVp3rx52rx5s/75z38qMTHRGubpp5/Wiy++qFdeeUU//vijunXrprFjx6qhocEa5sorr9SmTZu0cOFCffbZZ/r222910003dUWWgE731FNP6eWXX9ZLL72kLVu26KmnntLTTz+tf/3rX9Yw9CPA3oEDB3Tsscfq3//+t9PvA9FnampqNGbMGGVmZmr16tV65pln9Le//U2vvfaa6fkDOoO7flRXV6effvpJDz30kH766SfNnj1bOTk5uvDCC+3C0Y9wtPM0H1nMmTNHy5cvV69evdp9Rz+CDOAwU1paakgylixZYhiGYVRVVRlhYWHGRx99ZA2zZcsWQ5KxbNkywzAM44svvjCCg4ON4uJia5iXX37ZiIuLMxobGzs3A0AXqa2tNQYOHGgsXLjQOP3004277rrLMAz6EOCN+++/3zjllFNcft/a2mqkpaUZzzzzjPWzqqoqIyIiwpg5c6ZhGIaxefNmQ5KxcuVKa5h58+YZQUFBxu7du81LPHCIGDdunHH99dfbfXbJJZcYV155pWEY9CPAE0nGnDlzrO8D1WemTZtmJCYm2q3p7r//fmPw4MEm5wjofI79yJkVK1YYkoyCggLDMOhHgCNX/WjXrl1G7969jY0bNxqZmZnGc889Z/2OfgTDMAz+IgKHnerqaklS9+7dJUmrV69Wc3OzzjnnHGuYIUOGKCMjQ8uWLZMkLVu2TCNGjFBqaqo1zNixY1VTU6NNmzZ1YuqBrjN58mSNGzfOrq9I9CHAG5988olGjx6tyy67TCkpKRo1apRef/116/c7d+5UcXGxXT+Kj4/XCSecYNePEhISNHr0aGuYc845R8HBwfrxxx87LzNAFznppJP09ddfKzc3V5K0bt06LV26VOeff74k+hHgq0D1mWXLlum0005TeHi4NczY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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"first_training_file['annotation']"
]
@@ -96,9 +170,21 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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HtXV1TFs2LD49re/He+99153dwV6xJYtW2LOnDkxfvz4GDhwYHz2s5+Nq666KlJK+TLiCAo98cQTccIJJ0RtbW1UVFTE73//+4L95YqZZcuWxRe+8IXYeeedY8yYMXHDDTdk3TXoNh3F0ebNm+PSSy+NCRMmxC677BK1tbXxjW98I1atWlVQhzhie7et81Fr55xzTlRUVMRPfvKTgu3iCIkIer3HH388Zs6cGU8//XQ0NjbG5s2bY9q0afH+++/ny1x00UXxwAMPxL333huPP/54rFq1Kk4++eT8/i1btsTxxx8fH3/8cfz973+Pu+66K371q1/F3Llze6JL0GMWL14ct99+exx00EEF28UQdOzdd9+Nww47LHbcccd46KGH4qWXXoof/ehHMXz48HyZG264IW655Za47bbbYtGiRbHLLrvEscceGx9++GG+zPTp0+PFF1+MxsbGePDBB+OJJ56Is88+uye6BN3u+uuvj3nz5sWtt94aL7/8clx//fVxww03xE9/+tN8GXEEhd5///04+OCD42c/+1mb+8sRM83NzTFt2rQYO3ZsLFmyJG688ca48sor44477si8f9AdOoqjTZs2xdKlS2POnDmxdOnSuO+++2LFihVx4oknFpQTR2zvtnU+yrn//vvj6aefjtra2q32iSMiQR+zbt26FBHp8ccfTymltH79+rTjjjume++9N1/m5ZdfThGRnnrqqZRSSn/6059SZWVlWrNmTb7MvHnzUnV1dfroo4+6twPQQzZu3Jj22Wef1NjYmI488sh04YUXppTEEJTi0ksvTYcffni7+1taWtLIkSPTjTfemN+2fv36NGDAgPTrX/86pZTSSy+9lCIiLV68OF/moYceShUVFemtt97KrvHQSxx//PHpW9/6VsG2k08+OU2fPj2lJI5gWyIi3X///fnfyxUzP//5z9Pw4cMLrukuvfTStO+++2bcI+h+xXHUlmeeeSZFRHr99ddTSuIIirUXR//+97/TnnvumZYvX57Gjh2bbrrppvw+cURKKflEBH3Ohg0bIiJi1113jYiIJUuWxObNm+OYY47Jl9lvv/1ir732iqeeeioiIp566qmYMGFC1NTU5Msce+yx0dzcHC+++GI3th56zsyZM+P4448viJUIMQSl+OMf/xhTpkyJU089NUaMGBETJ06MO++8M79/5cqVsWbNmoI4Gjp0aNTX1xfE0bBhw2LKlCn5Msccc0xUVlbGokWLuq8z0EMOPfTQePTRR+OVV16JiIjnn38+nnzyyTjuuOMiQhxBZ5UrZp566qk44ogjYqeddsqXOfbYY2PFihXx7rvvdlNvoPfYsGFDVFRUxLBhwyJCHEEpWlpaoqGhIS655JKoq6vbar84IiKiqqcbAJ3R0tISs2bNisMOOywOPPDAiIhYs2ZN7LTTTvmLhJyamppYs2ZNvkzrB6i5/bl90N8tWLAgli5dGosXL95qnxiCbfvnP/8Z8+bNi4svvji+//3vx+LFi+OCCy6InXbaKc4888x8HLQVJ63jaMSIEQX7q6qqYtdddxVHbBcuu+yyaG5ujv322y922GGH2LJlS1x99dUxffr0iAhxBJ1UrphZs2ZNjB8/fqs6cvta/xlC6O8+/PDDuPTSS+P000+P6urqiBBHUIrrr78+qqqq4oILLmhzvzgiQiKCPmbmzJmxfPnyePLJJ3u6KdBnvPnmm3HhhRdGY2Nj7Lzzzj3dHOiTWlpaYsqUKXHNNddERMTEiRNj+fLlcdttt8WZZ57Zw62DvuG3v/1t3H333XHPPfdEXV1dNDU1xaxZs6K2tlYcAdDjNm/eHKeddlqklGLevHk93RzoM5YsWRI333xzLF26NCoqKnq6OfRi/jQTfcZ5550XDz74YCxcuDBGjx6d3z5y5Mj4+OOPY/369QXl165dGyNHjsyXWbt27Vb7c/ugP1uyZEmsW7cuJk2aFFVVVVFVVRWPP/543HLLLVFVVRU1NTViCLZh1KhRccABBxRs23///eONN96IiP/FQVtx0jqO1q1bV7D/k08+iXfeeUccsV245JJL4rLLLouvf/3rMWHChGhoaIiLLroorr322ogQR9BZ5YoZ13nwvyTE66+/Ho2NjflPQ0SII9iWv/71r7Fu3brYa6+98s8cXn/99Zg9e3aMGzcuIsQR/0cigl4vpRTnnXde3H///fHYY49t9TGtyZMnx4477hiPPvpoftuKFSvijTfeiKlTp0ZExNSpU+OFF14oWPRyFxfFD5agvzn66KPjhRdeiKampvy/KVOmxPTp0/M/iyHo2GGHHRYrVqwo2PbKK6/E2LFjIyJi/PjxMXLkyII4am5ujkWLFhXE0fr162PJkiX5Mo899li0tLREfX19N/QCetamTZuisrLw9mOHHXaIlpaWiBBH0FnlipmpU6fGE088EZs3b86XaWxsjH333defwWC7kEtCvPrqq/HnP/85dtttt4L94gg61tDQEMuWLSt45lBbWxuXXHJJPPLIIxEhjvj/evrbsmFbzj333DR06ND0l7/8Ja1evTr/b9OmTfky55xzTtprr73SY489lp599tk0derUNHXq1Pz+Tz75JB144IFp2rRpqampKT388MNpjz32SJdffnlPdAl63JFHHpkuvPDC/O9iCDr2zDPPpKqqqnT11VenV199Nd19991p0KBBaf78+fky1113XRo2bFj6wx/+kJYtW5a+8pWvpPHjx6cPPvggX+bLX/5ymjhxYlq0aFF68skn0z777JNOP/30nugSdLszzzwz7bnnnunBBx9MK1euTPfdd1/afffd0/e+9718GXEEhTZu3Jiee+659Nxzz6WISD/+8Y/Tc889l15//fWUUnliZv369ammpiY1NDSk5cuXpwULFqRBgwal22+/vdv7C1noKI4+/vjjdOKJJ6bRo0enpqamgmcOH330Ub4OccT2blvno2Jjx45NN910U8E2cYREBL1eRLT575e//GW+zAcffJC++93vpuHDh6dBgwalr371q2n16tUF9fzrX/9Kxx13XBo4cGDafffd0+zZs9PmzZu7uTfQOxQnIsQQbNsDDzyQDjzwwDRgwIC03377pTvuuKNgf0tLS5ozZ06qqalJAwYMSEcffXRasWJFQZm33347nX766Wnw4MGpuro6nXXWWWnjxo3d2Q3oMc3NzenCCy9Me+21V9p5553TZz7zmfSDH/yg4EGPOIJCCxcubPNe6Mwzz0wplS9mnn/++XT44YenAQMGpD333DNdd9113dVFyFxHcbRy5cp2nzksXLgwX4c4Ynu3rfNRsbYSEeKIipRS6o5PXgAAAAAAANsf3xEBAAAAAABkRiICAAAAAADIjEQEAAAAAACQGYkIAAAAAAAgMxIRAAAAAABAZiQiAAAAAACAzEhEAAAAAAAAmZGIAAAACnzzm9+Mk046qaebAQAA9BNVPd0AAACg+1RUVHS4/4orroibb745Ukrd1CIAAKC/k4gAAIDtyOrVq/M//+Y3v4m5c+fGihUr8tsGDx4cgwcP7ommAQAA/ZQ/zQQAANuRkSNH5v8NHTo0KioqCrYNHjx4qz/N9MUvfjHOP//8mDVrVgwfPjxqamrizjvvjPfffz/OOuusGDJkSOy9997x0EMPFbzX8uXL47jjjovBgwdHTU1NNDQ0xH//+99u7jEAANDTJCIAAIBtuuuuu2L33XePZ555Js4///w499xz49RTT41DDz00li5dGtOmTYuGhobYtGlTRESsX78+jjrqqJg4cWI8++yz8fDDD8fatWvjtNNO6+GeAAAA3U0iAgAA2KaDDz44fvjDH8Y+++wTl19+eey8886x++67x3e+853YZ599Yu7cufH222/HsmXLIiLi1ltvjYkTJ8Y111wT++23X0ycODF+8YtfxMKFC+OVV17p4d4AAADdyXdEAAAA23TQQQflf95hhx1it912iwkTJuS31dTURETEunXrIiLi+eefj4ULF7b5fROvvfZafO5zn8u4xQAAQG8hEQEAAGzTjjvuWPB7RUVFwbaKioqIiGhpaYmIiPfeey9OOOGEuP7667eqa9SoURm2FAAA6G0kIgAAgLKbNGlS/O53v4tx48ZFVZXbDgAA2J75jggAAKDsZs6cGe+8806cfvrpsXjx4njttdfikUceibPOOiu2bNnS080DAAC6kUQEAABQdrW1tfG3v/0ttmzZEtOmTYsJEybErFmzYtiwYVFZ6TYEAAC2JxUppdTTjQAAAAAAAPon/xUJAAAAAADIjEQEAAAAAACQGYkIAAAAAAAgMxIRAAAAAABAZiQiAAAAAACAzEhEAAAAAAAAmZGIAAAAAAAAMiMRAQAAAAAAZEYiAgAAAAAAyIxEBAAAAAAAkBmJCAAAAAAAIDMSEQAAAAAAQGb+H3i6QsDNwRxqAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ", , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , |