o
    pi_Y                     @  sR  d dl mZ d dlZd dlZd dlZd dlmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZmZ d dlZd dlZd dlmZ d dlZd dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZm Z m!Z!m"Z" d dl#m$Z$ d dl%m&Z& d dl'm(Z(m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/ G dd dZ0eG dd dZ1G dd dej2Z3dS )    )annotationsN)	dataclass)cached_property)import_module)Path)AnyOptional)_load)ModelSummary)__version__)Audio)ProblemSpecificationsTaskUnknownSpecificationsError)track_model_init)check_dependencies)AssetFileNamedownload_from_hf_hub)map_with_specifications)SlidingWindow)
DataLoaderc                   @  s   e Zd ZdS )IntrospectionN)__name__
__module____qualname__ r   r   M/home/ubuntu/.local/lib/python3.10/site-packages/pyannote/audio/core/model.pyr   :   s    r   c                   @  s&   e Zd ZU ded< ded< ded< dS )Outputint
num_frames	dimensionr   framesN)r   r   r   __annotations__r   r   r   r   r   >   s   
 r   c                      sp  e Zd ZdZ			dbdc fd
dZeddddZejdeddZdd ZedfddZ	e	jdgddZ	e	j
dd Z	dhdiddZedjddZedkd!d"Zd#d$ Zdhd%d&Zd'd( Zdld+d,Zdmd/d0Zdnd2d3Zdod5d6Zd7d8 Zdod9d:Zd;d< Zd=d> ZdpdqdEdFZdrdGdHZdrdIdJZ	K	?dsdtdOdPZ	KdudvdRdSZ	KdudwdTdUZe 		K				dxdyd`daZ!  Z"S )zModela  Base model

    Parameters
    ----------
    sample_rate : int, optional
        Audio sample rate. Defaults to 16kHz (16000).
    num_channels : int, optional
        Number of channels. Defaults to mono (1).
    task : Task, optional
        Task addressed by the model.
    >     Nsample_rater   num_channelstaskTask | Nonec                   sB   t    |dksJ d| dd || _t| jjdd| _d S )Nr&   z7Only mono audio is supported for now (num_channels = 1)r'   r(   downmix)r'   mono)super__init__save_hyperparametersr)   r   hparamsr'   audio)selfr'   r(   r)   	__class__r   r   r.   R   s   

zModel.__init__returnr   c                 C  s   | j S N)_taskr2   r   r   r   r)   c   s   z
Model.taskc                 C  s   | ` || _d S r6   )specificationsr7   )r2   r)   r   r   r   r)   g   s   
c                 C  s   d S r6   r   r8   r   r   r   buildm   s   zModel.build&Specifications | tuple[Specifications]c              
   C  sF   | j d u rz| j}W |S  ty } ztd|d }~ww | j j}|S )NzModel specifications are not available because it has not been assigned a task yet. Use `model.task = ...` to assign a task to the model.)r)   _specificationsAttributeErrorr   r9   )r2   r9   er   r   r   r9   r   s   
zModel.specificationsr9   c                 C  sl   t |ttfstdtdd |D }t|dkrtdtdd |D }t|dkr1td|| _d S )NzEOnly regular specifications or tuple of specifications are supported.c                 s      | ]}|j V  qd S r6   )duration.0sr   r   r   	<genexpr>       z'Model.specifications.<locals>.<genexpr>r&   z1All tasks must share the same (maximum) duration.c                 s  r?   r6   )min_durationrA   r   r   r   rD      rE   z/All tasks must share the same minimum duration.)
isinstancer   tuple
ValueErrorsetlenr<   )r2   r9   	durationsmin_durationsr   r   r   r9      s   
c                 C  s   t | dr	| `d S d S )Nr<   )hasattrr<   r8   r   r   r   r9      s   
r@   float | Nonetorch.Tensorc                 C  s6   |p	t t| jj}tjd| jj| j	|f| j
dS )Nr&   )device)nextiterr9   r@   torchrandnr0   r(   r1   get_num_samplesrQ   )r2   r@   r   r   r   __example_input_array   s   
zModel.__example_input_arrayc                 C  s   |   S r6   )_Model__example_input_arrayr8   r   r   r   example_input_array   s   zModel.example_input_arrayr   c                 C  sZ   | j dd}| j dd| }| jdd|d d  }t|| jj || jj || jj dS )z(Internal) framesr&   )r       r   )frame)startr@   step)receptive_field_sizereceptive_field_centerr   r0   r'   )r2   r^   receptive_field_stepreceptive_field_startr   r   r   receptive_field   s   


