o
    wiL+                     @   sH  d dl Z d dlmZmZmZmZmZmZ d dlm	Z	 eG dd deZ
ede	jdZee	jge	jf Zee	jgeee
f f Z	d d	ed
ededefddZ	d d	ed
ededefddZd d	e	jd
ededefddZ	d!d	ed
edefddZ	d!ded
edefddZ			d!ded
edededef
ddZdd Zdd ZdS )"    N)CallableIterableProtocolTypeVarUnionruntime_checkable)nnc                   @   s   e Zd ZdefddZdS )HasBoolreturnc                 C   s   d S N )selfr   r   Y/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/nemo/collections/llm/fn/base.py__bool__   s    zHasBool.__bool__N)__name__
__module____qualname__boolr   r   r   r   r   r	      s    r	   _TModule)boundFmodulefunc	leaf_onlyr
   c                    s   | ddst dr j|fd|i|S t tr<t fdddD r1t |fd|i|S t |fd|i|S t |fd|i|S )a  Applies a function to a PyTorch module or a collection of modules.

    This function can be used to modify modules in place, such as changing their attributes,
    applying normalization, or any other custom transformations. It supports individual modules,
    lists of modules, and dictionaries of modules. The function can be applied selectively to
    modules that do not have parameters if `leaf_only` is set to True.

    Args:
        module: The module or collection of modules to which the function will be applied.
        func: A callable that takes a module (and optionally additional keyword arguments) and
              returns a transformed module. The signature should be `func(module, **kwargs)`.
        leaf_only: If True, the function will only be applied to modules that
                                    do not have any parameters. Defaults to False.
        **kwargs: Additional keyword arguments that will be passed to `func`.

    Returns
    -------
        The transformed module or collection of modules.

    Examples
    --------
        >>> import torch
        >>> import torch.nn as nn
        >>> from nemo.collections.llm import fn

        # Example: Doubling the weights of all Linear layers in a model
        model = nn.Sequential(nn.Linear(10, 20), nn.ReLU(), nn.Linear(20, 10))
        def double_weights(m):
            if isinstance(m, nn.Linear):
                m.weight.data *= 2
            return m
        model = fn.map(model, double_weights)
        print(model)

    	_skip_mapFmapr   c                 3   s    | ]}t  |V  qd S r   )hasattr).0keyr   r   r   	<genexpr>L   s    zmap.<locals>.<genexpr>)itemsvalueskeys)	popr   r   
isinstancer   all_map_module_dict_map_module_list_map_moduler   r   r   kwargsr   r   r   r      s   )
r   c                 K   s   t | |fd|d|S )a/  Recursively apply a function to a module or collection.

    This function is similar to `map`, but it applies the function recursively to all child
    modules as well. This is useful for applying transformations that need to consider the
    module hierarchy.

    Args:
        module: The module or collection to recursively apply to.
        func: The function to apply.
        leaf_only: If True, only apply to modules without parameters. Defaults to False.
        **kwargs: Additional kwargs to pass to the function.

    Returns
    -------
        The transformed module or collection.

    Examples
    --------
        >>> import torch
        >>> import torch.nn as nn
        >>> from nemo.collections.llm import fn

        # Example: Setting the bias of all Conv2d layers to False
        model = nn.Sequential(nn.Conv2d(1, 20, 5), nn.ReLU(), nn.Conv2d(20, 10, 5))
        def remove_bias(m):
            if isinstance(m, nn.Conv2d):
                m.bias = None
            return m
        model = fn.walk(model, remove_bias)
        print(model)
    T)recurser   )r   r)   r   r   r   walkT   s   %r,   r+   c                    s@   fdd |r fdd|   D }t|S  | g}t|S )ao  
    Checks if a predicate holds for all modules in a given module or its children, optionally
    recursively.

    This function iterates over all modules and applies a predicate function to determine if
    all modules satisfy a certain condition. If `recurse` is True, it checks all child modules
    recursively.

    Args:
        module (nn.Module): The root module to check.
        func (ModulePredicate): A predicate function that takes a module as input and returns
                                a boolean or an object that can be evaluated as a boolean.
        recurse (bool): If True, applies the predicate recursively to all child modules.
                        Defaults to False.

    Returns
    -------
        bool: True if all modules satisfy the predicate, False otherwise.

    Examples
    --------
        >>> import torch.nn as nn
        >>> model = nn.Sequential(nn.Linear(10, 20), nn.ReLU(), nn.Linear(20, 10))
        >>> predicate = lambda m: isinstance(m, nn.Linear)
        >>> print(forall(model, predicate))
        False
        >>> print(forall(model, predicate, recurse=True))
        True
    c                    s    | }t |S r   )r   )mresult)r   r   r   apply_predicate   s   zforall.<locals>.apply_predicatec                    s   g | ]} |qS r   r   )r   r-   )r/   r   r   
