o
    oiYZ                     @   s  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	m
Z
mZmZmZmZmZmZmZ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 d dl m!Z! d dl"m#Z# G dd deZ$de%de&fddZ'de%dee( fddZ)de%dee fddZ*dedeeef defddZ+dedeeef deee	 ee,e	f f fddZ-dedeeef dee,e	f fddZ.de%de(ddfdd Z/dd!d"e	d#e	d$ee d%e	de	f
d&d'Z0dEd(e
d)ee, de
fd*d+Z1d,e
d-e$de
fd.d/Z2edEd0ed)ee, ded1 fd2d3Z3d4e,d5e	d#ee	d6f d%ee,e	f d7ee,e	f d8ee,d6f dee&ee	d6f ee,e	f f fd9d:Z4de%d;e(ddfd<d=Z5d>e(de(fd?d@Z6de(fdAdBZ7G dCdD dDeZ8dS )F    N)OrderedDict)contextmanager)partial)
AnyCallableDict	GeneratorIterableOptionalSizedTupleTypeUnion)get_all_subclasses)BatchSampler
DataLoaderIterableDatasetSampler)	TypeGuard)LightningEnum)MisconfigurationException)rank_zero_warn)pl_worker_init_functionc                   @   s&   e Zd ZdZdZdeddfddZdS )_WrapAttrTagsetdelargsreturnNc                 G   s   | | j krtnt}|| S N)SETsetattrdelattr)selfr   fn r$   S/home/ubuntu/.local/lib/python3.10/site-packages/lightning/fabric/utilities/data.py__call__%   s   z_WrapAttrTag.__call__)__name__
__module____qualname__r   DELr   r&   r$   r$   r$   r%   r   !   s    r   
dataloaderr   c                 C   s   t | do
t| jtS )Ndataset)hasattr
isinstancer,   r   )r+   r$   r$   r%   has_iterable_dataset+   s   r/   c              	   C   s,   zt | }W |S  ttfy   d}Y |S w )z>Try to get the length of an object, return ``None`` otherwise.N)len	TypeErrorNotImplementedErrorr+   lengthr$   r$   r%   	sized_len/   s   
r5   c                 C   sD   t | }|dkrtd| jj d |durt| rtd |duS )z<Checks if a given object has ``__len__`` method implemented.r   `z>` returned 0 length. Please make sure this was your intention.NzYour `IterableDataset` has `__len__` defined. In combination with multi-process data loading (when num_workers > 1), `__len__` could be inaccurate if each worker is not configured independently to avoid having duplicate data.)r5   r   	__class__r'   r/   r3   r$   r$   r%   has_len9   s   r8   samplerc                 C   s$   t | |\}}t| g|R i |S r   )$_get_dataloader_init_args_and_kwargs_reinstantiate_wrapped_cls)r+   r9   dl_args	dl_kwargsr$   r$   r%   _update_dataloaderJ   s   r>   c              
      s  t | tstd|  dt| d}|r!| j}| j| j | j}ndd t| 	 D d }| j
d< d tt| jj}tdd	 | D }|ro|r_|d
d ttjj	 D  n|ttjj |dd  |sfdd|	 D d fdd	 D d}d|}t |trd d< d d< nt| |  fdd| D }|rt|}	| jj}
ddd	 |	D }td|
 d|	 d|
 d| d	|stt B |  }|rt|}| jj}
td|
 d| d|
 d|fS )NzThe dataloader z0 needs to subclass `torch.utils.data.DataLoader`__pl_saved_argsc                 S   s    i | ]\}}| d s||qS )_)
