U
    ¯Ê¹j¦)  ã                   @   s”   d Z ddlmZ ddlZddlmZ ddlm  mZ ddlm	Z	 ddl
mZ ddlmZ ee d	œd
d„ZG dd„ dejƒZG dd„ dejƒZdS )a]   Halo Self Attention

Paper: `Scaling Local Self-Attention for Parameter Efficient Visual Backbones`
    - https://arxiv.org/abs/2103.12731

@misc{2103.12731,
Author = {Ashish Vaswani and Prajit Ramachandran and Aravind Srinivas and Niki Parmar and Blake Hechtman and
    Jonathon Shlens},
Title = {Scaling Local Self-Attention for Parameter Efficient Visual Backbones},
Year = {2021},
}

Status:
This impl is a WIP, there is no official ref impl and some details in paper weren't clear to me.
The attention mechanism works but it's slow as implemented.

Hacked together by / Copyright 2021 Ross Wightman
é    )ÚListN)Únné   )Úmake_divisible)Útrunc_normal_)Ú_assert©Úpermute_maskc                 C   sÆ   | j \}}}}|j d }|d d }| | dd¡ }	|	 d||¡}	t |	ddg¡ d¡}
t |
d|| g¡}
|
 d|d |¡}
|
dd…d|…|d d…f }	|	 ||d||¡ dd|dd¡}	|	 |¡S )a~   Compute relative logits along one dimension

    As per: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
    Originally from: `Attention Augmented Convolutional Networks` - https://arxiv.org/abs/1904.09925

    Args:
        q: (batch, height, width, dim)
        rel_k: (2 * window - 1, dim)
        permute_mask: permute output dim according to this
    r   r   é   éÿÿÿÿéþÿÿÿN)ÚshapeÚ	transposeÚreshapeÚFÚpadÚflattenÚexpandÚpermute)ÚqZrel_kr	   ÚBÚHÚWÚdimZrel_sizeÚwin_sizeÚxZx_pad© r   úT/var/www/html/bwave/python/venv/lib/python3.8/site-packages/timm/layers/halo_attn.pyÚrel_logits_1d   s    
 r   c                       s(   e Zd ZdZ‡ fdd„Zdd„ Z‡  ZS )ÚPosEmbedRelzÜ Relative Position Embedding
    As per: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
    Originally from: `Attention Augmented Convolutional Networks` - https://arxiv.org/abs/1904.09925

    c                    sZ   t ƒ  ¡  || _|| _t t |d d |¡| ¡| _t t |d d |¡| ¡| _	dS )zØ
        Args:
            block_size (int): block size
            win_size (int): neighbourhood window size
            dim_head (int): attention head dim
            scale (float): scale factor (for init)
        r
   r   N)
ÚsuperÚ__init__Ú
block_sizeÚdim_headr   Ú	ParameterÚtorchZrandnÚ
height_relÚ	width_rel)Úselfr"   r   r#   Úscale©Ú	__class__r   r   r!   C   s
    
 zPosEmbedRel.__init__c           	      C   sl   |j \}}}}| d| j| j| j¡}t|| jdd�}| dd¡}t|| jdd�}|| }| |||d¡}|S )Nr   )r   r   é   r
   é   r   r   r
   )r   r,   r   r-   r
   )r   r   r"   r#   r   r'   r   r&   )	r(   r   r   ÚBBZHWÚ_Zrel_logits_wZrel_logits_hZ