<listcomp>   s    zforall.<locals>.<listcomp>)modulesr%   )r   r   r+   resultsr   )r/   r   r   forall   s   
r3   c                 K   s   |du rt  }t| |v r| S | }t|fi |}|r#t| jddr+||fi |}|dds7|ddn
|d  d|d  }|dd |dd |dd t|  D ]\}	\}
}t	||
t
||f||||	|
|d	| qZ|t| |S )
a  
    Applies a transformation function to a module and optionally to its child modules.

    Parameters
    ----------
    module : nn.Module
        The module to which the function will be applied.
    func : ModuleFunc
        The function that will be applied to the module.
    recurse : bool, optional
        Whether to apply the function recursively to child modules.
    leaf_only : bool, optional
        Whether to apply the function only to modules without parameters.
    transformed_modules : set, optional
        A set to keep track of modules that have already been transformed.
    **kwargs : dict
        Additional keyword arguments that will be passed to the transformation function.

    Returns
    -------
    nn.Module
        The transformed module.
    NF)r+   prefix name.ir+   r   transformed_modulesr8   r6   r4   )setid_get_func_kwargslist
parametersgetr#   	enumeratenamed_childrensetattrr   add)r   r   r+   r   r:   r*   
new_modulef_kwargsr4   r8   r6   childr   r   r   r(      s@   .	r(   module_listc              
   K   s   |d u rt  }t|fi |}|s|| fi |} g }|dds'|ddn
|d  d|d  }|dd  |dd  |dd  t| D ]\}	}
t|
|f||||	t|	|d|}|| qHt| |S )Nr4   r5   r6   r7   r8   r9   )	r;   r=   r@   r#   rA   r   strappend_create_list_wrapper)rH   r   r+   r   r:   r*   rF   mapped_modulesr4   r8   r   rE   r   r   r   r'      s4   .	
r'   module_dictc                 K   s   |du rt  }t|fi |}|s|| fi |} i }t|  D ]\}\}	}
||d< |	|d< t|
|f|||d|||	< q!t| |S )a  
    Applies a transformation function to a ModuleDict of modules.

    Parameters
    ----------
    module_dict : nn.ModuleDict
        The ModuleDict of modules to which the function will be applied.
    func : ModuleFunc
        The function that will be applied to the modules.
    recurse : bool, optional
        Whether to apply the function recursively to child modules.
    parameterless_modules_only : bool, optional
        Whether to apply the function only to modules without parameters.
    **kwargs : dict
        Additional keyword arguments that will be passed to the transformation function.

    Returns
    -------
    nn.ModuleDict
        The ModuleDict of transformed modules.
    Nr8   r6   )r+   r   r:   )r;   r=   rA   r    r   type)rM   r   r+   r   r:   r*   rF   rL   r8   r6   r   r   r   r   r&     s(   	r&   c                 C   s2   t t| j}d|jv rt| | S t| |S )Nargs)inspect	signaturerN   __init__r?   )rH   to_addsigr   r   r   rK   F  s   
rK   c                    s    t |   fdd| D S )Nc                    s    i | ]\}}| j v r||qS r   )r?   )r   kwargvaluerT   r   r   
<dictcomp>Q  s     z$_get_func_kwargs.<locals>.<dictcomp>)rP   rQ   r    )r   r*   r   rW   r   r=   O  s   
r=   )F)FFN)rP   typingr   r   r   r   r   r   torchr   r	   Moduler   
ModuleFuncr   ModulePredicater   r,   r3   r(   r'   r&   rK   r=   r   r   r   r   <module>   sz    
8
./
B
#
5	