startswith.0kvr$   r$   r%   
<dictcomp>^   s     z8_get_dataloader_init_args_and_kwargs.<locals>.<dictcomp>multiprocessing_contextr$   c                 s   s    | ]	}|j |ju V  qd S r   )kindVAR_KEYWORDrC   pr$   r$   r%   	<genexpr>h       z7_get_dataloader_init_args_and_kwargs.<locals>.<genexpr>c                 S   s"   i | ]\}}|j |jur||qS r$   )defaultemptyrB   r$   r$   r%   rF   o   s    r"   c                    s*   h | ]\}}| v r|j  | ur|qS r$   )rN   )rC   namerK   )attrsr$   r%   	<setcomp>x   s   * z7_get_dataloader_init_args_and_kwargs.<locals>.<setcomp>r,   c                    s   i | ]\}}| v r||qS r$   r$   rB   )non_defaultsr$   r%   rF   }   s    batch_samplerr9   c                    sD   h | ]}|j |j|jfv r |j|ju r |jvr |j vr|jqS r$   )rH   POSITIONAL_ONLYPOSITIONAL_OR_KEYWORDrN   rO   rP   rJ   )	arg_namesr=   r$   r%   rR      s    

z, c                 s   s    | ]	}d | dV  qdS )z`self.r6   Nr$   )rC   arg_namer$   r$   r%   rL      rM   z,Trying to inject custom `Sampler` into the `z` instance. This would fail as some of the `__init__` arguments are not available as instance attributes. The missing attributes are z. If you instantiate your `zZ` inside a `*_dataloader` hook of your module, we will do this for you. Otherwise, define z inside your `__init__`.z&Trying to inject parameters into the `z{` instance. This would fail as it doesn't expose all its attributes in the `__init__` signature. The missing arguments are z. HINT: If you wrote the `zA` class, add the `__init__` arguments or allow passing `**kwargs`) r.   r   
ValueErrorr-   r?   __pl_saved_kwargs__pl_saved_arg_names	__datasetvarsitemsrG   dictinspect	signature__init__
parametersanyvaluesupdatepopaddgetr   '_dataloader_init_kwargs_resolve_samplersortedr7   r'   joinr   r   keysr1   )r+   r9   was_wrappedr<   original_datasetparamshas_variadic_kwargsr,   required_argssorted_required_argsdataloader_cls_namemissing_args_messagemissing_kwargssorted_missing_kwargsr$   )rW   rQ   r=   rS   r%   r:   O   sx   







	r:   c              
   C   s  t | d}|durt|turt|}t|drG|j}|j}|j}|j}td|||||\}}}|s;t	d|j
 dt|g|R i |}n:t|dr}t|dr}z|||j|jd	}W n$ t	y| }	 zd
dl}
|
dt|	}|ss t	d|	d}	~	ww t	ddd|dddS |dddS )zThis function is used to handle the sampler, batch_sampler arguments associated within a DataLoader for its re-
    instantiation.rT   Nr?   r9   zYTrying to inject a modified sampler into the batch sampler; however, it seems the class `z` does not have an argument called `sampler.` To mitigate this, expose an argument `sampler` in the `__init__` method of your custom class.
batch_size	drop_last)rx   ry   r   z:.*__init__\(\) (got multiple values)|(missing \d required)ak   Lightning can't inject a (distributed) sampler into your batch sampler, because it doesn't subclass PyTorch's `BatchSampler`. To mitigate this, either follow the API of `BatchSampler` or set`.setup_dataloaders(..., use_distributed_sampler=False)`. If you choose the latter, you will be responsible for handling the distributed sampling within your batch sampler.F   )r9   shufflerT   rx   ry   )r9   r{   rT   )getattrtyper   r-   r?   rZ   __pl_saved_default_kwargsr[   _replace_value_in_saved_argsr1   r)   r;   rx   ry   rematchstr)r+   r9   rT   batch_sampler_clsr   kwargsdefault_kwargsrW   successexr   r   r$   r$   r%   rj      s^   



rj   rankc                 C   sD   t | dsd S ttjddr| jd u r tt|d| _d S d S d S )Nworker_init_fnPL_SEED_WORKERSr   )r   )r-   intosenvironri   r   r   r   )r+   r   r$   r$   r%   _auto_add_worker_init_fn   s
   
r   )explicit_clsorig_objectr   r   r   c                O   s   |d u rt | n|}z	||i |}W n6 tyI } z*dd l}|dt|}|s* | d }	d|j d|	 d|	 d|	 d	}
t|
|d }~ww t| dg }|D ]\}}||g|R   qR|S )	Nr   z-.*__init__\(\) got multiple values .* '(\w+)'zThe zd implementation has an error where more than one `__init__` argument can be passed to its parent's `zr=...` `__init__` argument. This is likely caused by allowing passing both a custom argument that will map to the `zc` argument as well as `**kwargs`. `kwargs` should be filtered to make sure they don't contain the `zR` key. This argument was automatically passed to your object by PyTorch Lightning.__pl_attrs_record)	r}   r1   r   r   r   groupsr'   r   r|   )r   r   r   r   constructorresultr   r   r   argumentmessageattrs_recordr#   r$   r$   r%   r;      s0   

r;   initstore_explicit_argc              	      s.   t  dtdtdtddf fdd}|S )zWraps the ``__init__`` method of classes (currently :class:`~torch.utils.data.DataLoader` and
    :class:`~torch.utils.data.BatchSampler`) in order to enable re-instantiation of custom subclasses.objr   r   r   Nc                    s"  t | dd}t| dd tj}tdd | D }t|d t	|  fdd|
 D }t| dsUt| d| t| d	  t| d
 t| d| d ur}v rmt| d |  n v r}t| d    | g|R i   t| d| d S )N__pl_inside_initFTc                 s   s8    | ]}|j d kr|j|j|jfvr|j |jfV  qdS )r"   N)rP   rH   VAR_POSITIONALrI   rN   )rC   paramr$   r$   r%   rL   '  s    
z5_wrap_init_method.<locals>.wrapper.<locals>.<genexpr>c                    s2   i | ]\}}| vr|vr|t jjkr||qS r$   )r`   	ParameterrO   )rC   rP   valuer   param_namesr$   r%   rF   /  s
    z6_wrap_init_method.<locals>.wrapper.<locals>.<dictcomp>r?   rZ   r[   r~   __)r|   object__setattr__r`   ra   rc   r   re   tupler0   r^   r-   index)r   r   r   old_inside_initrp   parameters_defaultsr   r   r   r   r%   wrapper  s,   
 z"_wrap_init_method.<locals>.wrapper	functoolswrapsr   )r   r   r   r$   r   r%   _wrap_init_method  s   "'r   methodtagc                    s*   t  dtdtddf fdd}|S )zWraps the ``__setattr__`` or ``__delattr__`` method of classes (currently :class:`~torch.utils.data.DataLoader`
    and :class:`~torch.utils.data.BatchSampler`) in order to enable re- instantiation of custom subclasses.r   r   r   Nc                    s   |^}}t | dd\}}||ko|k }t| d|f  | g|R   |rBt | ddsBt | dg }||f t| d| t| d||f d S )N__pl_current_call)Nr   r   Tr   )r|   r   r   append)r   r   rP   r@   prev_call_nameprev_call_method
first_callr   r   r   r$   r%   r   N  s   z"_wrap_attr_method.<locals>.wrapperr   )r   r   r   r$   r   r%   _wrap_attr_methodJ  s   r   base_cls)NNNc              	   c   s    t | | hB }|D ]D}d|jv r|j|_t|j||_dtjfdtjffD ]'\}}||jv s3|| u rMd| }t||t	|| t||t
t	||| q&q
dV  |D ]#}dD ]}d| |jv rvt||t	|d|  t|d|  qXqTdS )zThis context manager is used to add support for re-instantiation of custom (subclasses) of `base_cls`.

    It patches the ``__init__``, ``__setattr__`` and ``__delattr__`` methods.

    rb   r   __delattr____oldN)r   r   rb   )r   __dict__rb   __old__init__r   r   r   r*   r    r|   r   r!   )r   r   classesclspatch_fn_namer   
saved_namepatched_namer$   r$   r%   _replace_dunder_methodse  s,   

r   replace_keyreplace_value.r   rW   c                 C   sj   | |v r| | }|d| |f ||d d  }d||fS | |v s'| |v r0||| < d||fS d||fS )zTries to replace an argument value in a saved list of args and kwargs.

    Returns a tuple indicating success of the operation and modified saved args and kwargs

    Nrz   TF)r   )r   r   r   r   r   rW   replace_indexr$   r$   r%   r     s   
"


r   epochc                 C   s   i }t | dd }dur||t|< t | dd }dur,t |dd }dur,||t|< | D ]}t |dd}t|r@|| q0dS )a  Calls the ``set_epoch`` method on either the sampler of the given dataloader.

    Every PyTorch dataloader has either a sampler or a batch sampler. If the sampler is wrapped by a
    :class:`~torch.utils.data.distributed.DistributedSampler`, ``set_epoch`` must be called at the beginning
    of every epoch to ensure shuffling applies a new ordering. This has no effect if shuffling is off.

    r9   NrT   	set_epoch)r|   idre   callable)r+   r   objectsr9   rT   r   r   r$   r$   r%   _set_sampler_epoch  s   	r   local_world_sizec                 C   s0   | dk rt d|  dt }td||  d S )a  Suggests an upper bound of ``num_workers`` to use in a PyTorch :class:`~torch.utils.data.DataLoader` based on
    the number of CPU cores available on the system and the number of distributed processes in the current machine.

    Args:
        local_world_size: The number of distributed processes running on the current machine. Set this to the number
            of devices configured in Fabric/Trainer.

    rz   z'`local_world_size` should be >= 1, got .)rY   _num_cpus_availablemax)r   	cpu_countr$   r$   r%   suggested_max_num_workers  s   	r   c                  C   s0   t tdrttdS t } | d u rdS | S )Nsched_getaffinityr   rz   )r-   r   r0   r   r   )r   r$   r$   r%   r     s   
r   c                   @   sX   e Zd ZdZdedefddZdededdfdd	Zd
eddfddZdefddZ	dS )AttributeDicta  A container to store state variables of your program.

    This is a drop-in replacement for a Python dictionary, with the additional functionality to access and modify keys
    through attribute lookup for convenience.

    Use this to define the state of your program, then pass it to
    :meth:`~lightning.fabric.fabric.Fabric.save` and :meth:`~lightning.fabric.fabric.Fabric.load`.

    Example:
        >>> import torch
        >>> model = torch.nn.Linear(2, 2)
        >>> state = AttributeDict(model=model, iter_num=0)
        >>> state.model
        Linear(in_features=2, out_features=2, bias=True)
        >>> state.iter_num += 1
        >>> state.iter_num
        1
        >>> state
        "iter_num": 1
        "model":    Linear(in_features=2, out_features=2, bias=True)

    keyr   c              
   C   sB   z| | W S  t y  } ztdt| j d| d|d }~ww )N'z' object has no attribute ')KeyErrorAttributeErrorr}   r'   )r"   r   er$   r$   r%   __getattr__  s   
zAttributeDict.__getattr__valNc                 C   s   || |< d S r   r$   )r"   r   r   r$   r$   r%   r     s   zAttributeDict.__setattr__itemc                 C   s   || vrt || |= d S r   )r   )r"   r   r$   r$   r%   r     s   
zAttributeDict.__delattr__c                    sX   t  sdS tdd  D }dt|d  d  fddt  D }d	|S )
N c                 s   s    | ]	}t t|V  qd S r   )r0   r   )rC   rD   r$   r$   r%   rL     rM   z)AttributeDict.__repr__.<locals>.<genexpr>z{:   zs} {}c                    s$   g | ]} d | d | qS )"z":)format)rC   nr"   tmp_namer$   r%   
<listcomp>  s   $ z*AttributeDict.__repr__.<locals>.<listcomp>
)r0   r   r   rk   rm   rl   )r"   max_key_lengthrowsr$   r   r%   __repr__  s   
zAttributeDict.__repr__)
r'   r(   r)   __doc__r   r   r   r   r   r   r$   r$   r$   r%   r     s    r   r   )9r   r`   r   collectionsr   
contextlibr   r   typingr   r   r   r   r	   r
   r   r   r   r   $lightning_utilities.core.inheritancer   torch.utils.datar   r   r   r   typing_extensionsr    lightning.fabric.utilities.enumsr   %lightning.fabric.utilities.exceptionsr   $lightning.fabric.utilities.rank_zeror   lightning.fabric.utilities.seedr   r   r   boolr/   r   r5   r8   r>   r   r:   rj   r   r;   r   r   r   r   r   r   r   r   r$   r$   r$   r%   <module>   st   0



]


I(/"




