o
    zi                     @   sf   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 G dd dZdS )	    N)DataParallel)DistributedDataParallel   )ResumableDistributedSampler)ResumableSequentialSamplerc                   @   s   e Zd ZdZddefddZdd Zdd	 Zd
ej	j
fddZdd ZdejfddZdejjfddZdd Z	ddejdefddZedd ZdS ) Acceleratoraf  This class is used to prepare models and dataloaders for
    usage with DDP or DP. Use the functions prepare_model, prepare_dataloader to
    prepare the respective objects. In the case of models, they are moved to
    the appropriate GPU and SyncBatchNorm is applied to them. In the case of
    dataloaders, a sampler is created and the dataloader is initialized with
    that sampler.

    If the world size is 1, prepare_model and prepare_dataloader are
    no-ops. If the environment variable ``LOCAL_RANK`` is not set, then the
    script was launched without ``torchrun``, and ``DataParallel``
    will be used instead of ``DistributedDataParallel`` (not recommended), if
    the world size (number of GPUs) is greater than 1.

    Parameters
    ----------
    amp : bool, optional
        Whether or not to enable automatic mixed precision, by default False
    Fampc                 C   s   t dd }tj | _| jdko|d u| _| jdko|d u | _| jdkr'dnd| _| jr;t	|}t
jdd| j|d |d u rAdn|| _|| _G d	d
 d
}|rVtjj n| | _tj ritj| j| _d S d | _d S )N
LOCAL_RANK   r   cpucudancclzenv://)init_method
world_sizerankc                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )z)Accelerator.__init__.<locals>.DummyScalerc                 S      d S N selfr   r   M/home/ubuntu/.local/lib/python3.10/site-packages/audiotools/ml/accelerator.py__init__6      z2Accelerator.__init__.<locals>.DummyScaler.__init__c                 S   s   |   d S r   )stepr   	optimizerr   r   r   r   9   s   z.Accelerator.__init__.<locals>.DummyScaler.stepc                 S      |S r   r   r   lossr   r   r   scale<   r   z/Accelerator.__init__.<locals>.DummyScaler.scalec                 S   r   r   r   r   r   r   r   unscale_?   r   z2Accelerator.__init__.<locals>.DummyScaler.unscale_c                 S   r   r   r   r   r   r   r   updateB   r   z0Accelerator.__init__.<locals>.DummyScaler.updateN)__name__
__module____qualname__r   r   r   r    r!   r   r   r   r   DummyScaler5   s    r%   )osgetenvtorchr   device_countr   use_ddpuse_dpdeviceintdistinit_process_group
local_rankr   
GradScalerscaleris_available
device_ctx)r   r   r0   r%   r   r   r   r   !   s*   zAccelerator.__init__c                 C   s   | j d ur
| j   | S r   )r4   	__enter__r   r   r   r   r5   J   s   

zAccelerator.__enter__c                 C   s"   | j d ur| j ||| d S d S r   )r4   __exit__)r   exc_type	exc_value	tracebackr   r   r   r6   O   s   
zAccelerator.__exit__modelc                 K   sV   | | j}| jrtjj|}t|fd| jgi|}|S | j	r)t
|fi |}|S )ab  Prepares model for DDP or DP. The model is moved to
        the device of the correct rank.

        Parameters
        ----------
        model : torch.nn.Module
            Model that is converted for DDP or DP.

        Returns
        -------
        torch.nn.Module
            Wrapped model, or original model if DDP and DP are turned off.
        
device_ids)tor,   r*   r(   nnSyncBatchNormconvert_sync_batchnormr   r0   r+   r   )r   r:   kwargsr   r   r   prepare_modelS   s   zAccelerator.prepare_modelc                 O   s   t jjj| jg|R i |S )z^Context manager for autocasting. Arguments
        go to ``torch.cuda.amp.autocast``.
        )r(   r   r   autocast)r   argsr@   r   r   r   rB   l   s   zAccelerator.autocastr   c                 C   s   | j |  dS )zBackwards pass, after scaling the loss if ``amp`` is
        enabled.

        Parameters
        ----------
        loss : torch.Tensor
            Loss value.
        N)r2   r   backwardr   r   r   r   rD   r   s   	zAccelerator.backwardr   c                 C   s   | j | dS )zSteps the optimizer, using a ``scaler`` if ``amp`` is
        enabled.

        Parameters
        ----------
        optimizer : torch.optim.Optimizer
            Optimizer to step forward.
        N)r2   r   r   r   r   r   r   }   s   	zAccelerator.stepc                 C   s   | j   dS )zUpdates the scale factor.N)r2   r!   r   r   r   r   r!      s   zAccelerator.updateNdataset	start_idxc                 K   s|   | j r*t||| j| jd}d|v rt|d | j d|d< t|d | j d|d< nt||}tjjj	|fd|i|}|S )a  Wraps a dataset with a DataLoader, using the correct sampler if DDP is
        enabled.

        Parameters
        ----------
        dataset : typing.Iterable
            Dataset to build Dataloader around.
        start_idx : int, optional
            Start index of sampler, useful if resuming from some epoch,
            by default None

        Returns
        -------
        _type_
            _description_
        )num_replicasr   num_workersr
   
batch_sizesampler)
r*   DistributedSamplerr   r0   maxSequentialSamplerr(   utilsdata
DataLoader)r   rE   rF   r@   rJ   
dataloaderr   r   r   prepare_dataloader   s   
zAccelerator.prepare_dataloaderc                 C   s   t | dr| jS | S )zUnwraps the model if it was wrapped in DDP or DP, otherwise
        just returns the model. Use this to unwrap the model returned by
        :py:func:`audiotools.ml.accelerator.Accelerator.prepare_model`.
        module)hasattrrS   )r:   r   r   r   unwrap   s   
zAccelerator.unwrap)Fr   )r"   r#   r$   __doc__boolr   r5   r6   r(   r=   ModulerA   rB   TensorrD   optim	Optimizerr   r!   typingIterabler-   rR   staticmethodrU   r   r   r   r   r      s$    )
$r   )r&   r\   r(   torch.distributeddistributedr.   torch.nn.parallelr   r   data.datasetsr   rK   r   rM   r   r   r   r   r   <module>   s    