zModel.receptive_fieldc                 C  s   | j   d S r6   )r)   prepare_datar8   r   r   r   rc         zModel.prepare_datac              
   C  s2  |dkr	| j | j_ | jr| j| tdd |  D }|  }|   z| j|dd\}}W n' tyW } zdt	|v rKd| j
 d}t| n|W Y d }~nd }~ww |  D ]\}}	|t|	f|vrn|	| j q\| jr| | j_| j  | j  td	d |  D }
td
d |
| D | _
d S )Nfitc                 s       | ]\}}|t |fV  qd S r6   idrB   namemoduler   r   r   rD          zModel.setup.<locals>.<genexpr>F)strictzsize mismatchzModel has been trained for a different task. For fine tuning or transfer learning, it is recommended to train task-dependent layers for a few epochs before training the whole model: .c                 s  rf   r6   rg   ri   r   r   r   rD      rl   c                 s  s    | ]\}}|V  qd S r6   r   )rB   rj   _r   r   r   rD      s    )trainerr)   setuprJ   named_modules
state_dictr:   load_state_dictRuntimeErrorstrtask_dependentwarningswarnrh   torQ   modelsetup_loss_funcsetup_validation_metriclist)r2   stagebeforeoriginal_state_dictmissing_keysunexpected_keysr>   msgrj   rk   afterr   r   r   rq      s@   


zModel.setupc                 C  s(   dt i| jj| jjd| jd|d< d S )Npyannote.audio)rk   class)versionsarchitecturer9   )r   r4   r   r   r9   r2   
checkpointr   r   r   on_save_checkpoint   s   zModel.on_save_checkpointr   dict[str, Any]c                 C  s   |d d | _ |   d S )Nr   r9   )r9   rq   r   r   r   r   on_load_checkpoint  s   zModel.on_load_checkpoint	waveforms"torch.Tensor | tuple[torch.Tensor]c                 K  s   d}t |)NzAClass {self.__class__.__name__} should define a `forward` method.)NotImplementedError)r2   r   kwargsr   r   r   r   forward  s   zModel.forwardnn.Module | tuple[nn.Module]c                 C  s   	dd	dd}t | j|S )
aT  Guess default activation function according to task specification

            * sigmoid for binary classification
            * log-softmax for regular multi-class classification
            * sigmoid for multi-label classification

        Returns
        -------
        activation : (tuple of) nn.Module
            Activation.
        Nr9   Specifications | Noner5   	nn.Modulec                 S  sL   | j tjkr
t S | j tjkrtjddS | j tjkr t S d}t|)N)dimz>TODO: implement default activation for other types of problems)	problemr   BINARY_CLASSIFICATIONnnSigmoidMONO_LABEL_CLASSIFICATION
LogSoftmaxMULTI_LABEL_CLASSIFICATIONr   )r9   r   r   r   r   __default_activation  s   z6Model.default_activation.<locals>.__default_activationr6   )r9   r   r5   r   )r   r9   )r2   _Model__default_activationr   r   r   default_activation  s   zModel.default_activationr   c                 C  
   | j  S r6   )r)   train_dataloaderr8   r   r   r   r   0     
