Download code/dense/temperature.py from fdemelo/jegue: direct link, hf CLI and curl.
- Browser
- Download file 2.57 kB
-
https://huggingface.co/fdemelo/jegue/resolve/main/code/dense/temperature.py
- Command line
-
hf download hf://fdemelo/jegue/code/dense/temperature.py
-
curl -L -o temperature.py https://huggingface.co/fdemelo/jegue/resolve/main/code/dense/temperature.py
2.57 kB
| """Calibration head used at inference (temperature as a function of the logits and the pooled answer-slot state).""" | |
| import math | |
| from typing import Optional | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| LO, HI = math.log(0.5), math.log(5.0) | |
| MODES = {"yesno": 0, "digits": 1, "letters": 2, "parallel": 3} | |
| N_FEAT = 3 + 4 + 5 | |
| # ------------------------------------------------------------------ features ----------------------------------------------------------- | |
| def make_features(logits: torch.Tensor, mask: torch.Tensor, qtype: torch.Tensor, mode: torch.Tensor) -> torch.Tensor: | |
| """(N, Kmax) padded logits -> (N, N_FEAT) features that do not depend on which option is which.""" | |
| z = logits.masked_fill(~mask, -1e4) | |
| k = mask.sum(-1).clamp(min=2).float() | |
| logp = torch.log_softmax(z, -1) | |
| p = logp.exp() | |
| ent = -(p * logp).sum(-1) / torch.log(k) | |
| top = z.topk(2, -1).values | |
| mean = (logits * mask).sum(-1) / k | |
| std = (((logits - mean[:, None]) ** 2 * mask).sum(-1) / k).sqrt() | |
| return torch.cat([F.one_hot(qtype, 3).float(), F.one_hot(mode, 4).float(), torch.stack([torch.log(k) / 5, ent, p.max(-1).values, (top[:, 0] - top[:, 1]) / 10, std / 10], -1)], -1) | |
| class SwiGLU(nn.Module): | |
| def __init__(self, d_in: int, d_hid: int, d_out: int): | |
| super().__init__() | |
| self.gate, self.up, self.down = nn.Linear(d_in, d_hid), nn.Linear(d_in, d_hid), nn.Linear(d_hid, d_out) | |
| def forward(self, x): | |
| return self.down(F.silu(self.gate(x)) * self.up(x)) | |
| class TempHead(nn.Module): | |
| """log T = LO + (HI - LO) * sigmoid(raw + c) with c chosen so that raw = 0 gives T = 1; the last layer starts at zero (T = 1).""" | |
| def __init__(self, n_feat: int = N_FEAT, hidden: Optional[int] = None, d: int = 128): | |
| super().__init__() | |
| self.hidden_dim = hidden | |
| self.proj = nn.Sequential(nn.LayerNorm(hidden), nn.Linear(hidden, d)) if hidden else None | |
| self.ffn = SwiGLU(n_feat + (d if hidden else 0), 2 * d, 1) | |
| nn.init.zeros_(self.ffn.down.weight); nn.init.zeros_(self.ffn.down.bias) | |
| self.register_buffer("c", torch.tensor(math.log((0 - LO) / (HI - 0)))) | |
| def log_t(self, feats: torch.Tensor, pooled: Optional[torch.Tensor] = None) -> torch.Tensor: | |
| x = feats if self.proj is None else torch.cat([feats, self.proj(pooled)], -1) | |
| return LO + (HI - LO) * torch.sigmoid(self.ffn(x).squeeze(-1) + self.c) | |
| # ------------------------------------------------------------------ cache -------------------------------------------------------------- | |