|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| import torch
|
|
|
|
|
| class EMAWrapper(object):
|
| """A wrapper class for exponential moving average of model weights."""
|
|
|
| def __init__(
|
| self, model: torch.nn.Module, decay: float = 0.999, mutable_param_keywords=None
|
| ):
|
| """
|
| model: a pytorch model to apply EMA
|
| decay: a scaler to indicate the decay rate
|
| mutable_param_keywords: keywords of parameters to apply EMA decay, other params will stay untouched
|
| """
|
| self.model = model
|
| self.decay = decay
|
| self.mutable_param_keywords = [
|
| s.strip() for s in mutable_param_keywords if s.strip()
|
| ]
|
| self.shadow = {}
|
| self.backup = {}
|
|
|
| def register(self):
|
| for name, param in self.model.named_parameters():
|
| self.shadow[name] = param.data.clone()
|
|
|
| def update(self):
|
| for name, param in self.model.named_parameters():
|
| if self.mutable_param_keywords and not any(
|
| [keyword in name for keyword in self.mutable_param_keywords]
|
| ):
|
| continue
|
| assert name in self.shadow
|
| new_average = (1.0 - self.decay) * param.data + self.decay * self.shadow[
|
| name
|
| ]
|
| self.shadow[name] = new_average.clone()
|
|
|
| def apply_shadow(self):
|
| for name, param in self.model.named_parameters():
|
| assert name in self.shadow
|
| self.backup[name] = param.data
|
| param.data = self.shadow[name]
|
|
|
| def restore(self):
|
| for name, param in self.model.named_parameters():
|
| assert name in self.backup
|
| param.data = self.backup[name]
|
| self.backup = {}
|
|
|