U
    ©Ê¹j9  ã                   @   sæ   U d Z ddlZddlmZmZmZmZmZmZ ddlZddlm	Z	 ddl
Zddddd	gZee ed
< ee	 Zee	ef Zeegeee e	f f ZG dd„ dƒZG dd„ dƒZddœdd„Zeee dœdd„Zee dœdd	„ZdS )zManipulation of micro-batches.é    N)ÚAnyÚCallableÚListÚUnionÚcastÚSequence)ÚTensorÚNoChunkÚBatchÚcheckÚscatterÚgatherÚ__all__c                   @   s*   e Zd ZdZedœdd„Zedd„ ƒZdS )r	   a  
    Wrapper for a Tensor in :meth:`Pipe.forward` indicating that the tensor
    should not be chunked on the batch dimension and instead be replicated
    as-is across all micro-batches. This is useful for tensors which might
    not have any 'batch' semantics for the model.
    )Úinpc                 C   s"   t  |¡std|› �ƒ‚|| _d S )Nz+NoChunk only supported for tensors, found: )ÚtorchÚ	is_tensorÚ	TypeErrorÚ_tensor)Úselfr   © r   úi/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/distributed/pipeline/sync/microbatch.pyÚ__init__   s    
zNoChunk.__init__c                 C   s   | j S ©N)r   ©r   r   r   r   Útensor#   s    zNoChunk.tensorN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   Úpropertyr   r   r   r   r   r	      s   c                   @   s  e Zd ZdZeee ef ddœdd„Ze	edœdd„ƒZ
e	d	d
„ ƒZdd„ Zdd„ Zed dœdd„Zedœdd„Zdd„ Zedœdd„Zedœdd„Zejeeddœdd„ƒZejeeddœdd„ƒZeeef ddœd d„Zeddœd!d"„Zeddœd#d$„ZdS )%r
   zC
    An abstraction representing a microbatch in the pipeline.
    N)ÚvaluesÚreturnc                 C   s@   || _ t |¡| _| js<tdd„ | j D ƒƒs<td| j › �ƒ‚d S )Nc                 s   s   | ]}t  |¡V  qd S r   ©r   r   )Ú.0Úvaluer   r   r   Ú	<genexpr>3   s     z!Batch.__init__.<locals>.<genexpr>zNo tensors found in batch: )Ú_valuesr   r   ÚatomicÚanyr   )r   r    r   r   r   r   -   s
    zBatch.__init__©r!   c                 C   s   | j stdƒ‚tt| jƒS )z Retrieves the underlying tensor.znot atomic batch)r'   ÚAttributeErrorr   r   r&   r   r   r   r   r   6   s    zBatch.tensorc                 C   s   | j S )z-Retrieves the underlying values for the batch)r&   r   r   r   r   r    =   s    zBatch.valuesc                 C   s<   | j r
dS t| jƒD ]\}}t |¡r|  S qtdƒ‚dS )z<
        Retrieves the index of first tensor found.
        r   zNo tensor found!N)r'   Ú	enumerater&   r   r   r   )r   Úir$   r   r   r   Úfind_tensor_idxB   s    

zBatch.find_tensor_idxc                 C   s2   | j r| jjS | jD ]}t |¡r|j  S qdS )z;
        Retrieves the device for this microbatch.
        N)r'   r&   Údevicer   r   )r   r$   r   r   r   Ú
get_deviceN   s
    

zBatch.get_device)Úfunctionr!   c                 C   s&   | j rt|| jƒƒS t|| jŽ ƒS dS )zbCalls a function on the microbatch. It also wraps
        the output with :class:`Batch`.
        N)r'   r
   r&   )r   r0   r   r   r   ÚcallY   s    z
Batch.callc                 C   s   d| j ›d| j›d�S )NzBatch[atomic=z](ú)©r'   r&   r   r   r   r   Ú__repr__b   s    zBatch.__repr__c                 c   s    | j r| jV  n| jE d H  d S r   r3   r   r   r   r   Ú__iter__e   s    
zBatch.__iter__c                 C   s   | j r
dS t| jƒS )Né   )r'   Úlenr&   r   r   r   r   Ú__len__k   s    zBatch.__len__)Úindexc                 C   s&   | j s| j| S |dkr tdƒ‚| jS )Nr   ú atomic batch allows index 0 only©r'   r&   Ú
IndexError)r   r9   r   r   r   Ú__getitem__n   s
    
