code: def freeze_modules_based_on_opts(
      opts: argparse.Namespace,
      model: torch.nn.Module,
      verbose: bool = True,
  ) -> torch.nn.Module:
      """
      Allows for freezing immediate modules and parameters of the model using --model.freeze-modules.
  
      --model.freeze-modules should be a list of strings or a comma-separated list of regex expressions.
  
      Examples of --model.freeze-modules:
          "conv.*"  # see example below: can freeze all (top-level) conv layers
          "^((?!classifier).)*$"   # freezes everything except for "classifier": useful for linear probing
          "conv1,layer1,layer2,layer3"  # freeze all layers up to layer3
  
      >>> model = nn.Sequential(OrderedDict([
            ('conv1', nn.Conv2d(1, 20, 5)),
            ('relu1', nn.ReLU()),
            ('conv2', nn.Conv2d(20, 64, 5)),
            ('relu2', nn.ReLU())
          ]))
      >>> opts = argparse.Namespace(**{"model.freeze_modules": "conv1"})
      >>> _ = freeze_modules_based_on_opts(opts, model)
      INFO    - Freezing module: conv1
      >>> model.train()
      >>> model.conv1.training
      False
      >>> model.conv2.training
      True
      """
      freeze_patterns = getattr(opts, "model.freeze_modules", "")
      freeze_patterns = clean_strip(freeze_patterns)
  
      verbose = verbose and is_master(opts)
  
      if freeze_patterns:
          # TODO: allow applying on all modules, not just immediate chidren? How?
          for name, module in model.named_children():
              if any([re.match(p, name) for p in freeze_patterns]):
                  freeze_module(module)
                  if verbose:
                      logger.info("Freezing module: {}".format(name))
  
          for name, param in model.named_parameters(recurse=False):
              if any([re.match(p, name) for p in freeze_patterns]):
                  param.requires_grad = False
                  if verbose:
                      logger.info("Freezing parameter: {}".format(name))
  
      if verbose and hasattr(model, "get_trainable_parameters"):
          param_list, _ = model.get_trainable_parameters()
          for params in param_list:
              if (
                  not isinstance(params["param_names"], List)
                  or not isinstance(params["params"], List)
                  or not isinstance(
                      params["weight_decay"], (float, int)
                  )
              ):
                  param_types = {k: type(v) for k, v in params.items()}
                  logger.error(
                      "Expected parameter format: {{ params: List, weight_decay: float, param_names: List }}. "
                      "Got: {}".format(param_types)
                  )
          # Flatten all parameter names
          trainable_param_names = [
              p for x in param_list for p in x["param_names"]
          ]
          logger.info(
              "Trainable parameters: {}".format(trainable_param_names)
          )
  
      return model
  
file_path: ml-cvnets/cvnets/misc/common.py
imports: import argparse
  import os
  import re
  from types import MethodType
  from typing import Dict, List, Optional, Tuple, Union
  import torch
  from torch import Tensor
  from utils import logger
  from utils.common_utils import unwrap_model_fn
  from utils.ddp_utils import is_master, is_start_rank_node
label_desc: Use image node_id 5 for calling a global function with example usage: freeze_modules_based_on_opts(opts, model, verbose) and returns: model