U
    ¯Ê¹j´(  ã                   @   sì   d Z ddlZddlmZ ddlZddlmZ ddlmZm	Z	m
Z
mZmZ ddlmZ dd	„ Zefd
d„Zdd„ Zdd„ Zdd„ ZG dd„ dƒZddddgfdd„Zg ddfdd„Zg dfdd„Zg dfdd„Zd$ejjejjd!œd"d#„ZdS )%zM Model / state_dict utils

Hacked together by / Copyright 2020 Ross Wightman
é    N©Údeepcopy)ÚFrozenBatchNorm2d)ÚBatchNormAct2dÚSyncBatchNormActÚFrozenBatchNormAct2dÚfreeze_batch_norm_2dÚunfreeze_batch_norm_2dé   )ÚModelEmac                 C   s,   t | tƒrt| jƒS t| dƒr$| jS | S d S )NÚmodule)Ú
isinstancer   Úunwrap_modelZemaÚhasattrr   )Úmodel© r   úO/var/www/html/bwave/python/venv/lib/python3.8/site-packages/timm/utils/model.pyr      s    

r   c                 C   s   || ƒ  ¡ S ©N)Z
state_dict)r   Z	unwrap_fnr   r   r   Úget_state_dict   s    r   c                 C   s    t  |jdddgd�d ¡ ¡ S )zA calculate average channel square mean of output activations
    r   é   é   ©Zaxis)ÚtorchÚmeanÚitem©r   ÚinputÚoutputr   r   r   Úavg_sq_ch_mean   s    r   c                 C   s   t  |jdddgd�¡ ¡ S ©z> calculate average channel variance of output activations
    r   r   r   r   ©r   r   Úvarr   r   r   r   r   Ú
avg_ch_var!   s    r"   c                 C   s   t  |jdddgd�¡ ¡ S r   r    r   r   r   r   Úavg_ch_var_residual'   s    r#   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚActivationStatsHooka  Iterates through each of `model`'s modules and matches modules using unix pattern 
    matching based on `hook_fn_locs` and registers `hook_fn` to the module if there is 
    a match. 

    Arguments:
        model (nn.Module): model from which we will extract the activation stats
        hook_fn_locs (List[str]): List of `hook_fn` locations based on Unix type string 
            matching with the name of model's modules. 
        hook_fns (List[Callable]): List of hook functions to be registered at every
            module in `layer_names`.
    
    Inspiration from https://docs.fast.ai/callback.hook.html.

    Refer to https://gist.github.com/amaarora/6e56942fcb46e67ba203f3009b30d950 for an example 
    on how to plot Signal Propogation Plots using `ActivationStatsHook`.
    c                 C   sb   || _ || _|| _t|ƒt|ƒkr*tdƒ‚tdd„ |D ƒƒ| _t||ƒD ]\}}|  ||¡ qHd S )Nz_Please provide `hook_fns` for each `hook_fn_locs`,                 their lengths are different.c                 s   s   | ]}|j g fV  qd S r   )Ú__name__)Ú.0Úhook_fnr   r   r   Ú	<genexpr>F   s     z/ActivationStatsHook.__init__.<locals>.<genexpr>)	r   Úhook_fn_locsÚhook_fnsÚlenÚ
ValueErrorÚdictÚstatsÚzipÚregister_hook)Úselfr   r)   r*   Úhook_fn_locr'   r   r   r   Ú__init__?   s    zActivationStatsHook.__init__c                    s   ‡ ‡fdd„}|S )Nc                    s"   ˆ | ||ƒ}ˆj ˆ j  |¡ d S r   )r.   r%   Úappend)r   r   r   Úout©r'   r1   r   r   Úappend_activation_statsK   s    zAActivationStatsHook._create_hook.<locals>.append_activation_statsr   )r1   r'   r7   r   r6   r   Ú_create_hookJ   s    z ActivationStatsHook._create_hookc                 C   s6   | j  ¡ D ]&\}}t ||¡s q
| |  |¡¡ q
d S r   )r   Únamed_modulesÚfnmatchZregister_forward_hookr8   )r1   r2   r'   Únamer   r   r   r   r0   Q   s    z!ActivationStatsHook.register_hookN)r%   Ú
__module__Ú__qualname__Ú__doc__r3   r8   r0   r   r   r   r   r$   -   s   r$   é   r   éà   c                 C   s*   t  dd|¡}t| ||d�}| |ƒ}|jS )a  Extract average square channel mean and variance of activations during 
    forward pass to plot Signal Propogation Plots (SPP).
    
    Paper: https://arxiv.org/abs/2101.08692

    Example Usage: https://gist.github.com/amaarora/6e56942fcb46e67ba203f3009b30d950
    g        g      ð?)r)   r*   )r   Únormalr$   r.   )r   r)   r*   Zinput_shapeÚxÚhookÚ_r   r   r   Úextract_spp_statsX   s    rE   TÚfreezec           
         s"  |dkst dƒ‚tˆ tjjjjtjjjjtt	fƒr:t dƒ‚t|t
