Instructions to use CyanMonkey/Test-Subject-3 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use CyanMonkey/Test-Subject-3 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="CyanMonkey/Test-Subject-3")# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("CyanMonkey/Test-Subject-3", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use CyanMonkey/Test-Subject-3 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "CyanMonkey/Test-Subject-3" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "CyanMonkey/Test-Subject-3", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/CyanMonkey/Test-Subject-3
- SGLang
How to use CyanMonkey/Test-Subject-3 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "CyanMonkey/Test-Subject-3" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "CyanMonkey/Test-Subject-3", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "CyanMonkey/Test-Subject-3" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "CyanMonkey/Test-Subject-3", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use CyanMonkey/Test-Subject-3 with Docker Model Runner:
docker model run hf.co/CyanMonkey/Test-Subject-3
Download modeling_oleander.py from CyanMonkey/Test-Subject-3: direct link, hf CLI and curl.
- Browser
- Download file 19.3 kB
-
https://huggingface.co/CyanMonkey/Test-Subject-3/resolve/main/modeling_oleander.py
- Command line
-
hf download hf://CyanMonkey/Test-Subject-3/modeling_oleander.py
-
curl -L -o modeling_oleander.py https://huggingface.co/CyanMonkey/Test-Subject-3/resolve/main/modeling_oleander.py
19.3 kB
| # coding=utf-8 | |
| # Modeling file for Oleander (hybrid GDN2 / gated-GQA causal LM). | |
| # Auto-generated by the Oleander training notebook. The arithmetic mirrors the trainer exactly (same parameter names, | |
| # same reference path), so the checkpoints in this repository load with | |
| # | |
| # AutoModelForCausalLM.from_pretrained(repo, trust_remote_code=True) | |
| # | |
| # Kernel policy - both paths implement the same math: | |
| # * GDN2 -> flash-linear-attention `chunk_gdn2` when installed AND running on CUDA in bf16/fp16; | |
| # otherwise a token-by-token recurrent reference (exact, but slow for long prompts). | |
| # * GQA -> torch.nn.functional.scaled_dot_product_attention (no KV cache: this repo ships `use_cache=False`). | |
| # * norm -> F.rms_norm when the installed torch has it. | |
| # Set OLEANDER_REFERENCE_KERNELS=1 to force the reference path (handy when diffing against the trainer). | |
| from __future__ import annotations | |
| import os | |
| from typing import Optional | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from transformers import PreTrainedModel | |
| from transformers.modeling_outputs import CausalLMOutputWithPast | |
| try: # loaded as remote code through config.json -> auto_map | |
| from .configuration_oleander import OleanderConfig | |
| except ImportError: # loaded as a plain module (a script, or the trainer's selftest) | |
| from configuration_oleander import OleanderConfig | |
| _REF_ONLY = os.environ.get("OLEANDER_REFERENCE_KERNELS", "0") == "1" | |
| try: | |
| from fla.ops.gdn2 import chunk_gdn2 as _chunk_gdn2 | |
| _HAS_FLA = not _REF_ONLY | |
| except Exception: | |
| _chunk_gdn2 = None | |
| _HAS_FLA = False | |
| _HAS_FUSED_RMS = hasattr(F, "rms_norm") | |
| def _rms(x, w, eps): | |
| if _HAS_FUSED_RMS: | |
| return F.rms_norm(x, (x.shape[-1],), w, eps) | |
| xf = x.float() | |
| y = xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps) | |
| if w is not None: | |
| y = y * w.float() | |
| return y.to(x.dtype) | |
| class RMSNorm(nn.Module): | |
| def __init__(self, d, eps): | |
| super().__init__() | |
| self.weight = nn.Parameter(torch.ones(d)) | |
| self.eps = eps | |
| def forward(self, x): | |
| return _rms(x, self.weight, self.eps) | |
| class OffsetRMSNorm(nn.Module): | |
| # QK-norm in offset form: scale = 1 + w, w initialised at zero (same as the trainer). | |
| def __init__(self, d, eps): | |
| super().__init__() | |
| self.weight = nn.Parameter(torch.zeros(d)) | |
| self.eps = eps | |
| def forward(self, x): | |
| return _rms(x, None, self.eps) * (1.0 + self.weight).to(x.dtype) | |
| class GatedRMSNorm(nn.Module): | |
| # FLA FusedRMSNormGated(activation="sigmoid") semantics: rmsnorm(x) * w * sigmoid(g). | |
| def __init__(self, d, eps): | |
| super().__init__() | |
| self.weight = nn.Parameter(torch.ones(d)) | |
| self.eps = eps | |
| def forward(self, x, g): | |
| xf = x.float() | |
| y = xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + self.eps) * self.weight.float() | |
| return (y * torch.sigmoid(g.float())).to(x.dtype) | |
| class SwiGLU(nn.Module): | |
| def __init__(self, d, ff): | |
| super().__init__() | |
| self.gate_proj = nn.Linear(d, ff, bias=False) | |
| self.up_proj = nn.Linear(d, ff, bias=False) | |
| self.down_proj = nn.Linear(ff, d, bias=False) | |
| def forward(self, x): | |
| return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x)) | |
| class ResConsumer(nn.Module): | |
| # Learned query + RMS-norm scale for one Block-Attention-Residuals read point. | |
| def __init__(self, d): | |
| super().__init__() | |
| self.query = nn.Parameter(torch.zeros(d)) | |
| self.norm_w = nn.Parameter(torch.ones(d)) | |
| def attnres_mix(query, norm_w, eps, *srcs): | |
| # softmax over sources of <rmsnorm(src) * norm_w, query>, weighted sum of the RAW sources (fp32). | |
| V = torch.stack(srcs, 0).float() | |
| qeff = (query * norm_w).float() | |
| r = torch.rsqrt(V.pow(2).mean(-1, keepdim=True) + eps) | |
| a = torch.softmax(((V * r) * qeff).sum(-1), dim=0) | |
| return (a.unsqueeze(-1) * V).sum(0) | |
| def build_rope(max_len, rot_dim, theta): | |
| inv = 1.0 / (theta ** (torch.arange(0, rot_dim, 2, dtype=torch.float32) / rot_dim)) | |
| f = torch.outer(torch.arange(max_len, dtype=torch.float32), inv) | |
| return f.cos(), f.sin() | |
| def apply_rope(x, cos, sin): | |
| # Partial RoPE on the first 2*cos.shape[-1] dims of x [B,T,H,hd]. | |
| T = x.shape[1] | |
| r = cos.shape[-1] * 2 | |
| c = cos[:T].to(x.dtype)[None, :, None, :] | |
| s = sin[:T].to(x.dtype)[None, :, None, :] | |
| x1, x2, xp = x[..., : r // 2], x[..., r // 2: r], x[..., r:] | |
| return torch.cat([x1 * c - x2 * s, x2 * c + x1 * s, xp], dim=-1) | |
| def l2norm(x, eps=1e-6): | |
| xf = x.float() | |
| return (xf * torch.rsqrt(xf.pow(2).sum(-1, keepdim=True) + eps)).to(x.dtype) | |
| def causal_conv(x, weight): | |
| # Depthwise causal conv (+SiLU). x [B,T,C]; weight [C,1,K] (nn.Conv1d) or [C,K]. | |
| T = x.shape[1] | |
| w = (weight[:, 0, :] if weight.dim() == 3 else weight).to(x.dtype) | |
| K = w.shape[-1] | |
| out = torch.zeros_like(x) | |
| for j in range(K): | |
| s = K - 1 - j | |
| xs = F.pad(x, (0, 0, s, 0))[:, :T] if s > 0 else x | |
| out = out + xs * w[:, j] | |
| return F.silu(out) | |
| def gdn2_recurrent(q, k, v, g, b, w): | |
| # Token-by-token GDN2 reference (same arithmetic as fla.ops.gdn2.naive and the trainer). | |
| # q,k [B,T,H,K] (l2-normalised) | v,w [B,T,H,V] | g,b [B,T,H,K]. | |
| B, T, H, K = k.shape | |
| V = v.shape[-1] | |
| qf, kf, vf, gf, bf, wf = (x.float() for x in (q, k, v, g, b, w)) | |
| qf = qf * (K ** -0.5) | |
| S = torch.zeros(B, H, K, V, dtype=torch.float32, device=k.device) | |
| outs = [] | |
| for t in range(T): | |
| S = S * gf[:, t].exp().unsqueeze(-1) | |
| erase = ((bf[:, t] * kf[:, t]).unsqueeze(-1) * S).sum(-2) | |
| S = S + kf[:, t].unsqueeze(-1) * (wf[:, t] * vf[:, t] - erase).unsqueeze(-2) | |
| outs.append((qf[:, t].unsqueeze(-1) * S).sum(-2)) | |
| return torch.stack(outs, 1).to(v.dtype) | |
| class GDN2Mixer(nn.Module): | |
| def __init__(self, d, cfg): | |
| super().__init__() | |
| self.H = int(cfg["heads"]) | |
| self.hd = int(cfg["head_dim"]) | |
| self.K = self.Vd = self.H * self.hd | |
| self.norm_eps = float(cfg.get("norm_eps", 1e-5)) | |
| self.allow_neg = bool(cfg.get("allow_neg_eigval", False)) | |
| self.gate_in_kernel = bool(cfg.get("gate_in_kernel", False)) | |
| conv = int(cfg.get("conv_size", 4)) | |
| K = self.K | |
| self.q_proj = nn.Linear(d, K, bias=False) | |
| self.k_proj = nn.Linear(d, K, bias=False) | |
| self.v_proj = nn.Linear(d, self.Vd, bias=False) | |
| self.q_conv1d = nn.Conv1d(K, K, conv, groups=K, padding=conv - 1, bias=False) | |
| self.k_conv1d = nn.Conv1d(K, K, conv, groups=K, padding=conv - 1, bias=False) | |
| self.v_conv1d = nn.Conv1d(self.Vd, self.Vd, conv, groups=self.Vd, padding=conv - 1, bias=False) | |
| self.f_proj = nn.Sequential(nn.Linear(d, self.hd, bias=False), nn.Linear(self.hd, K, bias=False)) | |
| self.b_proj = nn.Linear(d, K, bias=False) | |
| self.w_proj = nn.Linear(d, self.Vd, bias=False) | |
| self.A_log = nn.Parameter(torch.zeros(self.H)) | |
| self.dt_bias = nn.Parameter(torch.zeros(K)) | |
| self.g_proj = nn.Sequential(nn.Linear(d, self.hd, bias=False), nn.Linear(self.hd, self.Vd, bias=True)) | |
| self.o_norm = GatedRMSNorm(self.hd, self.norm_eps) | |
| self.o_proj = nn.Linear(self.Vd, d, bias=False) | |
| def forward(self, x): | |
| B, T, _ = x.shape | |
| H, hd = self.H, self.hd | |
| q, k, v = self.q_proj(x), self.k_proj(x), self.v_proj(x) | |
| f = self.f_proj(x) | |
| gate = self.g_proj(x) | |
| b = torch.sigmoid(self.b_proj(x)) | |
| w = torch.sigmoid(self.w_proj(x)) | |
| fast = _HAS_FLA and x.is_cuda and x.dtype in (torch.bfloat16, torch.float16) | |
| if fast: | |
| q = causal_conv(q, self.q_conv1d.weight).view(B, T, H, hd) | |
| k = causal_conv(k, self.k_conv1d.weight).view(B, T, H, hd) | |
| v = causal_conv(v, self.v_conv1d.weight).view(B, T, H, hd) | |
| bb = b.view(B, T, H, hd) | |
| if self.allow_neg: | |
| bb = bb * 2.0 | |
| ww = w.view(B, T, H, hd) | |
| if self.gate_in_kernel: | |
| # the Triton kernel applies softplus + dt_bias itself | |
| g = f.float().view(B, T, H, hd) | |
| kw = dict(use_gate_in_kernel=True, A_log=self.A_log, dt_bias=self.dt_bias) | |
| else: | |
| g = -self.A_log.float().exp().view(1, 1, H, 1) * \ | |
| F.softplus(f.float() + self.dt_bias).view(B, T, H, hd) | |
| kw = {} | |
| o, _ = _chunk_gdn2(q=q, k=k, v=v, g=g, b=bb, w=ww, use_qk_l2norm_in_kernel=True, **kw) | |
| else: | |
| q = causal_conv(q, self.q_conv1d.weight).view(B, T, H, hd) | |
| k = causal_conv(k, self.k_conv1d.weight).view(B, T, H, hd) | |
| v = causal_conv(v, self.v_conv1d.weight).view(B, T, H, hd) | |
| g = -self.A_log.float().exp().view(1, 1, H, 1) * \ | |
| F.softplus(f.float() + self.dt_bias).view(B, T, H, hd) | |
| bb = b.view(B, T, H, hd) | |
| if self.allow_neg: | |
| bb = bb * 2.0 | |
| o = gdn2_recurrent(l2norm(q), l2norm(k), v, g, bb, w.view(B, T, H, hd)) | |
| o = self.o_norm(o, gate.view(B, T, H, hd)).reshape(B, T, self.Vd) | |
| return self.o_proj(o) | |
| class GatedGQA(nn.Module): | |
| def __init__(self, d, cfg, max_len, eps): | |
| super().__init__() | |
| self.nq = int(cfg["q_heads"]) | |
| self.nkv = int(cfg["kv_heads"]) | |
| self.hd = int(cfg["head_dim"]) | |
| self.rot = int(cfg.get("rotary_dim", self.hd)) | |
| self.theta = float(cfg.get("rope_theta", 10000.0)) | |
| self.value_residual = bool(cfg.get("value_residual", True)) | |
| self.qk_norm = bool(cfg.get("qk_norm", True)) | |
| self.max_len = int(max_len) | |
| self.qg_proj = nn.Linear(d, 2 * self.nq * self.hd, bias=False) | |
| self.k_proj = nn.Linear(d, self.nkv * self.hd, bias=False) | |
| self.v_proj = nn.Linear(d, self.nkv * self.hd, bias=False) | |
| self.o_proj = nn.Linear(self.nq * self.hd, d, bias=False) | |
| self.q_norm = OffsetRMSNorm(self.hd, eps) if self.qk_norm else None | |
| self.k_norm = OffsetRMSNorm(self.hd, eps) if self.qk_norm else None | |
| self.v_mix = nn.Parameter(torch.tensor([0.5, 0.5])) | |
| # NOTE: the RoPE tables are deliberately NOT buffers. transformers builds models on the `meta` device and | |
| # materialises them afterwards, which leaves computed non-persistent buffers uninitialised (NaNs). | |
| self._rope = None | |
| self._rope_key = None | |
| def _tables(self, T, device): | |
| key = (int(max(T, 1)), str(device)) | |
| if self._rope_key != key: | |
| cos, sin = build_rope(max(key[0], self.max_len), self.rot, self.theta) | |
| self._rope = (cos.to(device), sin.to(device)) | |
| self._rope_key = key | |
| return self._rope | |
| def forward(self, x, v_first, attn_mask): | |
| B, T, _ = x.shape | |
| nq, nkv, hd = self.nq, self.nkv, self.hd | |
| q, gate = self.qg_proj(x).chunk(2, dim=-1) | |
| q = q.reshape(B, T, nq, hd) | |
| k = self.k_proj(x).reshape(B, T, nkv, hd) | |
| v = self.v_proj(x).reshape(B, T, nkv, hd) | |
| if self.value_residual: | |
| if v_first is None: | |
| v_first = v | |
| v = self.v_mix[0].to(v.dtype) * v + self.v_mix[1].to(v.dtype) * v_first | |
| if self.q_norm is not None: | |
| q, k = self.q_norm(q), self.k_norm(k) | |
| cos, sin = self._tables(T, x.device) | |
| q = apply_rope(q, cos, sin) | |
| k = apply_rope(k, cos, sin) | |
| rep = nq // nkv | |
| k = k.repeat_interleave(rep, dim=2) | |
| v = v.repeat_interleave(rep, dim=2) | |
| o = F.scaled_dot_product_attention(q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2), | |
| attn_mask=attn_mask, is_causal=attn_mask is None) | |
| o = o.transpose(1, 2).reshape(B, T, nq * hd) * torch.sigmoid(gate) | |
| return self.o_proj(o), v_first | |
| def _causal_mask(attention_mask, B, T, device): | |
| # None means "plain causal" (the fast path: is_causal=True inside SDPA). | |
| if attention_mask is None: | |
| return None | |
| am = attention_mask.to(device=device) | |
| if am.dim() != 2 or bool(am.bool().all()): | |
| return None | |
| causal = torch.ones(T, T, dtype=torch.bool, device=device).tril() | |
| return causal[None, None] & am[:, None, None, :].bool() | |
| class OleanderBlock(nn.Module): | |
| def __init__(self, config, kind): | |
| super().__init__() | |
| d, eps = config.hidden_size, config.norm_eps | |
| self.kind = kind | |
| self.norm1, self.norm2 = RMSNorm(d, eps), RMSNorm(d, eps) | |
| if kind == "gdn2": | |
| self.mixer = GDN2Mixer(d, config.gdn2) | |
| elif kind == "gqa": | |
| self.mixer = GatedGQA(d, config.gqa, config.max_seq_len, eps) | |
| else: | |
| raise ValueError("unknown layer kind: %r" % (kind,)) | |
| self.mlp = SwiGLU(d, config.mlp_hidden) | |
| self.attn_res_mixer = ResConsumer(d) | |
| self.attn_res_mlp = ResConsumer(d) | |
| class OleanderPreTrainedModel(PreTrainedModel): | |
| config_class = OleanderConfig | |
| base_model_prefix = "" | |
| main_input_name = "input_ids" | |
| _no_split_modules = ["OleanderBlock"] | |
| supports_gradient_checkpointing = False | |
| _supports_sdpa = True | |
| _supports_cache_class = False | |
| _supports_static_cache = False | |
| def _init_weights(self, module): | |
| std = float(getattr(self.config, "init_std", 0.02)) | |
| if isinstance(module, nn.Linear): | |
| nn.init.normal_(module.weight, mean=0.0, std=std) | |
| if module.bias is not None: | |
| nn.init.zeros_(module.bias) | |
| elif isinstance(module, nn.Embedding): | |
| nn.init.normal_(module.weight, mean=0.0, std=std) | |
| def tie_weights(self, *args, **kwargs): | |
| # The LM head *is* the embedding matrix - nothing to tie. | |
| return None | |
| # transformers >= 4.50 wants an explicit GenerationMixin; older versions already inherit it, in which case the tuple | |
| # stays a single base (listing it twice would be an MRO error). | |
| _OLEANDER_BASES = (OleanderPreTrainedModel,) | |
| try: | |
| from transformers import GenerationMixin as _GenerationMixin | |
| if _GenerationMixin not in OleanderPreTrainedModel.__mro__: | |
| _OLEANDER_BASES = (OleanderPreTrainedModel, _GenerationMixin) | |
| except Exception: # noqa: BLE001 | |
| pass | |
| class OleanderForCausalLM(*_OLEANDER_BASES): | |
| """Causal LM. The trunk sits directly on this module (no `model.` submodule), so the parameter names are exactly | |
| the trainer's - `embed.weight`, `layers.N.mixer.*`, `final_norm.weight` - and the training checkpoints load with | |
| `strict=True`. The LM head is the tied embedding matrix. | |
| """ | |
| base_model_prefix = "" | |
| def __init__(self, config): | |
| super().__init__(config) | |
| d = config.hidden_size | |
| self.group_size = len(config.group_pattern) | |
| self.eps = config.norm_eps | |
| self.use_attn_res = bool(config.attn_res) | |
| self.embed = nn.Embedding(config.vocab_size, d) | |
| kinds = getattr(config, "oleander_layer_types", None) or config.layer_types | |
| self.layers = nn.ModuleList([OleanderBlock(config, kinds[i]) for i in range(config.num_hidden_layers)]) | |
| self.res_out = ResConsumer(d) | |
| self.final_norm = RMSNorm(d, self.eps) | |
| self.post_init() | |
| # ---- embeddings / head ----------------------------------------------------------------------------------- | |
| def get_input_embeddings(self): | |
| return self.embed | |
| def set_input_embeddings(self, value): | |
| self.embed = value | |
| def get_output_embeddings(self): | |
| return None | |
| def head_weight(self): | |
| return self.embed.weight | |
| # ---- trunk ----------------------------------------------------------------------------------------------- | |
| def _mix(self, cons, srcs): | |
| if len(srcs) == 1: | |
| return srcs[0] | |
| if not self.use_attn_res: | |
| out = None | |
| for s in srcs: | |
| out = s.float() if out is None else out + s.float() | |
| return out | |
| return attnres_mix(cons.query, cons.norm_w, self.eps, *srcs) | |
| def _trunk(self, input_ids, attention_mask=None): | |
| """Returns the final-normed hidden states in fp32.""" | |
| x = self.embed(input_ids) | |
| B, T, _ = x.shape | |
| attn_mask = _causal_mask(attention_mask, B, T, x.device) | |
| sources, partial, v_first = [x], None, None | |
| for i, blk in enumerate(self.layers): | |
| h = self._mix(blk.attn_res_mixer, sources + ([partial] if partial is not None else [])) | |
| if i > 0 and i % self.group_size == 0: | |
| sources.append(partial) | |
| partial = None | |
| hn = blk.norm1(h) | |
| if blk.kind == "gdn2": | |
| out = blk.mixer(hn) | |
| else: | |
| out, v_first = blk.mixer(hn, v_first, attn_mask) | |
| out = out.float() | |
| partial = out if partial is None else partial + out | |
| h = self._mix(blk.attn_res_mlp, sources + [partial]) | |
| partial = partial + blk.mlp(blk.norm2(h)).float() | |
| h = self._mix(self.res_out, sources + [partial]) | |
| return self.final_norm(h) | |
| # ---- head / loss ----------------------------------------------------------------------------------------- | |
| def _logits(self, h, keep=0, chunk=8192): | |
| if keep and keep > 0: | |
| h = h[:, -int(keep):] | |
| B, T, D = h.shape | |
| hf = h.reshape(-1, D) | |
| parts = [F.linear(hf[s:s + chunk], self.head_weight) for s in range(0, hf.shape[0], chunk)] | |
| logits = parts[0] if len(parts) == 1 else torch.cat(parts, 0) | |
| return logits.view(B, T, -1).float() | |
| def _loss(self, h, labels, chunk=8192): | |
| if labels.dim() == 3: | |
| labels = labels[..., 0] | |
| B, T, D = h.shape | |
| hf = h.reshape(-1, D) | |
| lf = labels.reshape(-1) | |
| total = hf.new_zeros((), dtype=torch.float32) | |
| denom = (lf >= 0).sum().clamp(min=1).float() | |
| for s in range(0, hf.shape[0], chunk): | |
| lg = F.linear(hf[s:s + chunk], self.head_weight).float() | |
| total = total + F.cross_entropy(lg, lf[s:s + chunk], reduction="sum", ignore_index=-100) | |
| return total / denom | |
| def forward(self, input_ids=None, attention_mask=None, position_ids=None, past_key_values=None, | |
| inputs_embeds=None, labels=None, use_cache=None, output_attentions=None, | |
| output_hidden_states=None, return_dict=None, logits_to_keep=0, num_logits_to_keep=0, **kwargs): | |
| # No KV cache: the GDN2 mixers are linear-attention and this repo ships `use_cache=False`. | |
| return_dict = True if return_dict is None else return_dict | |
| h = self._trunk(input_ids, attention_mask=attention_mask) # fp32 [B, T, D] | |
| loss = self._loss(h, labels) if labels is not None else None | |
| keep = int(logits_to_keep or num_logits_to_keep or 0) | |
| logits = self._logits(h, keep=keep) | |
| if not return_dict: | |
| return (logits,) + ((loss,) if loss is not None else ()) | |
| return CausalLMOutputWithPast(loss=loss, logits=logits) | |
| def prepare_inputs_for_generation(self, input_ids, attention_mask=None, **kwargs): | |
| return {"input_ids": input_ids, "attention_mask": attention_mask} | |