def __init__(
        self,
        root_dir=None,
        use_memmap=False,
        sliding_window=None,
        dimension=None,
        classes=None,
        augmentation=None,
    ):

        if augmentation is not None:
            msg = "Data augmentation is not supported by `Precomputed`."
            raise ValueError(msg)

        super(Precomputed, self).__init__()
        self.root_dir = Path(root_dir).expanduser().resolve(strict=False)
        self.use_memmap = use_memmap

        path = self.root_dir / "metadata.yml"
        if path.exists():

            with io.open(path, "r") as f:
                params = yaml.load(f, Loader=yaml.SafeLoader)

            self.dimension_ = params.pop("dimension")
            self.classes_ = params.pop("classes", None)
            self.sliding_window_ = SlidingWindow(**params)

            if dimension is not None and self.dimension_ != dimension:
                msg = 'inconsistent "dimension" (is: {0}, should be: {1})'
                raise ValueError(msg.format(dimension, self.dimension_))

            if classes is not None and self.classes_ != classes:
                msg = 'inconsistent "classes" (is {0}, should be: {1})'
                raise ValueError(msg.format(classes, self.classes_))

            if (sliding_window is not None) and (
                (sliding_window.start != self.sliding_window_.start)
                or (sliding_window.duration != self.sliding_window_.duration)
                or (sliding_window.step != self.sliding_window_.step)
            ):
                msg = 'inconsistent "sliding_window"'
                raise ValueError(msg)

        else:

            if dimension is None:
                if classes is None:
                    msg = (
                        f"Please provide either `dimension` or `classes` "
                        f"parameters (or both) when instantiating "
                        f"`Precomputed`."
                    )
                dimension = len(classes)

            if sliding_window is None or dimension is None:
                msg = (
                    f"Either directory {self.root_dir} does not exist or it "
                    f"does not contain precomputed features. In case it exists "
                    f"and this was done on purpose, please provide both "
                    f"`sliding_window` and `dimension` parameters when "
                    f"instantianting `Precomputed`."
                )
                raise ValueError(msg)

            # create parent directory
            mkdir_p(path.parent)

            params = {
                "start": sliding_window.start,
                "duration": sliding_window.duration,
                "step": sliding_window.step,
                "dimension": dimension,
            }
            if classes is not None:
                params["classes"] = classes

            with io.open(path, "w") as f:
                yaml.dump(params, f, default_flow_style=False)

            self.sliding_window_ = sliding_window
            self.dimension_ = dimension
            self.classes_ = classes
 def dump(self, item, features):
     path = Path(self.get_path(item))
     mkdir_p(path.parent)
     np.save(path, features.data)
Пример #3
0
_ZIP_URL = f'{_HUB_REPO}/raw/master/{{kind}}s/{{name}}.zip'
_PRETRAINED_URL = f'{_HUB_REPO}/raw/master/pretrained.yml'

# path where pre-trained models and pipelines are downloaded and cached
_HUB_DIR = pathlib.Path(os.environ.get(
    "PYANNOTE_AUDIO_HUB", "~/.pyannote/hub")).expanduser().resolve()

# download pretrained.yml if needed
_PRETRAINED_YML = _HUB_DIR / 'pretrained.yml'

if not _PRETRAINED_YML.exists():
    msg = (f'Downloading list of pretrained models and pipelines '
           f'to "{_PRETRAINED_YML}".')
    print(msg)
    from pyannote.audio.utils.path import mkdir_p
    mkdir_p(_PRETRAINED_YML.parent)
    torch.hub.download_url_to_file(_PRETRAINED_URL,
                                   _PRETRAINED_YML,
                                   progress=True)


