We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
用户设置完了paramwise_cfg，如何知道是否符合预期，这个是否也要提供相应的脚本，用户运行后可以很容易的知道哪些参数被 frozen，不太参数组超参的不同。暂时没有时间开发的话，可以作为未来一个需求吧
用户设置完了，如何知道是否符合预期，这个是否也要提供相应的脚本，用户运行后可以很容易的知道哪些参数被 frozen，不太参数组超参的不同。暂时没有时间开发的话，可以作为未来一个需求吧

_Originally posted by @hhaAndroid in https://github.com/open-mmlab/mmengine/pull/25#discussion_r809786760_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mmengine/optim/optimizer/default_constructor.py`
Content:
```
1 # Copyright (c) OpenMMLab. All rights reserved.
2 import warnings
3 from typing import List, Optional, Union
4 
5 import torch
6 import torch.nn as nn
7 from torch.nn import GroupNorm, LayerNorm
8 
9 from mmengine.registry import OPTIMIZER_CONSTRUCTORS, OPTIMIZERS
10 from mmengine.utils import is_list_of, mmcv_full_available
11 from mmengine.utils.parrots_wrapper import _BatchNorm, _InstanceNorm
12 
13 
14 @OPTIMIZER_CONSTRUCTORS.register_module()
15 class DefaultOptimizerConstructor:
16     """Default constructor for optimizers.
17 
18     By default each parameter share the same optimizer settings, and we
19     provide an argument ``paramwise_cfg`` to specify parameter-wise settings.
20     It is a dict and may contain the following fields:
21 
22     - ``custom_keys`` (dict): Specified parameters-wise settings by keys. If
23       one of the keys in ``custom_keys`` is a substring of the name of one
24       parameter, then the setting of the parameter will be specified by
25       ``custom_keys[key]`` and other setting like ``bias_lr_mult`` etc. will
26       be ignored. It should be noted that the aforementioned ``key`` is the
27       longest key that is a substring of the name of the parameter. If there
28       are multiple matched keys with the same length, then the key with lower
29       alphabet order will be chosen.
30       ``custom_keys[key]`` should be a dict and may contain fields ``lr_mult``
31       and ``decay_mult``. See Example 2 below.
32     - ``bias_lr_mult`` (float): It will be multiplied to the learning
33       rate for all bias parameters (except for those in normalization
34       layers and offset layers of DCN).
35     - ``bias_decay_mult`` (float): It will be multiplied to the weight
36       decay for all bias parameters (except for those in
37       normalization layers, depthwise conv layers, offset layers of DCN).
38     - ``norm_decay_mult`` (float): It will be multiplied to the weight
39       decay for all weight and bias parameters of normalization
40       layers.
41     - ``dwconv_decay_mult`` (float): It will be multiplied to the weight
42       decay for all weight and bias parameters of depthwise conv
43       layers.
44     - ``dcn_offset_lr_mult`` (float): It will be multiplied to the learning
45       rate for parameters of offset layer in the deformable convs
46       of a model.
47     - ``bypass_duplicate`` (bool): If true, the duplicate parameters
48       would not be added into optimizer. Default: False.
49 
50     Note:
51 
52         1. If the option ``dcn_offset_lr_mult`` is used, the constructor will
53         override the effect of ``bias_lr_mult`` in the bias of offset layer.
54         So be careful when using both ``bias_lr_mult`` and
55         ``dcn_offset_lr_mult``. If you wish to apply both of them to the offset
56         layer in deformable convs, set ``dcn_offset_lr_mult`` to the original
57         ``dcn_offset_lr_mult`` * ``bias_lr_mult``.
58 
59         2. If the option ``dcn_offset_lr_mult`` is used, the constructor will
60         apply it to all the DCN layers in the model. So be careful when the
61         model contains multiple DCN layers in places other than backbone.
62 
63     Args:
64         optimizer_cfg (dict): The config dict of the optimizer.
65             Positional fields are
66 
67                 - `type`: class name of the optimizer.
68 
69             Optional fields are
70 
71                 - any arguments of the corresponding optimizer type, e.g.,
72                   lr, weight_decay, momentum, etc.
73         paramwise_cfg (dict, optional): Parameter-wise options.
74 
75     Example 1:
76         >>> model = torch.nn.modules.Conv1d(1, 1, 1)
77         >>> optimizer_cfg = dict(type='SGD', lr=0.01, momentum=0.9,
78         >>>                      weight_decay=0.0001)
79         >>> paramwise_cfg = dict(norm_decay_mult=0.)
80         >>> optim_builder = DefaultOptimizerConstructor(
81         >>>     optimizer_cfg, paramwise_cfg)
82         >>> optimizer = optim_builder(model)
83 
84     Example 2:
85         >>> # assume model have attribute model.backbone and model.cls_head
86         >>> optimizer_cfg = dict(type='SGD', lr=0.01, weight_decay=0.95)
87         >>> paramwise_cfg = dict(custom_keys={
88                 '.backbone': dict(lr_mult=0.1, decay_mult=0.9)})
89         >>> optim_builder = DefaultOptimizerConstructor(
90         >>>     optimizer_cfg, paramwise_cfg)
91         >>> optimizer = optim_builder(model)
92         >>> # Then the `lr` and `weight_decay` for model.backbone is
93         >>> # (0.01 * 0.1, 0.95 * 0.9). `lr` and `weight_decay` for
94         >>> # model.cls_head is (0.01, 0.95).
95     """
96 
97     def __init__(self,
98                  optimizer_cfg: dict,
99                  paramwise_cfg: Optional[dict] = None):
100         if not isinstance(optimizer_cfg, dict):
101             raise TypeError('optimizer_cfg should be a dict',
102                             f'but got {type(optimizer_cfg)}')
103         self.optimizer_cfg = optimizer_cfg
104         self.paramwise_cfg = {} if paramwise_cfg is None else paramwise_cfg
105         self.base_lr = optimizer_cfg.get('lr', None)
106         self.base_wd = optimizer_cfg.get('weight_decay', None)
107         self._validate_cfg()
108 
109     def _validate_cfg(self) -> None:
110         """verify the correctness of the config."""
111         if not isinstance(self.paramwise_cfg, dict):
112             raise TypeError('paramwise_cfg should be None or a dict, '
113                             f'but got {type(self.paramwise_cfg)}')
114 
115         if 'custom_keys' in self.paramwise_cfg:
116             if not isinstance(self.paramwise_cfg['custom_keys'], dict):
117                 raise TypeError(
118                     'If specified, custom_keys must be a dict, '
119                     f'but got {type(self.paramwise_cfg["custom_keys"])}')
120             if self.base_wd is None:
121                 for key in self.paramwise_cfg['custom_keys']:
122                     if 'decay_mult' in self.paramwise_cfg['custom_keys'][key]:
123                         raise ValueError('base_wd should not be None')
124 
125         # get base lr and weight decay
126         # weight_decay must be explicitly specified if mult is specified
127         if ('bias_decay_mult' in self.paramwise_cfg
128                 or 'norm_decay_mult' in self.paramwise_cfg
129                 or 'dwconv_decay_mult' in self.paramwise_cfg):
130             if self.base_wd is None:
131                 raise ValueError('base_wd should not be None')
132 
133     def _is_in(self, param_group: dict, param_group_list: list) -> bool:
134         """check whether the `param_group` is in the`param_group_list`"""
135         assert is_list_of(param_group_list, dict)
136         param = set(param_group['params'])
137         param_set = set()
138         for group in param_group_list:
139             param_set.update(set(group['params']))
140 
141         return not param.isdisjoint(param_set)
142 
143     def add_params(self,
144                    params: List[dict],
145                    module: nn.Module,
146                    prefix: str = '',
147                    is_dcn_module: Optional[Union[int, float]] = None) -> None:
148         """Add all parameters of module to the params list.
149 
150         The parameters of the given module will be added to the list of param
151         groups, with specific rules defined by paramwise_cfg.
152 
153         Args:
154             params (list[dict]): A list of param groups, it will be modified
155                 in place.
156             module (nn.Module): The module to be added.
157             prefix (str): The prefix of the module
158             is_dcn_module (int|float|None): If the current module is a
159                 submodule of DCN, `is_dcn_module` will be passed to
160                 control conv_offset layer's learning rate. Defaults to None.
161         """
162         # get param-wise options
163         custom_keys = self.paramwise_cfg.get('custom_keys', {})
164         # first sort with alphabet order and then sort with reversed len of str
165         sorted_keys = sorted(sorted(custom_keys.keys()), key=len, reverse=True)
166 
167         bias_lr_mult = self.paramwise_cfg.get('bias_lr_mult', 1.)
168         bias_decay_mult = self.paramwise_cfg.get('bias_decay_mult', 1.)
169         norm_decay_mult = self.paramwise_cfg.get('norm_decay_mult', 1.)
170         dwconv_decay_mult = self.paramwise_cfg.get('dwconv_decay_mult', 1.)
171         bypass_duplicate = self.paramwise_cfg.get('bypass_duplicate', False)
172         dcn_offset_lr_mult = self.paramwise_cfg.get('dcn_offset_lr_mult', 1.)
173 
174         # special rules for norm layers and depth-wise conv layers
175         is_norm = isinstance(module,
176                              (_BatchNorm, _InstanceNorm, GroupNorm, LayerNorm))
177         is_dwconv = (
178             isinstance(module, torch.nn.Conv2d)
179             and module.in_channels == module.groups)
180 
181         for name, param in module.named_parameters(recurse=False):
182             param_group = {'params': [param]}
183             if not param.requires_grad:
184                 params.append(param_group)
185                 continue
186             if bypass_duplicate and self._is_in(param_group, params):
187                 warnings.warn(f'{prefix} is duplicate. It is skipped since '
188                               f'bypass_duplicate={bypass_duplicate}')
189                 continue
190             # if the parameter match one of the custom keys, ignore other rules
191             is_custom = False
192             for key in sorted_keys:
193                 if key in f'{prefix}.{name}':
194                     is_custom = True
195                     lr_mult = custom_keys[key].get('lr_mult', 1.)
196                     param_group['lr'] = self.base_lr * lr_mult
197                     if self.base_wd is not None:
198                         decay_mult = custom_keys[key].get('decay_mult', 1.)
199                         param_group['weight_decay'] = self.base_wd * decay_mult
200                     break
201 
202             if not is_custom:
203                 # bias_lr_mult affects all bias parameters
204                 # except for norm.bias dcn.conv_offset.bias
205                 if name == 'bias' and not (is_norm or is_dcn_module):
206                     param_group['lr'] = self.base_lr * bias_lr_mult
207 
208                 if (prefix.find('conv_offset') != -1 and is_dcn_module
209                         and isinstance(module, torch.nn.Conv2d)):
210                     # deal with both dcn_offset's bias & weight
211                     param_group['lr'] = self.base_lr * dcn_offset_lr_mult
212 
213                 # apply weight decay policies
214                 if self.base_wd is not None:
215                     # norm decay
216                     if is_norm:
217                         param_group[
218                             'weight_decay'] = self.base_wd * norm_decay_mult
219                     # depth-wise conv
220                     elif is_dwconv:
221                         param_group[
222                             'weight_decay'] = self.base_wd * dwconv_decay_mult
223                     # bias lr and decay
224                     elif name == 'bias' and not is_dcn_module:
225                         # TODO: current bias_decay_mult will have affect on DCN
226                         param_group[
227                             'weight_decay'] = self.base_wd * bias_decay_mult
228             params.append(param_group)
229 
230         if mmcv_full_available():
231             from mmcv.ops import DeformConv2d, ModulatedDeformConv2d
232             is_dcn_module = isinstance(module,
233                                        (DeformConv2d, ModulatedDeformConv2d))
234         else:
235             is_dcn_module = False
236         for child_name, child_mod in module.named_children():
237             child_prefix = f'{prefix}.{child_name}' if prefix else child_name
238             self.add_params(
239                 params,
240                 child_mod,
241                 prefix=child_prefix,
242                 is_dcn_module=is_dcn_module)
243 
244     def __call__(self, model: nn.Module) -> torch.optim.Optimizer:
245         if hasattr(model, 'module'):
246             model = model.module
247 
248         optimizer_cfg = self.optimizer_cfg.copy()
249         # if no paramwise option is specified, just use the global setting
250         if not self.paramwise_cfg:
251             optimizer_cfg['params'] = model.parameters()
252             return OPTIMIZERS.build(optimizer_cfg)
253 
254         # set param-wise lr and weight decay recursively
255         params: List = []
256         self.add_params(params, model)
257         optimizer_cfg['params'] = params
258 
259         return OPTIMIZERS.build(optimizer_cfg)
260
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mmengine/optim/optimizer/default_constructor.py b/mmengine/optim/optimizer/default_constructor.py
--- a/mmengine/optim/optimizer/default_constructor.py
+++ b/mmengine/optim/optimizer/default_constructor.py
@@ -5,6 +5,7 @@
 import torch
 import torch.nn as nn
 from torch.nn import GroupNorm, LayerNorm
+from mmengine.mmengine.logging.logger import print_log
 
 from mmengine.registry import OPTIMIZER_CONSTRUCTORS, OPTIMIZERS
 from mmengine.utils import is_list_of, mmcv_full_available
@@ -226,6 +227,13 @@
                         param_group[
                             'weight_decay'] = self.base_wd * bias_decay_mult
             params.append(param_group)
+            for key, value in param_group.items():
+                if key == 'params':
+                    continue
+                full_name = f'{prefix}.{name}' if prefix else name
+                print_log(
+                    f'paramwise_options -- {full_name}:{key}={value}',
+                    logger='current')
 
         if mmcv_full_available():
             from mmcv.ops import DeformConv2d, ModulatedDeformConv2d

{"golden_diff": "diff --git a/mmengine/optim/optimizer/default_constructor.py b/mmengine/optim/optimizer/default_constructor.py\n--- a/mmengine/optim/optimizer/default_constructor.py\n+++ b/mmengine/optim/optimizer/default_constructor.py\n@@ -5,6 +5,7 @@\n import torch\n import torch.nn as nn\n from torch.nn import GroupNorm, LayerNorm\n+from mmengine.mmengine.logging.logger import print_log\n \n from mmengine.registry import OPTIMIZER_CONSTRUCTORS, OPTIMIZERS\n from mmengine.utils import is_list_of, mmcv_full_available\n@@ -226,6 +227,13 @@\n                         param_group[\n                             'weight_decay'] = self.base_wd * bias_decay_mult\n             params.append(param_group)\n+            for key, value in param_group.items():\n+                if key == 'params':\n+                    continue\n+                full_name = f'{prefix}.{name}' if prefix else name\n+                print_log(\n+                    f'paramwise_options -- {full_name}:{key}={value}',\n+                    logger='current')\n \n         if mmcv_full_available():\n             from mmcv.ops import DeformConv2d, ModulatedDeformConv2d\n", "issue": "\u7528\u6237\u8bbe\u7f6e\u5b8c\u4e86paramwise_cfg\uff0c\u5982\u4f55\u77e5\u9053\u662f\u5426\u7b26\u5408\u9884\u671f\uff0c\u8fd9\u4e2a\u662f\u5426\u4e5f\u8981\u63d0\u4f9b\u76f8\u5e94\u7684\u811a\u672c\uff0c\u7528\u6237\u8fd0\u884c\u540e\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u77e5\u9053\u54ea\u4e9b\u53c2\u6570\u88ab frozen\uff0c\u4e0d\u592a\u53c2\u6570\u7ec4\u8d85\u53c2\u7684\u4e0d\u540c\u3002\u6682\u65f6\u6ca1\u6709\u65f6\u95f4\u5f00\u53d1\u7684\u8bdd\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u672a\u6765\u4e00\u4e2a\u9700\u6c42\u5427\n\u7528\u6237\u8bbe\u7f6e\u5b8c\u4e86\uff0c\u5982\u4f55\u77e5\u9053\u662f\u5426\u7b26\u5408\u9884\u671f\uff0c\u8fd9\u4e2a\u662f\u5426\u4e5f\u8981\u63d0\u4f9b\u76f8\u5e94\u7684\u811a\u672c\uff0c\u7528\u6237\u8fd0\u884c\u540e\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u77e5\u9053\u54ea\u4e9b\u53c2\u6570\u88ab frozen\uff0c\u4e0d\u592a\u53c2\u6570\u7ec4\u8d85\u53c2\u7684\u4e0d\u540c\u3002\u6682\u65f6\u6ca1\u6709\u65f6\u95f4\u5f00\u53d1\u7684\u8bdd\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u672a\u6765\u4e00\u4e2a\u9700\u6c42\u5427\r\n\r\n_Originally posted by @hhaAndroid in https://github.com/open-mmlab/mmengine/pull/25#discussion_r809786760_\n", "before_files": [{"content": "# Copyright (c) OpenMMLab. All rights reserved.\nimport warnings\nfrom typing import List, Optional, Union\n\nimport torch\nimport torch.nn as nn\nfrom torch.nn import GroupNorm, LayerNorm\n\nfrom mmengine.registry import OPTIMIZER_CONSTRUCTORS, OPTIMIZERS\nfrom mmengine.utils import is_list_of, mmcv_full_available\nfrom mmengine.utils.parrots_wrapper import _BatchNorm, _InstanceNorm\n\n\n@OPTIMIZER_CONSTRUCTORS.register_module()\nclass DefaultOptimizerConstructor:\n    \"\"\"Default constructor for optimizers.\n\n    By default each parameter share the same optimizer settings, and we\n    provide an argument ``paramwise_cfg`` to specify parameter-wise settings.\n    It is a dict and may contain the following fields:\n\n    - ``custom_keys`` (dict): Specified parameters-wise settings by keys. If\n      one of the keys in ``custom_keys`` is a substring of the name of one\n      parameter, then the setting of the parameter will be specified by\n      ``custom_keys[key]`` and other setting like ``bias_lr_mult`` etc. will\n      be ignored. It should be noted that the aforementioned ``key`` is the\n      longest key that is a substring of the name of the parameter. If there\n      are multiple matched keys with the same length, then the key with lower\n      alphabet order will be chosen.\n      ``custom_keys[key]`` should be a dict and may contain fields ``lr_mult``\n      and ``decay_mult``. See Example 2 below.\n    - ``bias_lr_mult`` (float): It will be multiplied to the learning\n      rate for all bias parameters (except for those in normalization\n      layers and offset layers of DCN).\n    - ``bias_decay_mult`` (float): It will be multiplied to the weight\n      decay for all bias parameters (except for those in\n      normalization layers, depthwise conv layers, offset layers of DCN).\n    - ``norm_decay_mult`` (float): It will be multiplied to the weight\n      decay for all weight and bias parameters of normalization\n      layers.\n    - ``dwconv_decay_mult`` (float): It will be multiplied to the weight\n      decay for all weight and bias parameters of depthwise conv\n      layers.\n    - ``dcn_offset_lr_mult`` (float): It will be multiplied to the learning\n      rate for parameters of offset layer in the deformable convs\n      of a model.\n    - ``bypass_duplicate`` (bool): If true, the duplicate parameters\n      would not be added into optimizer. Default: False.\n\n    Note:\n\n        1. If the option ``dcn_offset_lr_mult`` is used, the constructor will\n        override the effect of ``bias_lr_mult`` in the bias of offset layer.\n        So be careful when using both ``bias_lr_mult`` and\n        ``dcn_offset_lr_mult``. If you wish to apply both of them to the offset\n        layer in deformable convs, set ``dcn_offset_lr_mult`` to the original\n        ``dcn_offset_lr_mult`` * ``bias_lr_mult``.\n\n        2. If the option ``dcn_offset_lr_mult`` is used, the constructor will\n        apply it to all the DCN layers in the model. So be careful when the\n        model contains multiple DCN layers in places other than backbone.\n\n    Args:\n        optimizer_cfg (dict): The config dict of the optimizer.\n            Positional fields are\n\n                - `type`: class name of the optimizer.\n\n            Optional fields are\n\n                - any arguments of the corresponding optimizer type, e.g.,\n                  lr, weight_decay, momentum, etc.\n        paramwise_cfg (dict, optional): Parameter-wise options.\n\n    Example 1:\n        >>> model = torch.nn.modules.Conv1d(1, 1, 1)\n        >>> optimizer_cfg = dict(type='SGD', lr=0.01, momentum=0.9,\n        >>>                      weight_decay=0.0001)\n        >>> paramwise_cfg = dict(norm_decay_mult=0.)\n        >>> optim_builder = DefaultOptimizerConstructor(\n        >>>     optimizer_cfg, paramwise_cfg)\n        >>> optimizer = optim_builder(model)\n\n    Example 2:\n        >>> # assume model have attribute model.backbone and model.cls_head\n        >>> optimizer_cfg = dict(type='SGD', lr=0.01, weight_decay=0.95)\n        >>> paramwise_cfg = dict(custom_keys={\n                '.backbone': dict(lr_mult=0.1, decay_mult=0.9)})\n        >>> optim_builder = DefaultOptimizerConstructor(\n        >>>     optimizer_cfg, paramwise_cfg)\n        >>> optimizer = optim_builder(model)\n        >>> # Then the `lr` and `weight_decay` for model.backbone is\n        >>> # (0.01 * 0.1, 0.95 * 0.9). `lr` and `weight_decay` for\n        >>> # model.cls_head is (0.01, 0.95).\n    \"\"\"\n\n    def __init__(self,\n                 optimizer_cfg: dict,\n                 paramwise_cfg: Optional[dict] = None):\n        if not isinstance(optimizer_cfg, dict):\n            raise TypeError('optimizer_cfg should be a dict',\n                            f'but got {type(optimizer_cfg)}')\n        self.optimizer_cfg = optimizer_cfg\n        self.paramwise_cfg = {} if paramwise_cfg is None else paramwise_cfg\n        self.base_lr = optimizer_cfg.get('lr', None)\n        self.base_wd = optimizer_cfg.get('weight_decay', None)\n        self._validate_cfg()\n\n    def _validate_cfg(self) -> None:\n        \"\"\"verify the correctness of the config.\"\"\"\n        if not isinstance(self.paramwise_cfg, dict):\n            raise TypeError('paramwise_cfg should be None or a dict, '\n                            f'but got {type(self.paramwise_cfg)}')\n\n        if 'custom_keys' in self.paramwise_cfg:\n            if not isinstance(self.paramwise_cfg['custom_keys'], dict):\n                raise TypeError(\n                    'If specified, custom_keys must be a dict, '\n                    f'but got {type(self.paramwise_cfg[\"custom_keys\"])}')\n            if self.base_wd is None:\n                for key in self.paramwise_cfg['custom_keys']:\n                    if 'decay_mult' in self.paramwise_cfg['custom_keys'][key]:\n                        raise ValueError('base_wd should not be None')\n\n        # get base lr and weight decay\n        # weight_decay must be explicitly specified if mult is specified\n        if ('bias_decay_mult' in self.paramwise_cfg\n                or 'norm_decay_mult' in self.paramwise_cfg\n                or 'dwconv_decay_mult' in self.paramwise_cfg):\n            if self.base_wd is None:\n                raise ValueError('base_wd should not be None')\n\n    def _is_in(self, param_group: dict, param_group_list: list) -> bool:\n        \"\"\"check whether the `param_group` is in the`param_group_list`\"\"\"\n        assert is_list_of(param_group_list, dict)\n        param = set(param_group['params'])\n        param_set = set()\n        for group in param_group_list:\n            param_set.update(set(group['params']))\n\n        return not param.isdisjoint(param_set)\n\n    def add_params(self,\n                   params: List[dict],\n                   module: nn.Module,\n                   prefix: str = '',\n                   is_dcn_module: Optional[Union[int, float]] = None) -> None:\n        \"\"\"Add all parameters of module to the params list.\n\n        The parameters of the given module will be added to the list of param\n        groups, with specific rules defined by paramwise_cfg.\n\n        Args:\n            params (list[dict]): A list of param groups, it will be modified\n                in place.\n            module (nn.Module): The module to be added.\n            prefix (str): The prefix of the module\n            is_dcn_module (int|float|None): If the current module is a\n                submodule of DCN, `is_dcn_module` will be passed to\n                control conv_offset layer's learning rate. Defaults to None.\n        \"\"\"\n        # get param-wise options\n        custom_keys = self.paramwise_cfg.get('custom_keys', {})\n        # first sort with alphabet order and then sort with reversed len of str\n        sorted_keys = sorted(sorted(custom_keys.keys()), key=len, reverse=True)\n\n        bias_lr_mult = self.paramwise_cfg.get('bias_lr_mult', 1.)\n        bias_decay_mult = self.paramwise_cfg.get('bias_decay_mult', 1.)\n        norm_decay_mult = self.paramwise_cfg.get('norm_decay_mult', 1.)\n        dwconv_decay_mult = self.paramwise_cfg.get('dwconv_decay_mult', 1.)\n        bypass_duplicate = self.paramwise_cfg.get('bypass_duplicate', False)\n        dcn_offset_lr_mult = self.paramwise_cfg.get('dcn_offset_lr_mult', 1.)\n\n        # special rules for norm layers and depth-wise conv layers\n        is_norm = isinstance(module,\n                             (_BatchNorm, _InstanceNorm, GroupNorm, LayerNorm))\n        is_dwconv = (\n            isinstance(module, torch.nn.Conv2d)\n            and module.in_channels == module.groups)\n\n        for name, param in module.named_parameters(recurse=False):\n            param_group = {'params': [param]}\n            if not param.requires_grad:\n                params.append(param_group)\n                continue\n            if bypass_duplicate and self._is_in(param_group, params):\n                warnings.warn(f'{prefix} is duplicate. It is skipped since '\n                              f'bypass_duplicate={bypass_duplicate}')\n                continue\n            # if the parameter match one of the custom keys, ignore other rules\n            is_custom = False\n            for key in sorted_keys:\n                if key in f'{prefix}.{name}':\n                    is_custom = True\n                    lr_mult = custom_keys[key].get('lr_mult', 1.)\n                    param_group['lr'] = self.base_lr * lr_mult\n                    if self.base_wd is not None:\n                        decay_mult = custom_keys[key].get('decay_mult', 1.)\n                        param_group['weight_decay'] = self.base_wd * decay_mult\n                    break\n\n            if not is_custom:\n                # bias_lr_mult affects all bias parameters\n                # except for norm.bias dcn.conv_offset.bias\n                if name == 'bias' and not (is_norm or is_dcn_module):\n                    param_group['lr'] = self.base_lr * bias_lr_mult\n\n                if (prefix.find('conv_offset') != -1 and is_dcn_module\n                        and isinstance(module, torch.nn.Conv2d)):\n                    # deal with both dcn_offset's bias & weight\n                    param_group['lr'] = self.base_lr * dcn_offset_lr_mult\n\n                # apply weight decay policies\n                if self.base_wd is not None:\n                    # norm decay\n                    if is_norm:\n                        param_group[\n                            'weight_decay'] = self.base_wd * norm_decay_mult\n                    # depth-wise conv\n                    elif is_dwconv:\n                        param_group[\n                            'weight_decay'] = self.base_wd * dwconv_decay_mult\n                    # bias lr and decay\n                    elif name == 'bias' and not is_dcn_module:\n                        # TODO: current bias_decay_mult will have affect on DCN\n                        param_group[\n                            'weight_decay'] = self.base_wd * bias_decay_mult\n            params.append(param_group)\n\n        if mmcv_full_available():\n            from mmcv.ops import DeformConv2d, ModulatedDeformConv2d\n            is_dcn_module = isinstance(module,\n                                       (DeformConv2d, ModulatedDeformConv2d))\n        else:\n            is_dcn_module = False\n        for child_name, child_mod in module.named_children():\n            child_prefix = f'{prefix}.{child_name}' if prefix else child_name\n            self.add_params(\n                params,\n                child_mod,\n                prefix=child_prefix,\n                is_dcn_module=is_dcn_module)\n\n    def __call__(self, model: nn.Module) -> torch.optim.Optimizer:\n        if hasattr(model, 'module'):\n            model = model.module\n\n        optimizer_cfg = self.optimizer_cfg.copy()\n        # if no paramwise option is specified, just use the global setting\n        if not self.paramwise_cfg:\n            optimizer_cfg['params'] = model.parameters()\n            return OPTIMIZERS.build(optimizer_cfg)\n\n        # set param-wise lr and weight decay recursively\n        params: List = []\n        self.add_params(params, model)\n        optimizer_cfg['params'] = params\n\n        return OPTIMIZERS.build(optimizer_cfg)\n", "path": "mmengine/optim/optimizer/default_constructor.py"}], "after_files": [{"content": "# Copyright (c) OpenMMLab. All rights reserved.\nimport warnings\nfrom typing import List, Optional, Union\n\nimport torch\nimport torch.nn as nn\nfrom torch.nn import GroupNorm, LayerNorm\nfrom mmengine.mmengine.logging.logger import print_log\n\nfrom mmengine.registry import OPTIMIZER_CONSTRUCTORS, OPTIMIZERS\nfrom mmengine.utils import is_list_of, mmcv_full_available\nfrom mmengine.utils.parrots_wrapper import _BatchNorm, _InstanceNorm\n\n\n@OPTIMIZER_CONSTRUCTORS.register_module()\nclass DefaultOptimizerConstructor:\n    \"\"\"Default constructor for optimizers.\n\n    By default each parameter share the same optimizer settings, and we\n    provide an argument ``paramwise_cfg`` to specify parameter-wise settings.\n    It is a dict and may contain the following fields:\n\n    - ``custom_keys`` (dict): Specified parameters-wise settings by keys. If\n      one of the keys in ``custom_keys`` is a substring of the name of one\n      parameter, then the setting of the parameter will be specified by\n      ``custom_keys[key]`` and other setting like ``bias_lr_mult`` etc. will\n      be ignored. It should be noted that the aforementioned ``key`` is the\n      longest key that is a substring of the name of the parameter. If there\n      are multiple matched keys with the same length, then the key with lower\n      alphabet order will be chosen.\n      ``custom_keys[key]`` should be a dict and may contain fields ``lr_mult``\n      and ``decay_mult``. See Example 2 below.\n    - ``bias_lr_mult`` (float): It will be multiplied to the learning\n      rate for all bias parameters (except for those in normalization\n      layers and offset layers of DCN).\n    - ``bias_decay_mult`` (float): It will be multiplied to the weight\n      decay for all bias parameters (except for those in\n      normalization layers, depthwise conv layers, offset layers of DCN).\n    - ``norm_decay_mult`` (float): It will be multiplied to the weight\n      decay for all weight and bias parameters of normalization\n      layers.\n    - ``dwconv_decay_mult`` (float): It will be multiplied to the weight\n      decay for all weight and bias parameters of depthwise conv\n      layers.\n    - ``dcn_offset_lr_mult`` (float): It will be multiplied to the learning\n      rate for parameters of offset layer in the deformable convs\n      of a model.\n    - ``bypass_duplicate`` (bool): If true, the duplicate parameters\n      would not be added into optimizer. Default: False.\n\n    Note:\n\n        1. If the option ``dcn_offset_lr_mult`` is used, the constructor will\n        override the effect of ``bias_lr_mult`` in the bias of offset layer.\n        So be careful when using both ``bias_lr_mult`` and\n        ``dcn_offset_lr_mult``. If you wish to apply both of them to the offset\n        layer in deformable convs, set ``dcn_offset_lr_mult`` to the original\n        ``dcn_offset_lr_mult`` * ``bias_lr_mult``.\n\n        2. If the option ``dcn_offset_lr_mult`` is used, the constructor will\n        apply it to all the DCN layers in the model. So be careful when the\n        model contains multiple DCN layers in places other than backbone.\n\n    Args:\n        optimizer_cfg (dict): The config dict of the optimizer.\n            Positional fields are\n\n                - `type`: class name of the optimizer.\n\n            Optional fields are\n\n                - any arguments of the corresponding optimizer type, e.g.,\n                  lr, weight_decay, momentum, etc.\n        paramwise_cfg (dict, optional): Parameter-wise options.\n\n    Example 1:\n        >>> model = torch.nn.modules.Conv1d(1, 1, 1)\n        >>> optimizer_cfg = dict(type='SGD', lr=0.01, momentum=0.9,\n        >>>                      weight_decay=0.0001)\n        >>> paramwise_cfg = dict(norm_decay_mult=0.)\n        >>> optim_builder = DefaultOptimizerConstructor(\n        >>>     optimizer_cfg, paramwise_cfg)\n        >>> optimizer = optim_builder(model)\n\n    Example 2:\n        >>> # assume model have attribute model.backbone and model.cls_head\n        >>> optimizer_cfg = dict(type='SGD', lr=0.01, weight_decay=0.95)\n        >>> paramwise_cfg = dict(custom_keys={\n                '.backbone': dict(lr_mult=0.1, decay_mult=0.9)})\n        >>> optim_builder = DefaultOptimizerConstructor(\n        >>>     optimizer_cfg, paramwise_cfg)\n        >>> optimizer = optim_builder(model)\n        >>> # Then the `lr` and `weight_decay` for model.backbone is\n        >>> # (0.01 * 0.1, 0.95 * 0.9). `lr` and `weight_decay` for\n        >>> # model.cls_head is (0.01, 0.95).\n    \"\"\"\n\n    def __init__(self,\n                 optimizer_cfg: dict,\n                 paramwise_cfg: Optional[dict] = None):\n        if not isinstance(optimizer_cfg, dict):\n            raise TypeError('optimizer_cfg should be a dict',\n                            f'but got {type(optimizer_cfg)}')\n        self.optimizer_cfg = optimizer_cfg\n        self.paramwise_cfg = {} if paramwise_cfg is None else paramwise_cfg\n        self.base_lr = optimizer_cfg.get('lr', None)\n        self.base_wd = optimizer_cfg.get('weight_decay', None)\n        self._validate_cfg()\n\n    def _validate_cfg(self) -> None:\n        \"\"\"verify the correctness of the config.\"\"\"\n        if not isinstance(self.paramwise_cfg, dict):\n            raise TypeError('paramwise_cfg should be None or a dict, '\n                            f'but got {type(self.paramwise_cfg)}')\n\n        if 'custom_keys' in self.paramwise_cfg:\n            if not isinstance(self.paramwise_cfg['custom_keys'], dict):\n                raise TypeError(\n                    'If specified, custom_keys must be a dict, '\n                    f'but got {type(self.paramwise_cfg[\"custom_keys\"])}')\n            if self.base_wd is None:\n                for key in self.paramwise_cfg['custom_keys']:\n                    if 'decay_mult' in self.paramwise_cfg['custom_keys'][key]:\n                        raise ValueError('base_wd should not be None')\n\n        # get base lr and weight decay\n        # weight_decay must be explicitly specified if mult is specified\n        if ('bias_decay_mult' in self.paramwise_cfg\n                or 'norm_decay_mult' in self.paramwise_cfg\n                or 'dwconv_decay_mult' in self.paramwise_cfg):\n            if self.base_wd is None:\n                raise ValueError('base_wd should not be None')\n\n    def _is_in(self, param_group: dict, param_group_list: list) -> bool:\n        \"\"\"check whether the `param_group` is in the`param_group_list`\"\"\"\n        assert is_list_of(param_group_list, dict)\n        param = set(param_group['params'])\n        param_set = set()\n        for group in param_group_list:\n            param_set.update(set(group['params']))\n\n        return not param.isdisjoint(param_set)\n\n    def add_params(self,\n                   params: List[dict],\n                   module: nn.Module,\n                   prefix: str = '',\n                   is_dcn_module: Optional[Union[int, float]] = None) -> None:\n        \"\"\"Add all parameters of module to the params list.\n\n        The parameters of the given module will be added to the list of param\n        groups, with specific rules defined by paramwise_cfg.\n\n        Args:\n            params (list[dict]): A list of param groups, it will be modified\n                in place.\n            module (nn.Module): The module to be added.\n            prefix (str): The prefix of the module\n            is_dcn_module (int|float|None): If the current module is a\n                submodule of DCN, `is_dcn_module` will be passed to\n                control conv_offset layer's learning rate. Defaults to None.\n        \"\"\"\n        # get param-wise options\n        custom_keys = self.paramwise_cfg.get('custom_keys', {})\n        # first sort with alphabet order and then sort with reversed len of str\n        sorted_keys = sorted(sorted(custom_keys.keys()), key=len, reverse=True)\n\n        bias_lr_mult = self.paramwise_cfg.get('bias_lr_mult', 1.)\n        bias_decay_mult = self.paramwise_cfg.get('bias_decay_mult', 1.)\n        norm_decay_mult = self.paramwise_cfg.get('norm_decay_mult', 1.)\n        dwconv_decay_mult = self.paramwise_cfg.get('dwconv_decay_mult', 1.)\n        bypass_duplicate = self.paramwise_cfg.get('bypass_duplicate', False)\n        dcn_offset_lr_mult = self.paramwise_cfg.get('dcn_offset_lr_mult', 1.)\n\n        # special rules for norm layers and depth-wise conv layers\n        is_norm = isinstance(module,\n                             (_BatchNorm, _InstanceNorm, GroupNorm, LayerNorm))\n        is_dwconv = (\n            isinstance(module, torch.nn.Conv2d)\n            and module.in_channels == module.groups)\n\n        for name, param in module.named_parameters(recurse=False):\n            param_group = {'params': [param]}\n            if not param.requires_grad:\n                params.append(param_group)\n                continue\n            if bypass_duplicate and self._is_in(param_group, params):\n                warnings.warn(f'{prefix} is duplicate. It is skipped since '\n                              f'bypass_duplicate={bypass_duplicate}')\n                continue\n            # if the parameter match one of the custom keys, ignore other rules\n            is_custom = False\n            for key in sorted_keys:\n                if key in f'{prefix}.{name}':\n                    is_custom = True\n                    lr_mult = custom_keys[key].get('lr_mult', 1.)\n                    param_group['lr'] = self.base_lr * lr_mult\n                    if self.base_wd is not None:\n                        decay_mult = custom_keys[key].get('decay_mult', 1.)\n                        param_group['weight_decay'] = self.base_wd * decay_mult\n                    break\n\n            if not is_custom:\n                # bias_lr_mult affects all bias parameters\n                # except for norm.bias dcn.conv_offset.bias\n                if name == 'bias' and not (is_norm or is_dcn_module):\n                    param_group['lr'] = self.base_lr * bias_lr_mult\n\n                if (prefix.find('conv_offset') != -1 and is_dcn_module\n                        and isinstance(module, torch.nn.Conv2d)):\n                    # deal with both dcn_offset's bias & weight\n                    param_group['lr'] = self.base_lr * dcn_offset_lr_mult\n\n                # apply weight decay policies\n                if self.base_wd is not None:\n                    # norm decay\n                    if is_norm:\n                        param_group[\n                            'weight_decay'] = self.base_wd * norm_decay_mult\n                    # depth-wise conv\n                    elif is_dwconv:\n                        param_group[\n                            'weight_decay'] = self.base_wd * dwconv_decay_mult\n                    # bias lr and decay\n                    elif name == 'bias' and not is_dcn_module:\n                        # TODO: current bias_decay_mult will have affect on DCN\n                        param_group[\n                            'weight_decay'] = self.base_wd * bias_decay_mult\n            params.append(param_group)\n            for key, value in param_group.items():\n                if key == 'params':\n                    continue\n                full_name = f'{prefix}.{name}' if prefix else name\n                print_log(\n                    f'paramwise_options -- {full_name}:{key}={value}',\n                    logger='current')\n\n        if mmcv_full_available():\n            from mmcv.ops import DeformConv2d, ModulatedDeformConv2d\n            is_dcn_module = isinstance(module,\n                                       (DeformConv2d, ModulatedDeformConv2d))\n        else:\n            is_dcn_module = False\n        for child_name, child_mod in module.named_children():\n            child_prefix = f'{prefix}.{child_name}' if prefix else child_name\n            self.add_params(\n                params,\n                child_mod,\n                prefix=child_prefix,\n                is_dcn_module=is_dcn_module)\n\n    def __call__(self, model: nn.Module) -> torch.optim.Optimizer:\n        if hasattr(model, 'module'):\n            model = model.module\n\n        optimizer_cfg = self.optimizer_cfg.copy()\n        # if no paramwise option is specified, just use the global setting\n        if not self.paramwise_cfg:\n            optimizer_cfg['params'] = model.parameters()\n            return OPTIMIZERS.build(optimizer_cfg)\n\n        # set param-wise lr and weight decay recursively\n        params: List = []\n        self.add_params(params, model)\n        optimizer_cfg['params'] = params\n\n        return OPTIMIZERS.build(optimizer_cfg)\n", "path": "mmengine/optim/optimizer/default_constructor.py"}]}