U
    <c                     @   sr   d dl mZ d dlZddlmZ dd Zdd Zd	d
 Zdd Zdd Z	dd fddZ
ejeejdddZdS )    )OptionalN   )ExpandedWeightc                 C   sL   |t |t |  d }|dt |t |   }dd t| |D }||fS )zMost `__torch_function__`s standardize the kwargs that they give, so this will separate
    the args and kwargs they pass. Functions that don't are linear and convND
    Nc                 S   s   i | ]\}}||qS  r   ).0namevaluer   r   [/tmp/pip-unpacked-wheel-gikjz4vx/torch/nn/utils/_expanded_weights/expanded_weights_utils.py
<dictcomp>   s      z#standard_kwargs.<locals>.<dictcomp>)lenzip)Zkwarg_namesexpanded_argsZkwarg_valuesZexpanded_args_without_kwargsexpanded_kwargsr   r   r	   standard_kwargs   s    r   c                 C   s   t | ||\}}| ||S )a  Forward helper computes the forward pass for a function that has expanded weight(s)
    passed to it. It will run the forward pass where all ExpandedWeights are their original
    weight. It runs checks on the given arguments and detaches the outputs.

    .. note:: First argument in :attr:`expanded_args` must be the input with the batch
    dimension as the first element of the shape

    .. note:: :attr:`func` must return a Tensor or tuple of Tensors

    Args:
        func: The function to be called
        ctx: The context from the autograd.Function object. Will be used to save
          computed state from the forward pass
        expanded_args: Arguments to be passed to :attr:`func`. Will include arguments
          that need to be unpacked because they are ExpandedWeights
        num_true_outs: The number of outputs seen by the user since some functions
          return auxillary data that is only used in the backward pass
    )_check_and_unexpand_args)funcr   r   unexpanded_argsunexpanded_kwargsr   r   r	   forward_helper   s    r   c           	      C   sd  |d }t |tr.tdt|j d| j t |tjsVtdt|j d| j t|jdkrttd| j |jd dkrtd| d| j |jd }|t	|
  D ].}t |tr|j|krtd| d|j qd }|t	|
  D ]@}t |tr|d kr|j}q||jkrtd	| d
|j qt	dd |D }dd | D }||fS )Nr   zbExpanded Weights do not support inputs that are also ExpandedWeights. Input must be a Tensor, got z in function zVExpanded Weights requires a Tensor as the first input to get the batch dimension, got zSExpanded Weights requires a batch dimension but got an input of size 0 in function zI0 is not a valid batch size for Expanded Weights but got input tensor of zWExpected ExpandedWeights to have batch size matching input but got input batch size of z# with ExpandedWeight of batch size zVExpected ExpandedWeights to all have the same loss_reduction argument but got onewith z and one with c                 s   s"   | ]}t |tr|jn|V  qd S N
isinstancer   orig_weight)r   argr   r   r	   	<genexpr>B   s     z+_check_and_unexpand_args.<locals>.<genexpr>c                 S   s&   i | ]\}}|t |tr|jn|qS r   r   )r   r   r   r   r   r	   r
   C   s    z,_check_and_unexpand_args.<locals>.<dictcomp>)r   r   RuntimeErrortype__name__torchTensorr   shapetuplevalues
batch_sizeloss_reductionitems)	r   r   r   inputr#   r   r$   r   r   r   r   r	   r   %   s2    




r   c                 C   s   |j dkr| |j S | S d S )NZmean)r$   r#   )grad_sampleZexpanded_weightr   r   r	   maybe_scale_by_batch_sizeG   s    

r(   c                 C   sL   t | }t| trHt||| }t|drB|jd k	rB|j| |_n||_d S )Nr'   ) unpack_expanded_weight_or_tensorr   r   r(   hasattrr'   )maybe_expanded_weightZper_sample_grad_fnunpackedZgrad_sample_contributionr   r   r	   set_grad_sample_if_existsM   s    
r-   c                 C   s   | S r   r   )xr   r   r	   <lambda>V       r/   c                 C   sJ   t | tr| j}||S t | tjr2| js2|| S t | tjrFtdd S )NzExpandedWeights currently does not support a mixture of ExpandedWeight parameters and normal Parameters. Please file and issue with pytorch/pytorch)r   r   r   r   r   Zrequires_gradr   )r+   r   r   r   r   r	   r)   V   s    
r)   )tensorn_dimsreturnc                 C   s:   |   |d kr| S ttd|   | }| j|dS dS )aF  
    Calculates the sum over all dimensions, except the first
    (batch dimension), and excluding the last n_dims.
    This function will ignore the first dimension and it will
    not aggregate over the last n_dims dimensions.
    Args:
        tensor: An input tensor of shape ``(B, ..., X[n_dims-1])``.
        n_dims: Number of dimensions to keep.
    Example:
        >>> tensor = torch.ones(1, 2, 3, 4, 5)
        >>> sum_over_all_but_batch_and_last_n(tensor, n_dims=2).shape
        torch.Size([1, 4, 5])
    Returns:
        A tensor of shape ``(B, ..., X[n_dims-1])``
    r   )dimN)r4   listrangesum)r1   r2   Zdimsr   r   r	   !sum_over_all_but_batch_and_last_nb   s    r8   )typingr   r   Zexpanded_weights_implr   r   r   r   r(   r-   r)   r   intr8   r   r   r   r	   <module>   s   	"	 