zBatch.__getitem__)r9   r$   r!   c                 C   s   d S r   r   ©r   r9   r$   r   r   r   Ú__setitem__x   s    zBatch.__setitem__c                 C   s   d S r   r   r>   r   r   r   r?   |   s    )r9   r!   c                 C   s(   t |tƒr|  ||¡ n|  ||¡ d S r   )Ú
isinstanceÚintÚ_setitem_by_indexÚ_setitem_by_slicer>   r   r   r   r?   €   s    
c                 C   sP   | j s6|}| jd |… |f | j|d d …  | _d S |dkrFtdƒ‚|| _d S )Nr6   r   r:   r;   )r   r9   r$   r,   r   r   r   rB   †   s    (zBatch._setitem_by_indexc                 C   s`   |j |j  kr$|j  kr$d ks.n tdƒ‚| js>|| _d S t|ƒdkrRtdƒ‚|d | _d S )Nzonly slice [:] supportedr6   z5atomic batch cannot be replaced with multiple tensorsr   )ÚstartÚstopÚstepÚNotImplementedErrorr'   r&   r7   r<   r>   r   r   r   rC   ‘   s    &zBatch._setitem_by_slice)r   r   r   r   r   r   r   r   r   r   r   r    r-   r/   ÚFunctionr1   Ústrr4   r5   rA   r8   r=   ÚtypingÚoverloadr?   ÚsliceÚTensorsrB   rC   r   r   r   r   r
   (   s(   	
	
r)   c                    sB   t dd„ |D ƒƒs td|› �ƒ‚t ‡ fdd„|D ƒƒr>tdƒ‚dS )zÎ
    Checks whether the input contains at least one tensor and each tensor is
    on the same device as the first partition.

    Raises:
        ValueError: input does not contain at least one tensor

    c                 s   s   | ]}t  |¡V  qd S r   r"   ©r#   Úinputr   r   r   r%   ©   s     zcheck.<locals>.<genexpr>z inputs do not have any tensors: c                 3   s"   | ]}t  |¡o|jˆ kV  qd S r   )r   r   r.   rN   ©Úfirst_devicer   r   r%   «   s     z>All inputs should be on the same device as the first partitionN)r(   r   Ú
ValueError)rQ   Úinputsr   rP   r   r   Ÿ   s    
)Úchunksr!   c                 G   s  t |ƒdkr2t|d tƒr2dd„ |d  | ¡D ƒS dd„ t| ƒD ƒ}d}|D ]¦}t |¡rº| | ¡}|dkr�|t |ƒkr�td|› dt |ƒ› �ƒ‚t |ƒ}t|ƒD ]\}}||  	|¡ q qLt| ƒD ].}t|t
ƒrâ||  	|j¡ qÂ||  	|¡ qÂqL|d	|… }d
d„ |D ƒS )z7Splits an input mini-batch into multiple micro-batches.r6   r   c                 S   s   g | ]}t |ƒ‘qS r   ©r
   ©r#   Úxr   r   r   Ú
<listcomp>²   s     zscatter.<locals>.<listcomp>c                 S   s   g | ]}g ‘qS r   r   )r#   Ú_r   r   r   rX   ´   s     éÿÿÿÿz6Found different number of chunks produced for inputs: ú and Nc                 S   s   g | ]}t |ƒ‘qS r   rU   rV   r   r   r   rX   Ï   s     )r7   r@   r   ÚchunkÚranger   r   ÚRuntimeErrorr+   Úappendr	   r   )rT   rS   ZbatchesZ
num_chunksrO   Útensorsr,   r   r   r   r   r   ¯   s$    


)Úoutputsc              	   C   sÔ   | d j r(tdd„ | D ƒƒ}t |¡}n¨g }tt| d ƒƒD ]Š}t| d | ƒ}g }| D ]>}|t|| ƒkrˆtd|› dt|| ƒ› �ƒ‚| || ¡ qXt 	| d | ¡r¼| t |¡¡ q<| |¡ q<t|ƒ}|S )z4Concatenates output micro-batches into a mini-batch.r   c                 s   s   | ]}|j V  qd S r   )r   )r#   Úbr   r   r   r%   ×   s     zgather.<locals>.<genexpr>z2Types for microbatch outputs do not match, found: r[   )
r'   Útupler   Úcatr]   r7   Útyper   r_   r   )ra   r`   ÚoutputZ
output_bufr,   Úoutput_typeZcurrent_outputsÚbatchr   r   r   r   Ò   s     
)r   rJ   r   r   r   r   r   r   r   r   Ztorch.cuda.commr   rI   Ú__annotations__rM   ZTensorOrTensorsrH   r	   r
   r   rA   r   r   r   r   r   r   Ú<module>   s    w#