Download training/train/efficiency.py from SinhalaMMLU-SharedTask/team-nexus: direct link, hf CLI and curl.
- Browser
- Download file 3.43 kB
-
https://huggingface.co/SinhalaMMLU-SharedTask/team-nexus/resolve/main/training/train/efficiency.py
- Command line
-
hf download hf://SinhalaMMLU-SharedTask/team-nexus/training/train/efficiency.py
-
curl -L -o efficiency.py https://huggingface.co/SinhalaMMLU-SharedTask/team-nexus/resolve/main/training/train/efficiency.py
3.43 kB
| """Training speed/memory options shared by the benchmark and the training scripts. | |
| loss="hf" transformers' built-in loss: materialises the full [tokens x vocab] logits (Gemma: 262k vocab) | |
| loss="chunked" plain-PyTorch chunked cross-entropy; each chunk's logits are recomputed in backward | |
| loss="liger" Liger fused linear + cross-entropy Triton kernel (never materialises the logits) | |
| ckpt_every=N recompute activations of every Nth decoder layer only (1 = all layers, 0 = none) | |
| compile=True torch.compile each decoder layer (regional compilation) | |
| """ | |
| from __future__ import annotations | |
| import torch | |
| import torch.nn.functional as F | |
| from torch.utils.checkpoint import checkpoint | |
| def lm_parts(model): | |
| """(decoder body, lm_head, final logit softcap) for plain and PEFT-wrapped causal LMs.""" | |
| lm = model.get_base_model() if hasattr(model, "get_base_model") else model | |
| return lm.model, lm.lm_head, getattr(lm.config, "final_logit_softcapping", None) | |
| def _ce_chunk(h, w, y, softcap): | |
| logits = (h @ w.t()).float() | |
| if softcap: | |
| logits = torch.tanh(logits / softcap) * softcap | |
| return F.cross_entropy(logits, y, ignore_index=-100, reduction="sum") | |
| def chunked_ce(h, w, y, softcap, chunk: int = 4096): | |
| total = h.new_zeros((), dtype=torch.float32) | |
| for i in range(0, h.shape[0], chunk): | |
| total = total + checkpoint(_ce_chunk, h[i:i + chunk], w, y[i:i + chunk], softcap, use_reentrant=False) | |
| return total / (y != -100).sum().clamp(min=1) | |
| _liger = {} | |
| def lm_loss(model, input_ids, labels, loss: str = "hf", attention_mask=None): | |
| """Next-token cross-entropy, mean over non-ignored target tokens. All three variants give the same value.""" | |
| if loss == "hf": | |
| return model(input_ids=input_ids, attention_mask=attention_mask, labels=labels).loss | |
| body, head, softcap = lm_parts(model) | |
| h = body(input_ids=input_ids, attention_mask=attention_mask).last_hidden_state | |
| h = h[:, :-1].reshape(-1, h.shape[-1]) | |
| y = labels[:, 1:].reshape(-1) | |
| if loss == "chunked": | |
| return chunked_ce(h, head.weight, y, softcap) | |
| if loss == "liger": | |
| from liger_kernel.transformers import LigerFusedLinearCrossEntropyLoss | |
| fn = _liger.setdefault(softcap, LigerFusedLinearCrossEntropyLoss(softcap=softcap)) | |
| return fn(head.weight, h, y) | |
| raise ValueError(loss) | |
| def configure(model, ckpt_every: int = 1, compile_layers: bool = False) -> None: | |
| body = lm_parts(model)[0] | |
| if ckpt_every > 0: | |
| model.gradient_checkpointing_enable(gradient_checkpointing_kwargs={"use_reentrant": False}) | |
| for i, layer in enumerate(body.layers): | |
| layer.gradient_checkpointing = i % ckpt_every == 0 | |
| else: | |
| model.gradient_checkpointing_disable() | |
| if compile_layers: | |
| # Layers differ (sliding vs global attention, linear-attention blocks), so dynamo compiles one graph per | |
| # layer variant; past the default limit of 8 it silently falls back to eager. The limit is passed per call: | |
| # the global config value was not honoured in the 11 Oct rerun. dynamic=False keeps one static graph per | |
| # shape, so activation recomputation cannot pick a different (dynamic) graph than the forward pass used | |
| # (pytorch/pytorch#166926). | |
| limit = max(64, 4 * len(body.layers)) | |
| for layer in body.layers: | |
| layer.compile(dynamic=False, recompile_limit=limit) | |