rel_logitsr   r   r   ÚforwardQ   s    zPosEmbedRel.forward)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r!   r0   Ú__classcell__r   r   r*   r   r   =   s   r   c                       s2   e Zd ZdZd‡ fdd	„	Zd
d„ Zdd„ Z‡  ZS )ÚHaloAttnaÀ   Halo Attention

    Paper: `Scaling Local Self-Attention for Parameter Efficient Visual Backbones`
        - https://arxiv.org/abs/2103.12731

    The internal dimensions of the attention module are controlled by the interaction of several arguments.
      * the output dimension of the module is specified by dim_out, which falls back to input dim if not set
      * the value (v) dimension is set to dim_out // num_heads, the v projection determines the output dim
      * the query and key (qk) dimensions are determined by
        * num_heads * dim_head if dim_head is not None
        * num_heads * (dim_out * attn_ratio // num_heads) if dim_head is None
      * as seen above, attn_ratio determines the ratio of q and k relative to the output if dim_head not used

    Args:
        dim (int): input dimension to the module
        dim_out (int): output dimension of the module, same as dim if not set
        feat_size (Tuple[int, int]): size of input feature_map (not used, for arg compat with bottle/lambda)
        stride: output stride of the module, query downscaled if > 1 (default: 1).
        num_heads: parallel attention heads (default: 8).
        dim_head: dimension of query and key heads, calculated from dim_out * attn_ratio // num_heads if not set
        block_size (int): size of blocks. (default: 8)
        halo_size (int): size of halo overlap. (default: 3)
        qk_ratio (float): ratio of q and k dimensions to output dimension when dim_head not set. (default: 1.0)
        qkv_bias (bool) : add bias to q, k, and v projections
        avg_down (bool): use average pool downsample instead of strided query blocks
        scale_pos_embed (bool): scale the position embedding as well as Q @ K
    Nr   é   r,   ç      ð?Fc                    sZ  t ƒ  ¡  |p|}|| dks"t‚|dks.t‚|| _|pJt||	 dd�| | _|| j | _|| j | _|| j | _| jd | _	|| _
| | _| _|| _||d  | _d| _d}|dkrâ|pÄ|| dk}|rÎdn|| _| j| j | _tj|| jd| j|
d	�| _tj|| j| j d|
d
�| _t| j| j| j| j	d�| _|�rDt dd¡nt ¡ | _|  ¡  d S )Nr   )r   r
   r7   )Zdivisorç      à¿r
   r   F)ÚstrideÚbias)r;   )r"   r   r#   r)   )r    r!   ÚAssertionErrorÚ	num_headsr   Údim_head_qkÚ
dim_head_vZ
dim_out_qkÚ	dim_out_vr)   Úscale_pos_embedr"   Úblock_size_dsÚ	halo_sizer   Úblock_strider   ZConv2dr   Úkvr   Ú	pos_embedZ	AvgPool2dZIdentityÚpoolÚreset_parameters)r(   r   Zdim_outZ	feat_sizer:   r=   r#   r"   rC   Zqk_ratioZqkv_biasZavg_downrA   Zuse_avg_poolr*   r   r   r!   }   s<    
   ÿzHaloAttn.__init__c                 C   sZ   | j jjd d }t| j j|d� t| jj|d� t| jj| jd� t| jj| jd� d S )Nr   r9   )Ústd)	r   Úweightr   r   rE   rF   r&   r)   r'   )r(   rI   r   r   r   rH   ¢   s
    zHaloAttn.reset_parametersc                 C   sè  |j \}}}}t|| j dkdƒ t|| j dkdƒ || j }|| j }|| }|  |¡}	|	 d| j|| j|| j¡ dddddd¡}	|	 || j | jd|¡ 	dd¡}	|  
|¡}
t |
| j| j| j| jg¡}
|
 d| j| j¡ d| j| j¡ || j | j| j |d¡ dddd¡}
tj|
| j| jgdd	�\}}| j�rX|	| 	dd
¡ |  |	¡ | j }n |	| 	dd
¡ | j |  |	¡ }|jdd	�}||  	dd¡}| d| j| j||¡}| ddddd¡ ¡  || j|| j || j ¡}|  |¡}|S )Nr   Ú r   r   r,   é   r
   r-   )r   r   )r   r   r"   r   r   r>   rB   r   r=   r   rE   r   r   rC   Zunfoldr   r?   r%   ÚsplitrA   rF   r)   ZsoftmaxÚ
contiguousÚviewr@   rD   rG   )r(   r   r   ÚCr   r   Znum_h_blocksZnum_w_blocksZ
num_blocksr   rE   ÚkÚvZattnÚoutr   r   r   r0   ©   sf    


    þ     þ 
  
  ÿ   ÿ"    ÿ
zHaloAttn.forward)NNr   r7   Nr7   r,   r8   FFF)r1   r2   r3   r4   r!   rH   r0   r5   r   r   r*   r   r6   a   s                       þ%r6   )r4   Útypingr   r%   r   Ztorch.nn.functionalZ
functionalr   Zhelpersr   Zweight_initr   Ztrace_utilsr   Úintr   ÚModuler   r6   r   r   r   r   Ú<module>   s   $t