zModel.train_dataloaderc                 C     | j ||S r6   )r)   training_stepr2   batch	batch_idxr   r   r   r   5  rd   zModel.training_stepc                 C  r   r6   )r)   val_dataloaderr8   r   r   r   r   :  r   zModel.val_dataloaderc                 C  r   r6   )r)   validation_stepr   r   r   r   r   ?  rd   zModel.validation_stepc                 C  s   t jj|  ddS )NgMbP?)lr)rT   optimAdam
parametersr8   r   r   r   configure_optimizersB  s   zModel.configure_optimizersFmodule_namerv   requires_gradbool	list[str]c           
      C  s   | d}t }t| ddjD ]?\}}| d}tdd t||D }|r1t|t|d kr1q|jddD ]}	||	_q7|j|d	 |	| ||krN nq||vrZt
d
| |S )z3Helper function for freeze_up_to and unfreeze_up_torn   r   )	max_depthc                 s  s     | ]\}}||kr|V  qd S r6   r   )rB   tokenother_tokenr   r   r   rD   M  s    z Model.__up_to.<locals>.<genexpr>r&   Trecurse)modezCould not find module )splitr~   r
   rr   ziprK   r   r   trainappendrI   )
r2   r   r   tokensupdated_modulesrj   rk   name_tokensmatching_tokens	parameterr   r   r   __up_toE  s&   


zModel.__up_toc                 C     | j |ddS )ac  Freeze model up to specific module

        Parameters
        ----------
        module_name : str
            Name of module (included) up to which the model will be frozen.

        Returns
        -------
        frozen_modules : list of str
            List of names of frozen modules

        Raises
        ------
        ValueError when requested module does not exist

        Note
        ----
        The order of modules is the one reported by self.summary("full").
        If your model does not follow a sequential structure, you might
        want to use freeze_by_name for more control.
        Fr   _Model__up_tor2   r   r   r   r   freeze_up_tog     zModel.freeze_up_toc                 C  r   )ai  Unfreeze model up to specific module

        Parameters
        ----------
        module_name : str
            Name of module (included) up to which the model will be unfrozen.

        Returns
        -------
        unfrozen_modules : list of str
            List of names of frozen modules

        Raises
        ------
        ValueError when requested module does not exist

        Note
        ----
        The order of modules is the one reported by self.summary("full").
        If your model does not follow a sequential structure, you might
        want to use freeze_by_name for more control.
        Tr   r   r   r   r   r   unfreeze_up_to  r   zModel.unfreeze_up_toTmoduleslist[str] | strr   c           	      C  s   t  }t|tr|g}|D ]}t| |}|jddD ]}||_q|| || qt t|t| }|r?t	d| d|S )z7Helper function for freeze_by_name and unfreeze_by_nameTr   z&Could not find the following modules: rn   )
r~   rG   rv   getattrr   r   r   r   rJ   rI   )	r2   r   r   r   r   rj   rk   r   missingr   r   r   	__by_name  s   


zModel.__by_namestr | list[str]c                 C     | j ||ddS )a#  Freeze modules

        Parameters
        ----------
        modules : list of str, str
            Name(s) of modules to freeze
        recurse : bool, optional
            If True (default), freezes parameters of these modules and all submodules.
            Otherwise, only freezes parameters that are direct members of these modules.

        Returns
        -------
        frozen_modules: list of str
            Names of frozen modules

        Raises
        ------
        ValueError if at least one of `modules` does not exist.
        Fr   r   _Model__by_namer2   r   r   r   r   r   freeze_by_name  s
   zModel.freeze_by_namec                 C  r   )a/  Unfreeze modules

        Parameters
        ----------
        modules : list of str, str
            Name(s) of modules to unfreeze
        recurse : bool, optional
            If True (default), unfreezes parameters of these modules and all submodules.
            Otherwise, only unfreezes parameters that are direct members of these modules.

        Returns
        -------
        unfrozen_modules: list of str
            Names of unfrozen modules

        Raises
        ------
        ValueError if at least one of `modules` does not exist.
        Tr   r   r   r   r   r   unfreeze_by_name  s   zModel.unfreeze_by_namePath | str | io.BytesIOrm   	subfolder
str | Nonerevisionr   str | bool | None	cache_dirPath | str | NoneOptional['Model']c              
   K  s  t |tjstj|r|durtd|}	d}
