o
    wi@                     @   sN   d dl mZ d dlmZ d dlmZ d dlmZ	 d dl
mZ G dd dZdS )    N)nn)Self)base)loggingc                       s   e Zd ZdZ fddZddejdedefdd	Zddej	d
ede
fddZddej	d
ede
fddZdddZdddZ  ZS )FNMixina  
    A mixin class providing utility methods for operating on PyTorch modules.

    This mixin class offers methods to apply functions, check predicates, and modify
    the state (freeze/unfreeze) of PyTorch modules within a container. It is designed
    to be used with classes that are composed of multiple PyTorch modules, facilitating
    operations that affect all contained modules either directly or recursively.

    Methods
    -------
        forall: Checks if a predicate holds for all modules.
        map: Applies a function to each module.
        walk: Traverses each module, applying a function.
        freeze: Freezes the parameters of all modules.
        unfreeze: Unfreezes the parameters of all modules.

    Examples
    --------
        >>> class MyModel(nn.Module, FNMixin):
        ...     def __init__(self):
        ...         super().__init__()
        ...         self.layer1 = nn.Linear(10, 10)
        ...         self.layer2 = nn.Linear(10, 10)
        ...
        >>> model = MyModel()
        >>> model.freeze()  # Freezes all parameters in the model
        >>> model.forall(lambda module: not module.parameters().requires_grad, recurse=True)
        True
    c                    s:   t | tjrddlm} || dd t jdi | d S )Nr   )hook_class_init_with_callbackson_model_init_starton_model_init_end )
issubclassplLightningModulenemo.lightning.callback_groupr   super__init_subclass__)clskwargsr   	__class__r
   Z/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/nemo/collections/llm/fn/mixin.pyr   6   s   zFNMixin.__init_subclass__Ffuncrecursereturnc                 C   s$   t | tjs
J dtj| ||dS )a  
        Evaluates a predicate for all modules in the container, optionally recursively.

        This method checks if a given predicate holds for all modules in the container.
        If `recurse` is True, it also checks all submodules recursively.

        Args:
            func (fn.ModulePredicate): A predicate function to apply to each module.
            recurse (bool, optional): Whether to apply the predicate recursively. Defaults to False.

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

        Example:
            >>> model = MyModel()
            >>> model.forall(lambda module: isinstance(module, nn.Linear), recurse=True)
            True
        self is not a nn.Module)r   )
isinstancer   Modulefnforall)selfr   r   r
   r
   r   r   ?   s   zFNMixin.forall	leaf_onlyc                 C   &   t | tjs
J dtj| ||ddS )a  
        Applies a function to each module in the container, optionally to leaf modules only.

        This method applies a given function to each module in the container. If `leaf_only`
        is True, the function is applied to leaf modules only.

        Args:
            func (fn.ModuleFunc): A function to apply to each module.
            leaf_only (bool, optional): Whether to apply the function to leaf modules only. Defaults to False.

        Returns
        -------
            Self: The container itself after applying the function.

        Example:
            >>> model = MyModel()
            >>> model.map(lambda module: module.double() if isinstance(module, nn.Linear) else module)
            <MyModel object>
        r   Tr   	_skip_map)r   r   r   r   mapr   r   r   r
   r
   r   r#   W      zFNMixin.mapc                 C   r    )a  
        Traverses each module in the container, applying a function, optionally to leaf modules only.

        This method is similar to `map`, but it is typically used for operations that do not
        modify the modules but instead collect information or perform checks.

        Args:
            func (fn.ModuleFunc): A function to apply to each module.
            leaf_only (bool, optional): Whether to traverse leaf modules only. Defaults to False.

        Returns
        -------
            Self: The container itself after the traversal.

        Example:
            >>> model = MyModel()
            >>> model.walk(print, leaf_only=True)
            <MyModel object>
        r   Tr!   )r   r   r   r   walkr$   r
   r
   r   r&   o   r%   zFNMixin.walkNc                 C   P   t | tjs
J dt|  }|std| jj  dS |D ]}d|_	q dS )zu
        Freezes the parameters of all modules in the container
        by setting `requires_grad` to False.
        r   No parameters found in module FN
r   r   r   list
parametersr   infor   __name__requires_gradr   paramsparamr
   r
   r   freeze      zFNMixin.freezec                 C   r'   )zv
        Unfreezes the parameters of all modules in the container
        by setting `requires_grad` to True.
        r   r(   TNr)   r/   r
   r
   r   unfreeze   r3   zFNMixin.unfreeze)F)r   N)r-   
__module____qualname____doc__r   r   ModulePredicateboolr   
ModuleFuncr   r#   r&   r2   r4   __classcell__r
   r
   r   r   r      s    	
r   )lightning.pytorchpytorchr   torchr   typing_extensionsr   nemo.collections.llm.fnr   r   
nemo.utilsr   r   r
   r
   r
   r   <module>   s   