Download code/optimizer/activation_preconditioned_optimizer.py from yuxing6/optimizer-model-consistency-pretrained: direct link, hf CLI and curl.
- Browser
- Download file 5.11 kB
-
https://huggingface.co/yuxing6/optimizer-model-consistency-pretrained/resolve/main/code/optimizer/activation_preconditioned_optimizer.py
- Command line
-
hf download hf://yuxing6/optimizer-model-consistency-pretrained/code/optimizer/activation_preconditioned_optimizer.py
-
curl -L -o activation_preconditioned_optimizer.py https://huggingface.co/yuxing6/optimizer-model-consistency-pretrained/resolve/main/code/optimizer/activation_preconditioned_optimizer.py
5.11 kB
| # activation_preconditioned_optimizer.py | |
| import torch | |
| import math | |
| from torch.optim.optimizer import Optimizer | |
| class ActivationPreconditionedOptimizer(Optimizer): | |
| """ | |
| Implements an Activation-Preconditioned Optimizer with optional normalization, | |
| scaling, Nesterov momentum, and grafting, inspired by NormalizedSteepestDescent. | |
| """ | |
| def __init__(self, params, lr=1e-3, betas=(0.9, 0.95), weight_decay=0.1, | |
| scale=0.2, eps=1e-8, use_nesterov=False, use_grafting=False): | |
| if not 0.0 <= lr: | |
| raise ValueError(f"Invalid learning rate: {lr}") | |
| if not 0.0 <= betas[0] < 1.0: | |
| raise ValueError(f"Invalid beta1 parameter: {betas[0]}") | |
| if not 0.0 <= betas[1] < 1.0: | |
| raise ValueError(f"Invalid beta2 parameter: {betas[1]}") | |
| if not 0.0 <= weight_decay: | |
| raise ValueError(f"Invalid weight_decay value: {weight_decay}") | |
| defaults = dict(lr=lr, betas=betas, weight_decay=weight_decay, scale=scale, | |
| eps=eps, use_nesterov=use_nesterov, use_grafting=use_grafting) | |
| super(ActivationPreconditionedOptimizer, self).__init__(params, defaults) | |
| def step(self, closure=None): | |
| loss = None | |
| if closure is not None: | |
| with torch.enable_grad(): | |
| loss = closure() | |
| for group in self.param_groups: | |
| lr = group['lr'] | |
| beta1, beta2_precond = group['betas'] | |
| # For grafting, we use the same beta2 as Adam, which is typically betas[1] | |
| beta2_grafting = group['betas'][1] | |
| weight_decay = group['weight_decay'] | |
| eps = group['eps'] | |
| scale = group['scale'] | |
| use_nesterov = group['use_nesterov'] | |
| use_grafting = group['use_grafting'] | |
| for p in group['params']: | |
| if p.grad is None: | |
| continue | |
| if not hasattr(p, 'activation_second_moment'): | |
| continue | |
| grad = p.grad | |
| if grad.is_sparse: | |
| raise RuntimeError('This optimizer does not support sparse gradients.') | |
| state = self.state[p] | |
| # State initialization | |
| if len(state) == 0: | |
| state['step'] = 0 | |
| state['momentum_buffer'] = torch.zeros_like(p, memory_format=torch.preserve_format) | |
| state['preconditioner'] = torch.zeros((p.shape[1], p.shape[1]), device=p.device) | |
| if use_grafting: | |
| state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) | |
| momentum_buffer = state['momentum_buffer'] | |
| preconditioner = state['preconditioner'] | |
| state['step'] += 1 | |
| # --- Update momentum and preconditioner --- | |
| momentum_buffer.mul_(beta1).add_(grad, alpha=1 - beta1) | |
| xxt = p.activation_second_moment | |
| preconditioner.mul_(beta2_precond).add_(xxt, alpha=1 - beta2_precond) | |
| # --- Nesterov Momentum Logic --- | |
| if use_nesterov: | |
| Gt = torch.lerp(grad, momentum_buffer, beta1) | |
| else: | |
| Gt = momentum_buffer | |
| # --- Calculate and Normalize the Update Direction --- | |
| eps_I = torch.eye(preconditioner.size(0), device=preconditioner.device) * eps | |
| precond_inv = torch.linalg.inv(preconditioner + eps_I) | |
| print(f"Preconditioner shape: {preconditioner.shape}, Gt shape: {Gt.shape}") | |
| # update_direction = torch.matmul(precond_inv, Gt) | |
| update_direction = torch.matmul(Gt, precond_inv) | |
| update_norm = torch.linalg.norm(update_direction) | |
| update_direction.div_(update_norm + eps) | |
| # --- Calculate the Update Magnitude (alpha) --- | |
| alpha = 0.0 | |
| if use_grafting: | |
| exp_avg_sq = state['exp_avg_sq'] | |
| exp_avg_sq.mul_(beta2_grafting).addcmul_(grad, grad, value=1 - beta2_grafting) | |
| step = state['step'] | |
| bias_correction1 = 1 - beta1 ** step | |
| bias_correction2 = 1 - beta2_grafting ** step | |
| denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(eps) | |
| adam_update_magnitude = torch.linalg.norm((Gt / bias_correction1) / denom) | |
| alpha = -lr * adam_update_magnitude | |
| else: | |
| mn = p.numel() | |
| alpha = -lr * scale * math.sqrt(mn) | |
| # --- Apply Updates --- | |
| if weight_decay > 0.0: | |
| p.add_(p, alpha=-lr * weight_decay) | |
| p.add_(update_direction, alpha=alpha) | |
| delattr(p, 'activation_second_moment') | |
| return loss |