a
    dx&                     @   s   d Z ddl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g dfddZg ddfddZg dfddZg dfddZdS )zM Model / state_dict utils

Hacked together by / Copyright 2020 Ross Wightman
    N)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   Y/var/www/html/stable-diffusion-webui/venv/lib/python3.9/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g ddd  S )zA calculate average channel square mean of output activations
    r         Zaxisr   )torchmeanitemr   inputoutputr   r   r   avg_sq_ch_mean   s    r   c                 C   s   t |jg dd S z> calculate average channel variance of output activations
    r   r   r   r   varr   r   r   r   r   
avg_ch_var    s    r!   c                 C   s   t |jg d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>E       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_statsJ   s    zAActivationStatsHook._create_hook.<locals>.append_activation_statsr   )r1   r&   r7   r   r6   r   _create_hookI   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   P   s    z!ActivationStatsHook.register_hookN)r$   
__module____qualname____doc__r3   r8   r0   r   r   r   r   r#   ,   s   r#   )   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_statsW   s    rE   Tfreezec           
         s"  |dv sJ 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rdnd|_q|rd	d
 }|dkrt|}	t |tjjjjtjjjjttfr| ||	 qt|}	t |ttfr| ||	 qd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"zYou 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>   r(   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)r   r   nnmodulesZ	batchnormZBatchNorm2dZSyncBatchNormr   r   AssertionErrorstrr+   listr/   Znamed_children
parametersZrequires_gradr   r   r   r   )
rK   
submodulesinclude_bn_running_statsmoder9   nrI   prQ   resr   rJ   r   _freeze_unfreezei   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   rY   rZ   Nr^   rK   rX   rY   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_   Nr`   ra   r   r   r   rG      s    rG   )r>   r:   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   r   r   r   r   <module>   s    /
E"