def _generic(
        name: str,
        duration: float = None,
        step: float = 0.25,
        batch_size: int = 32,
        device: typing.Optional[typing.Union[typing.Text,
                                             torch.device]] = None,
        pipeline: typing.Optional[bool] = None,
        force_reload: bool = False) -> typing.Union[_Pretrained, _Pipeline]:
    """Load pretrained model or pipeline
Пример #4
0
def _generic(
        name: str,
        duration: float = None,
        step: float = 0.25,
        batch_size: int = 32,
        device: typing.Optional[typing.Union[typing.Text,
                                             torch.device]] = None,
        pipeline: typing.Optional[bool] = None,
        force_reload: bool = False) -> typing.Union[_Pretrained, _Pipeline]:
    """Load pretrained model or pipeline

    Parameters
    ----------
    name : str
        Name of pretrained model or pipeline
    duration : float, optional
        Override audio chunks duration.
        Defaults to the one used during training.
    step : float, optional
        Ratio of audio chunk duration used for the internal sliding window.
        Defaults to 0.25 (i.e. 75% overlap between two consecutive windows).
        Reducing this value might lead to better results (at the expense of
        slower processing).
    batch_size : int, optional
        Batch size used for inference. Defaults to 32.
    device : torch.device, optional
        Device used for inference.
    pipeline : bool, optional
        Wrap pretrained model in a (not fully optimized) pipeline.
    force_reload : bool
        Whether to discard the existing cache and force a fresh download.
        Defaults to use existing cache.

    Returns
    -------
    pretrained: `Pretrained` or `Pipeline`

    Usage
    -----
    >>> sad_pipeline = torch.hub.load('pyannote/pyannote-audio', 'sad_ami')
    >>> scores = model({'audio': '/path/to/audio.wav'})
    """

    model_exists = name in _MODELS
    pipeline_exists = name in _PIPELINES

    if model_exists and pipeline_exists:

        if pipeline is None:
            msg = (
                f'Both a pretrained model and a pretrained pipeline called '
                f'"{name}" are available. Use option "pipeline=True" to '
                f'load the pipeline, and "pipeline=False" to load the model.')
            raise ValueError(msg)

        if pipeline:
            kind = 'pipeline'
            zip_url = _URL.format(kind=kind, name=name)
            sha256 = _PIPELINES[name]
            return_pipeline = True

        else:
            kind = 'model'
            zip_url = _URL.format(kind=kind, name=name)
            sha256 = _MODELS[name]
            return_pipeline = False

    elif pipeline_exists:

        if pipeline is None:
            pipeline = True

        if not pipeline:
            msg = (f'Could not find any pretrained "{name}" model. '
                   f'A pretrained "{name}" pipeline does exist. '
                   f'Did you mean "pipeline=True"?')
            raise ValueError(msg)

        kind = 'pipeline'
        zip_url = _URL.format(kind=kind, name=name)
        sha256 = _PIPELINES[name]
        return_pipeline = True

    elif model_exists:

        if pipeline is None:
            pipeline = False

        kind = 'model'
        zip_url = _URL.format(kind=kind, name=name)
        sha256 = _MODELS[name]
        return_pipeline = pipeline

        if name.startswith('emb_') and return_pipeline:
            msg = (
                f'Pretrained model "{name}" has no associated pipeline. Use '
                f'"pipeline=False" or remove "pipeline" option altogether.')
            raise ValueError(msg)

    else:
        msg = (
            f'Could not find any pretrained model nor pipeline called "{name}".'
        )
        raise ValueError(msg)

    if sha256 is None:
        msg = (f'Pretrained {kind} "{name}" is not available yet but will be '
               f'released shortly. Stay tuned...')
        raise NotImplementedError(msg)

    # path where pre-trained models and pipelines are downloaded and cached
    hub_dir = pathlib.Path(
        os.environ.get("PYANNOTE_AUDIO_HUB",
                       "~/.pyannote/hub")).expanduser().resolve()

    pretrained_dir = hub_dir / f'{kind}s'
    pretrained_subdir = pretrained_dir / f'{name}'
    pretrained_zip = pretrained_dir / f'{name}.zip'

    if not pretrained_subdir.exists() or force_reload:

        if pretrained_subdir.exists():
            shutil.rmtree(pretrained_subdir)

        from pyannote.audio.utils.path import mkdir_p
        mkdir_p(pretrained_zip.parent)
        try:
            msg = (
                f'Downloading pretrained {kind} "{name}" to "{pretrained_zip}".'
            )
            print(msg)
            torch.hub.download_url_to_file(zip_url,
                                           pretrained_zip,
                                           hash_prefix=sha256,
                                           progress=True)
        except RuntimeError as e:
            shutil.rmtree(pretrained_subdir)
            msg = (f'Failed to download pretrained {kind} "{name}".'
                   f'Please try again.')
            raise RuntimeError(msg)

        # unzip downloaded file
        with zipfile.ZipFile(pretrained_zip) as z:
            z.extractall(path=pretrained_dir)

    if kind == 'model':

        params_yml, = pretrained_subdir.glob('*/*/*/*/params.yml')
        pretrained = _Pretrained(validate_dir=params_yml.parent,
                                 duration=duration,
                                 step=step,
                                 batch_size=batch_size,
                                 device=device)

        if return_pipeline:
            if name.startswith('sad_'):
                from pyannote.audio.pipeline.speech_activity_detection import SpeechActivityDetection
                pipeline = SpeechActivityDetection(scores=pretrained)
            elif name.startswith('scd_'):
                from pyannote.audio.pipeline.speaker_change_detection import SpeakerChangeDetection
                pipeline = SpeakerChangeDetection(scores=pretrained)
            elif name.startswith('ovl_'):
                from pyannote.audio.pipeline.overlap_detection import OverlapDetection
                pipeline = OverlapDetection(scores=pretrained)
            else:
                # this should never happen
                msg = (
                    f'Pretrained model "{name}" has no associated pipeline. Use '
                    f'"pipeline=False" or remove "pipeline" option altogether.'
                )
                raise ValueError(msg)

            return pipeline.load_params(params_yml)

        return pretrained

    elif kind == 'pipeline':

        params_yml, = pretrained_subdir.glob('*/*/params.yml')

        config_yml = params_yml.parents[2] / 'config.yml'
        with open(config_yml, 'r') as fp:
            config = yaml.load(fp, Loader=yaml.SafeLoader)

        from pyannote.core.utils.helper import get_class_by_name
        pipeline_name = config['pipeline']['name']
        Pipeline = get_class_by_name(
            pipeline_name, default_module_name='pyannote.audio.pipeline')
        pipeline = Pipeline(**config['pipeline'].get('params', {}))

        return pipeline.load_params(params_yml)
Пример #5
0
    def __init__(self,
                 root_dir=None,
                 use_memmap=False,
                 sliding_window=None,
                 dimension=None,
                 classes=None,
                 augmentation=None):

        if augmentation is not None:
            msg = 'Data augmentation is not supported by `Precomputed`.'
            raise ValueError(msg)

        super(Precomputed, self).__init__()
        self.root_dir = Path(root_dir).expanduser().resolve(strict=False)
        self.use_memmap = use_memmap

        path = self.root_dir / 'metadata.yml'
        if path.exists():

            with io.open(path, 'r') as f:
                params = yaml.load(f, Loader=yaml.SafeLoader)

            self.dimension_ = params.pop('dimension')
            self.classes_ = params.pop('classes', None)
            self.sliding_window_ = SlidingWindow(**params)

            if dimension is not None and self.dimension_ != dimension:
                msg = 'inconsistent "dimension" (is: {0}, should be: {1})'
                raise ValueError(msg.format(dimension, self.dimensions_))

            if classes is not None and self.classes_ != classes:
                msg = 'inconsistent "classes" (is {0}, should be: {1})'
                raise ValueError(msg.format(classes, self.classes_))

            if ((sliding_window is not None) and
                ((sliding_window.start != self.sliding_window_.start) or
                 (sliding_window.duration != self.sliding_window_.duration) or
                 (sliding_window.step != self.sliding_window_.step))):
                msg = 'inconsistent "sliding_window"'
                raise ValueError(msg)

        else:

            if dimension is None:
                if classes is None:
                    msg = (f'Please provide either `dimension` or `classes` '
                           f'parameters (or both) when instantiating '
                           f'`Precomputed`.')
                dimension = len(classes)

            if sliding_window is None or dimension is None:
                msg = (
                    f'Either directory {self.root_dir} does not exist or it '
                    f'does not contain precomputed features. In case it exists '
                    f'and this was done on purpose, please provide both '
                    f'`sliding_window` and `dimension` parameters when '
                    f'instantianting `Precomputed`.')
                raise ValueError(msg)

            # create parent directory
            mkdir_p(path.parent)

            params = {
                'start': sliding_window.start,
                'duration': sliding_window.duration,
                'step': sliding_window.step,
                'dimension': dimension
            }
            if classes is not None:
                params['classes'] = classes

            with io.open(path, 'w') as f:
                yaml.dump(params, f, default_flow_style=False)

            self.sliding_window_ = sliding_window
            self.dimension_ = dimension
            self.classes_ = classes