Njap-png
Add Agron neural-network zoo, optimisers, algorithms, schedulers and unified trainer
a311e94 Download agron_nets/algorithms/stability.py from teddyoas/Agron: direct link, hf CLI and curl.
- Browser
- Download file 4.29 kB
-
https://huggingface.co/teddyoas/Agron/resolve/main/agron_nets/algorithms/stability.py
- Command line
-
hf download hf://teddyoas/Agron/agron_nets/algorithms/stability.py
-
curl -L -o stability.py https://huggingface.co/teddyoas/Agron/resolve/main/agron_nets/algorithms/stability.py
4.29 kB
| """Stability algorithms: clipping, accumulation, z-loss, noise, checkpointing.""" | |
| from __future__ import annotations | |
| import math | |
| from typing import Optional | |
| import torch | |
| from .base import AlgorithmContext, BaseAlgorithm, compose_loss | |
| class GradientClip(BaseAlgorithm): | |
| """Clip gradients by global norm (and optionally value).""" | |
| name = "gradient_clip" | |
| category = "stability" | |
| description = "Clips the global gradient norm before the optimiser step." | |
| def __init__(self, max_norm: float = 1.0, norm_type: float = 2.0, clip_values: float = 0.0): | |
| super().__init__(max_norm=max_norm, norm_type=norm_type, clip_values=clip_values) | |
| self.max_norm = max_norm | |
| self.norm_type = norm_type | |
| self.clip_values = clip_values | |
| def on_before_optimizer_step(self, ctx): | |
| params = [p for p in ctx.model.parameters() if p.grad is not None] | |
| if not params: | |
| return | |
| torch.nn.utils.clip_grad_norm_(params, self.max_norm, norm_type=self.norm_type) | |
| if self.clip_values > 0: | |
| torch.nn.utils.clip_grad_value_(params, self.clip_values) | |
| class GradientAccumulation(BaseAlgorithm): | |
| """Accumulate gradients over ``steps`` micro-batches before stepping. | |
| ``train_step`` performs the scaled backward pass; the engine consults | |
| :meth:`should_step` to decide whether to run ``optimizer.step()``. | |
| """ | |
| name = "gradient_accumulation" | |
| category = "stability" | |
| description = "Simulate larger batch sizes via gradient accumulation." | |
| def __init__(self, steps: int = 4): | |
| super().__init__(steps=steps) | |
| self.steps = max(1, steps) | |
| def train_step(self, ctx, batch): | |
| batch = self.on_step_begin(ctx, batch) | |
| outputs = ctx.model(**batch) | |
| loss = outputs["loss"] if isinstance(outputs, dict) else outputs.loss | |
| loss = self.compute_loss(ctx, batch, outputs, loss) | |
| loss = compose_loss(ctx, batch, outputs, loss, skip=self) | |
| if loss is not None: | |
| (loss / self.steps).backward() | |
| ctx.set("accum_step", (ctx.get("accum_step", 0) + 1) % self.steps) | |
| return loss | |
| def should_step(self, ctx) -> bool: | |
| return ctx.get("accum_step", 0) == 0 | |
| class ZLoss(BaseAlgorithm): | |
| """Auxiliary z-loss to keep the logits well-behaved (PaLM style).""" | |
| name = "z_loss" | |
| category = "stability" | |
| description = "Penalises large log-sum-exp values to stabilise logits." | |
| def __init__(self, weight: float = 1e-4): | |
| super().__init__(weight=weight) | |
| self.weight = weight | |
| def compute_loss(self, ctx, batch, outputs, loss): | |
| if loss is None: | |
| return None | |
| logits = outputs["logits"] if isinstance(outputs, dict) else outputs.logits | |
| z = logits.logsumexp(dim=-1).pow(2).mean() | |
| return loss + self.weight * z | |
| class GradientNoise(BaseAlgorithm): | |
| """Add calibrated Gaussian noise to gradients. | |
| Useful both as a differential-privacy mechanism and as an exploration | |
| regulariser for small models that overfit quickly. | |
| """ | |
| name = "gradient_noise" | |
| category = "stability" | |
| description = "Adds Gaussian noise to gradients (DP-style regularisation)." | |
| def __init__(self, sigma: float = 1e-3): | |
| super().__init__(sigma=sigma) | |
| self.sigma = sigma | |
| def on_before_optimizer_step(self, ctx): | |
| if self.sigma <= 0: | |
| return | |
| for p in ctx.model.parameters(): | |
| if p.grad is not None: | |
| p.grad.add_(torch.randn_like(p.grad) * self.sigma) | |
| class ActivationCheckpointing(BaseAlgorithm): | |
| """Enable gradient checkpointing on compatible models.""" | |
| name = "activation_checkpointing" | |
| category = "memory" | |
| description = "Trades compute for memory by recomputing activations." | |
| def on_train_begin(self, ctx): | |
| model = ctx.model | |
| if hasattr(model, "gradient_checkpointing_enable"): | |
| try: | |
| model.gradient_checkpointing_enable() | |
| except Exception: | |
| pass | |
| def on_train_end(self, ctx): | |
| model = ctx.model | |
| if hasattr(model, "gradient_checkpointing_disable"): | |
| try: | |
| model.gradient_checkpointing_disable() | |
| except Exception: | |
| pass | |