nNtj|r?|dur'td|r4t|| t	j
j }	nt|t	j
j }	d}
n(t|}d|v rKtdt|t	j
||||d}	|	du r\dS | dre|nd}
|du rqd	d
 }|}t|	|dd}|d d }td|d id |d d d }t|}|d d d }t||}zt |	tjr|	d |j|	f||dd|}W n; ty } z/dt|v rt |	tjr|	d d}t| |j|	f|ddd|}|W  Y d}~S |d}~ww |
|_t| |S )u  Load pretrained model

        Parameters
        ----------
        checkpoint : Path, str, or byte buffer
            Model checkpoint, provided as one of the following:
            * path to a local `pytorch_model.bin` model checkpoint
            * path to a local directory containing such a file
            * identifier of a model on Huggingface hub
            * pre-loaded model checkpoint as a byte buffer
        map_location: optional
            Same role as in torch.load().
            Defaults to `lambda storage, loc: storage`.
        strict : bool, optional
            Whether to strictly enforce that the keys in checkpoint match
            the keys returned by this module’s state dict. Defaults to True.
        subfolder : str, optional
            Folder inside the hf.co model repo.
        revision : str, optional
            Revision when loading from the huggingface.co model hub.
        token : str or bool, optional
            Token to be used for the download.
        cache_dir: Path or str, optional
            Path to the folder where cached files are stored.
        kwargs: optional
            Any extra keyword args needed to init the model.
            Can also be used to override saved hyperparameter values.

        Returns
        -------
        model : Model
            Model

        See also
        --------
        `huggingface_hub.hf_hub_download`

        Nz0Revisions cannot be used with local checkpoints.local@z:Revisions must be passed with `revision` keyword argument.)r   r   r   r   )z	pyannote/zpyannoteai/huggingfacec                 S  s   | S r6   r   )storagelocr   r   r   default_map_locationT  s   z3Model.from_pretrained.<locals>.default_map_locationF)map_locationweights_onlyr   r   r$   r   rk   r   r   )r   rm   r   	loss_funczModel has been trained with a task-dependent loss function. Set 'strict' to False to load the model without its loss function and prevent this warning from appearing. )rG   ioBytesIOospathisfilerI   isdirr   r   r$   valuerv   r   lower
startswithpl_loadr   r   r   seekload_from_checkpointru   rx   ry   _otel_originr   )clsr   r   rm   r   r   r   r   r   path_to_model_checkpointotel_originr   loaded_checkpointr   r   rk   
class_nameKlassr{   r>   r   r   r   r   from_pretrained  s   2




zModel.from_pretrained)r%   r&   N)r'   r   r(   r   r)   r*   )r5   r   )r)   r   )r5   r;   )r9   r;   r6   )r@   rO   r5   rP   )r5   rP   )r5   r   )r   r   )r   rP   r5   r   )r5   r   )r5   r   )F)r   rv   r   r   r5   r   )r   rv   r5   r   )TF)r   r   r   r   r   r   r5   r   )T)r   r   r   r   r5   r   )r   r   r   r   r5   r   )NTNNNN)r   r   rm   r   r   r   r   r   r   r   r   r   r5   r   )#r   r   r   __doc__r.   propertyr)   setterr:   r9   deleterrX   rY   r   rb   rc   rq   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   classmethodr   __classcell__r   r   r3   r   r$   E   sf    

8



!

"
!"r$   )4
__future__r   r   r   rx   dataclassesr   	functoolsr   	importlibr   pathlibr   typingr   r   	lightningrT   torch.nnr   torch.optim#lightning.fabric.utilities.cloud_ior	   r   7lightning.pytorch.utilities.model_summary.model_summaryr
   pyannote.audior   pyannote.audio.core.ior   pyannote.audio.core.taskr   r   r   r   pyannote.audio.telemetryr   !pyannote.audio.utils.dependenciesr   pyannote.audio.utils.hf_hubr   r   pyannote.audio.utils.multi_taskr   pyannote.corer   torch.utils.datar   r   r   LightningModuler$   r   r   r   r   <module>   s8   