| 193 | |
| 194 | |
| 195 | class CosineWeightDecayScheduler(LRScheduler): |
| 196 | def __init__( |
| 197 | self, |
| 198 | optimizer, |
| 199 | max_iters: int, |
| 200 | initial_wd: float = 0.05, |
| 201 | final_wd: float = 0.20, |
| 202 | last_epoch: int = -1, |
| 203 | ): |
| 204 | """ |
| 205 | 对 weight_decay 进行余弦“增加”调度,从 initial_wd -> final_wd。 |
| 206 | |
| 207 | 参数: |
| 208 | - optimizer: 任何带有 'weight_decay' param_group 的 optimizer |
| 209 | - max_iters: 总的调度步数 |
| 210 | - initial_wd: 第 0 步时的 weight_decay |
| 211 | - final_wd: 第 max_iters 步时的 weight_decay |
| 212 | - last_epoch: 如需从中途恢复训练,传入上次迭代 idx |
| 213 | """ |
| 214 | self.max_iters = max_iters |
| 215 | self.initial_wd = initial_wd |
| 216 | self.final_wd = final_wd |
| 217 | super().__init__(optimizer, last_epoch) |
| 218 | |
| 219 | def get_lr(self): |
| 220 | step = self._step_count |
| 221 | # 限制在 [0, max_iters] |
| 222 | if step <= 0: |
| 223 | factor = 0.0 |
| 224 | elif step >= self.max_iters: |
| 225 | factor = 1.0 |
| 226 | else: |
| 227 | # factor 从 0 -> 1,按 1 - cos(pi * t / T) / 2 |
| 228 | factor = 0.5 * (1 - math.cos(math.pi * step / self.max_iters)) |
| 229 | |
| 230 | wd = self.initial_wd + factor * (self.final_wd - self.initial_wd) |
| 231 | return [wd for _ in self.optimizer.param_groups] |
| 232 | |
| 233 | def step(self, epoch=None): |
| 234 | # 先让父类更新 last_epoch |
| 235 | self._step_count += 1 |
| 236 | # super().step(epoch) |
| 237 | # 再把新的 weight_decay 写到 optimizer |
| 238 | new_wd = self.get_lr() |
| 239 | for group, wd in zip(self.optimizer.param_groups, new_wd): |
| 240 | group['weight_decay'] = wd |
nothing calls this directly
no outgoing calls
no test coverage detected