| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| from __future__ import absolute_import |
| from __future__ import division |
| from __future__ import print_function |
| from __future__ import unicode_literals |
| import copy |
| import math |
| import paddle |
|
|
| __all__ = ["build_optimizer"] |
|
|
|
|
| class CosineWeightDecayScheduler(object): |
| """Cosine-anneal the optimizer's weight decay each step. |
| |
| wd(t) = end + 0.5 * (start - end) * (1 + cos(pi * t / T)) |
| |
| During warmup the coefficient is held at `start_factor`. |
| """ |
|
|
| def __init__( |
| self, optimizer, start_factor, end_factor, total_steps, warmup_steps=0 |
| ): |
| self.optimizer = optimizer |
| self.start_factor = start_factor |
| self.end_factor = end_factor |
| self.total_steps = total_steps |
| self.warmup_steps = warmup_steps |
| self._step = 0 |
|
|
| def step(self): |
| self._step += 1 |
| if self._step <= self.warmup_steps: |
| wd = self.start_factor |
| else: |
| progress = (self._step - self.warmup_steps) / max( |
| 1, self.total_steps - self.warmup_steps |
| ) |
| progress = min(progress, 1.0) |
| wd = self.end_factor + 0.5 * (self.start_factor - self.end_factor) * ( |
| 1 + math.cos(math.pi * progress) |
| ) |
| self.optimizer.regularization._coeff = wd |
|
|
| def get_wd(self): |
| return self.optimizer.regularization._coeff |
|
|
|
|
| def build_lr_scheduler(lr_config, epochs, step_each_epoch): |
| from . import learning_rate |
|
|
| lr_config.update({"epochs": epochs, "step_each_epoch": step_each_epoch}) |
| lr_name = lr_config.pop("name", "Const") |
| lr = getattr(learning_rate, lr_name)(**lr_config)() |
| return lr |
|
|
|
|
| def build_optimizer(config, epochs, step_each_epoch, model): |
| from . import regularizer, optimizer |
|
|
| config = copy.deepcopy(config) |
| |
| lr = build_lr_scheduler(config.pop("lr"), epochs, step_each_epoch) |
|
|
| |
| wd_scheduler = None |
| if "regularizer" in config and config["regularizer"] is not None: |
| reg_config = config.pop("regularizer") |
| reg_name = reg_config.pop("name") |
| if not hasattr(regularizer, reg_name): |
| reg_name += "Decay" |
| reg_obj = getattr(regularizer, reg_name)(**reg_config) |
| reg = reg_obj() |
|
|
| |
| if isinstance(reg_obj, regularizer.CosineL2Decay): |
| warmup_epoch = reg_obj.warmup_epoch |
| warmup_steps = round(warmup_epoch * step_each_epoch) |
| total_steps = step_each_epoch * epochs |
| wd_scheduler = { |
| "start_factor": reg_obj.start_factor, |
| "end_factor": reg_obj.end_factor, |
| "total_steps": total_steps, |
| "warmup_steps": warmup_steps, |
| } |
| elif "weight_decay" in config: |
| reg = config.pop("weight_decay") |
| else: |
| reg = None |
|
|
| |
| optim_name = config.pop("name") |
| if "clip_norm" in config: |
| clip_norm = config.pop("clip_norm") |
| grad_clip = paddle.nn.ClipGradByNorm(clip_norm=clip_norm) |
| elif "clip_norm_global" in config: |
| clip_norm = config.pop("clip_norm_global") |
| grad_clip = paddle.nn.ClipGradByGlobalNorm(clip_norm=clip_norm) |
| else: |
| grad_clip = None |
| optim = getattr(optimizer, optim_name)( |
| learning_rate=lr, weight_decay=reg, grad_clip=grad_clip, **config |
| ) |
| built_optim = optim(model) |
|
|
| |
| if wd_scheduler is not None: |
| wd_scheduler = CosineWeightDecayScheduler(built_optim, **wd_scheduler) |
|
|
| return built_optim, lr, wd_scheduler |
|
|