Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / optim / parameter_groups.py: 95%
56 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Parameter-name classification and optimizer parameter-group construction."""
17__all__ = [
18 "get_adamw_param_groups",
19 "get_parameter_names",
20 "split_muon_adamw_params",
21]
23import logging
24from typing import Any, Dict, List, Optional, Sequence, Tuple
26from torch import nn # pylint: disable=forbidden-backend-import
28logger = logging.getLogger(__name__)
30_DEFAULT_ADAMW_NAME_KEYWORDS: Tuple[str, ...] = (
31 "embed",
32 "lm_head",
33 "out_head",
34 "out_proj.bias",
35)
38def get_parameter_names(
39 model: nn.Module,
40 forbidden_param_names: Optional[Sequence[str]],
41) -> List[str]:
42 """Return canonical parameter names that do not match no-decay keywords.
44 Transparent module wrappers may expose different internal names through
45 ``named_children()`` while normalizing their public ``named_parameters()``
46 names. Deriving and consuming names from the same public traversal keeps
47 optimizer grouping stable when those wrappers are installed.
49 Args:
50 model: Model whose parameters should be classified.
51 forbidden_param_names: Case-insensitive keywords excluded from weight decay.
53 Returns:
54 Parameter names eligible for weight decay.
55 """
56 forbidden_names = tuple(name.lower() for name in forbidden_param_names or ())
57 return [
58 name
59 for name, _ in model.named_parameters()
60 if not any(forbidden in name.lower() for forbidden in forbidden_names)
61 ]
64def get_adamw_param_groups(
65 model: "nn.Module",
66 weight_decay: float = 1e-2,
67 no_decay_params: Optional[Sequence[str]] = None,
68 param_groups: Optional[Sequence[Dict[str, Any]]] = None,
69 allowed_param_ids: Optional[Sequence[int]] = None,
70 excluded_param_ids: Optional[Sequence[int]] = None,
71) -> Tuple[List[Dict[str, Any]], List[str]]:
72 """Split model parameters into decaying and non-decaying groups.
74 The function also adds ``model_name`` optimizer metadata to each selected
75 parameter.
77 Args:
78 model: Module whose trainable parameters are routed.
79 weight_decay: Default decay coefficient for trainable parameters.
80 no_decay_params: Name keywords excluded from weight decay.
81 param_groups: Optional prebuilt groups to return unchanged.
82 allowed_param_ids: Optional parameter identities eligible for routing.
84 Returns:
85 Parameter groups and names routed to AdamW.
86 """
87 adamw_names = []
88 no_decay_keywords = ("bias", "norm", "ln_") if no_decay_params is None else no_decay_params
89 no_decay_params = tuple(keyword.lower() for keyword in no_decay_keywords)
91 if param_groups is None:
92 decay_param_names = set(get_parameter_names(model, no_decay_params))
93 allowed_ids = set(allowed_param_ids) if allowed_param_ids is not None else None
94 excluded_ids = set(excluded_param_ids or ())
95 decay_parameters = []
96 no_decay_parameters = []
97 no_decay_parameter_names = []
98 for n, p in model.named_parameters():
99 if not p.requires_grad or id(p) in excluded_ids or (allowed_ids is not None and id(p) not in allowed_ids):
100 continue
101 setattr(p, "model_name", n)
102 adamw_names.append(n)
103 if n in decay_param_names:
104 decay_parameters.append(p)
105 else:
106 no_decay_parameter_names.append(n)
107 no_decay_parameters.append(p)
109 param_groups = []
110 if decay_parameters:
111 param_groups.append({"params": decay_parameters, "weight_decay": weight_decay})
112 if no_decay_parameters:
113 logger.info_rank0(f"Parameters without weight decay: {no_decay_parameter_names}")
114 param_groups.append({"params": no_decay_parameters, "weight_decay": 0.0})
116 return param_groups, adamw_names
119def split_muon_adamw_params(
120 model: nn.Module,
121 extra_adamw_name_keywords: Sequence[str] = (),
122 excluded_param_ids: Optional[Sequence[int]] = None,
123) -> Tuple[List[nn.Parameter], List[nn.Parameter], List[str], List[str]]:
124 """Route matrix parameters to Muon and remaining parameters to AdamW.
126 Args:
127 model: Module whose trainable parameters are routed.
128 extra_adamw_name_keywords: Additional names reserved for AdamW.
130 Returns:
131 Muon parameters, AdamW parameters, and their respective names.
132 """
133 adamw_keywords = []
134 for keyword in (*_DEFAULT_ADAMW_NAME_KEYWORDS, *extra_adamw_name_keywords):
135 adamw_keywords.append(keyword.lower())
136 adamw_keywords = tuple(adamw_keywords)
137 muon_params, adamw_params = [], []
138 muon_names, adamw_names = [], []
139 excluded_ids = set(excluded_param_ids or ())
141 for name, parameter in model.named_parameters():
142 setattr(parameter, "model_name", name)
143 if not parameter.requires_grad or id(parameter) in excluded_ids:
144 continue
146 is_matrix = parameter.ndim >= 2
147 is_adamw = any(keyword in name.lower() for keyword in adamw_keywords)
148 if is_matrix and not is_adamw:
149 muon_params.append(parameter)
150 muon_names.append(name)
151 else:
152 adamw_params.append(parameter)
153 adamw_names.append(name)
155 return muon_params, adamw_params, muon_names, adamw_names