ƒrJ|g}|}‡ fdd„|D ƒ}t|ƒs|ttˆ  ¡ Ž ƒ\}}t||ƒD ]–\}}| ¡ D ]}|dkr¦dnd|_q–|r†d	d
„ }|dkrút|ƒ}	t|tjjjjtjjjjtt	fƒrø|ˆ ||	ƒ q†t|ƒ}	t|ttfƒr†|ˆ ||	ƒ q†dS )a4  
    Freeze or unfreeze parameters of the specified modules and those of all their hierarchical descendants. This is
    done in place.
    Args:
        root_module (nn.Module, optional): Root module relative to which the `submodules` are referenced.
        submodules (list[str]): List of modules for which the parameters will be (un)frozen. They are to be provided as
            named modules relative to the root module (accessible via `root_module.named_modules()`). An empty list
            means that the whole root module will be (un)frozen. Defaults to []
        include_bn_running_stats (bool): Whether to also (un)freeze the running statistics of batch norm 2d layers.
            Defaults to `True`.
        mode (bool): Whether to freeze ("freeze") or unfreeze ("unfreeze"). Defaults to `"freeze"`.
    )rF   Úunfreezez,`mode` must be one of "freeze" or "unfreeze"z£You have provided a batch norm layer as the `root module`. Please use `timm.utils.model.freeze_batch_norm_2d` or `timm.utils.model.unfreeze_batch_norm_2d` instead.c                    s   g | ]}ˆ   |¡‘qS r   )Úget_submodule)r&   Úm©Úroot_moduler   r   Ú
<listcomp>ˆ   s     z$_freeze_unfreeze.<locals>.<listcomp>rF   FTc                 S   sD   |  dd¡}t|ƒdkr4|  |d ¡ |d |¡ n|  ||¡ d S )NÚ.r
   r   )Úrsplitr+   rH   Z
add_module)r   r;   Ú	submoduleÚsplitr   r   r   Ú_add_submodule“   s    z(_freeze_unfreeze.<locals>._add_submoduleN)ÚAssertionErrorr   r   ÚnnÚmodulesZ	batchnormZBatchNorm2dZSyncBatchNormr   r   Ústrr+   Úlistr/   Únamed_childrenÚ
parametersZrequires_gradr   r	   r   r   )
rK   Ú
submodulesÚinclude_bn_running_statsÚmoder9   ÚnrI   ÚprQ   Úresr   rJ   r   Ú_freeze_unfreezej   sB    

üÿ


ür_   c                 C   s   t | ||dd� dS )a¡  
    Freeze parameters of the specified modules and those of all their hierarchical descendants. This is done in place.
    Args:
        root_module (nn.Module): Root module relative to which `submodules` are referenced.
        submodules (list[str]): List of modules for which the parameters will be frozen. They are to be provided as
            named modules relative to the root module (accessible via `root_module.named_modules()`). An empty list
            means that the whole root module will be frozen. Defaults to `[]`.
        include_bn_running_stats (bool): Whether to also freeze the running statistics of `BatchNorm2d` and
            `SyncBatchNorm` layers. These will be converted to `FrozenBatchNorm2d` in place. Hint: During fine tuning,
            it's good practice to freeze batch norm stats. And note that these are different to the affine parameters
            which are just normal PyTorch parameters. Defaults to `True`.

    Hint: If you want to freeze batch norm ONLY, use `timm.utils.model.freeze_batch_norm_2d`.

    Examples::

        >>> model = timm.create_model('resnet18')
        >>> # Freeze up to and including layer2
        >>> submodules = [n for n, _ in model.named_children()]
        >>> print(submodules)
        ['conv1', 'bn1', 'act1', 'maxpool', 'layer1', 'layer2', 'layer3', 'layer4', 'global_pool', 'fc']
        >>> freeze(model, submodules[:submodules.index('layer2') + 1])
        >>> # Check for yourself that it works as expected
        >>> print(model.layer2[0].conv1.weight.requires_grad)
        False
        >>> print(model.layer3[0].conv1.weight.requires_grad)
        True
        >>> # Unfreeze
        >>> unfreeze(model)
    rF   ©rZ   r[   N©r_   ©rK   rY   rZ   r   r   r   rF   ¯   s    c                 C   s   t | ||dd� dS )a  
    Unfreeze parameters of the specified modules and those of all their hierarchical descendants. This is done in place.
    Args:
        root_module (nn.Module): Root module relative to which `submodules` are referenced.
        submodules (list[str]): List of submodules for which the parameters will be (un)frozen. They are to be provided
            as named modules relative to the root module (accessible via `root_module.named_modules()`). An empty
            list means that the whole root module will be unfrozen. Defaults to `[]`.
        include_bn_running_stats (bool): Whether to also unfreeze the running statistics of `FrozenBatchNorm2d` layers.
            These will be converted to `BatchNorm2d` in place. Defaults to `True`.

    See example in docstring for `freeze`.
    rG   r`   Nra   rb   r   r   r   rG   Ñ   s    rG   F)r   Úreturnc                    s$   |st | ƒ} ‡ fdd„‰ ˆ | ƒ | S )Nc                    s`   |   ¡ D ]R\}}t|dƒr,t| || ¡ ƒ n&t|dƒr@| ¡  nt|dƒrR| ¡  ˆ |ƒ qd S )NÚfuseÚreparameterizeÚswitch_to_deploy)rW   r   Úsetattrrd   re   rf   )rI   Z
child_nameÚchild©Ú_fuser   r   rj   å   s    



z#reparameterize_model.<locals>._fuser   )r   Zinplacer   ri   r   Úreparameterize_modelá   s
    
rk   )F)r>   r:   Úcopyr   r   Ztorchvision.ops.miscr   Ztimm.layersr   r   r   r   r	   Z	model_emar   r   r   r   r"   r#   r$   rE   r_   rF   rG   rS   ÚModulerk   r   r   r   r   Ú<module>   s$   /
ü
E"