Download code/optimizer/normalized_sgd.py from yuxing6/optimizer-model-consistency-pretrained: direct link, hf CLI and curl.
- Browser
- Download file 3.08 kB
-
https://huggingface.co/yuxing6/optimizer-model-consistency-pretrained/resolve/main/code/optimizer/normalized_sgd.py
- Command line
-
hf download hf://yuxing6/optimizer-model-consistency-pretrained/code/optimizer/normalized_sgd.py
-
curl -L -o normalized_sgd.py https://huggingface.co/yuxing6/optimizer-model-consistency-pretrained/resolve/main/code/optimizer/normalized_sgd.py
3.08 kB
| """ | |
| Implementation of normalized SGD algorithm. We additionally apply 0.2 * \sqrt{mn} to align the RMS norm update with Adam. | |
| """ | |
| import torch | |
| import math | |
| class NormalizedSGD(torch.optim.Optimizer): | |
| """ | |
| Implements a normalized version of Stochastic Gradient Descent (with momentum). | |
| The update for each parameter is normalized by its Frobenius norm before | |
| being applied. This is a form of layer-wise adaptivity. | |
| """ | |
| def __init__(self, params, lr=1e-3, momentum=0.9, weight_decay=0.1, scale=0.2, eps=1e-12): | |
| # scale is used for aligning the update RMS with Adam | |
| if lr < 0.0: | |
| raise ValueError(f"Invalid learning rate: {lr}") | |
| if momentum < 0.0: | |
| raise ValueError(f"Invalid momentum value: {momentum}") | |
| if weight_decay < 0.0: | |
| raise ValueError(f"Invalid weight_decay value: {weight_decay}") | |
| defaults = dict(lr=lr, momentum=momentum, weight_decay=weight_decay, scale=scale, eps=eps) | |
| super(NormalizedSGD, self).__init__(params, defaults) | |
| def __setstate__(self, state): | |
| super(NormalizedSGD, self).__setstate__(state) | |
| def step(self, closure=None): | |
| """Performs a single optimization step.""" | |
| loss = None | |
| if closure is not None: | |
| with torch.enable_grad(): | |
| loss = closure() | |
| for group in self.param_groups: | |
| lr = group['lr'] | |
| momentum = group['momentum'] | |
| weight_decay = group['weight_decay'] | |
| eps = group['eps'] | |
| scale = group['scale'] | |
| for p in group['params']: | |
| if p.grad is None: | |
| continue | |
| # Get the gradient | |
| d_p = p.grad | |
| # Apply momentum | |
| if momentum != 0: | |
| param_state = self.state[p] | |
| if 'momentum_buffer' not in param_state: | |
| buf = param_state['momentum_buffer'] = torch.clone(d_p).detach() | |
| else: | |
| buf = param_state['momentum_buffer'] | |
| buf.mul_(momentum).add_(d_p, alpha=1-momentum) # m_t = beta * m_{t-1} + (1-beta) * g_t | |
| # This is the update tensor (m_t) | |
| update_vec = buf | |
| else: | |
| # If no momentum, the gradient is the update tensor | |
| update_vec = d_p | |
| # +++ CORE MODIFICATION: Normalize the update vector +++ | |
| # Calculate the Frobenius norm of the update vector | |
| norm = torch.linalg.norm(update_vec) | |
| # Apply weight decay | |
| if weight_decay > 0.0: | |
| p.mul_(1.0 - lr * weight_decay) | |
| # Normalize and apply the update | |
| # p_new = p_old - lr * (m_t / ||m_t||_F) | |
| scale_align = scale * math.sqrt(p.numel()) | |
| p.add_(update_vec, alpha=-lr * scale_align / (norm + eps)) | |
| return loss |