Text Generation
MLX
English
German
next-concept-modeling
apple-silicon
diffusion-lm
research-code
negative-results
Instructions to use Red-fuchs/ncm-modular with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use Red-fuchs/ncm-modular with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # if on a CUDA device, also pip install mlx[cuda] # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("Red-fuchs/ncm-modular") prompt = "Once upon a time in" text = generate(model, tokenizer, prompt=prompt, verbose=True) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- MLX LM
How to use Red-fuchs/ncm-modular with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Generate some text mlx_lm.generate --model "Red-fuchs/ncm-modular" --prompt "Once upon a time"
- Atomic Chat
Download src/ncm_modular/gen_mlx.py from Red-fuchs/ncm-modular: direct link, hf CLI and curl.
- Browser
- Download file 6.29 kB
-
https://huggingface.co/Red-fuchs/ncm-modular/resolve/main/src/ncm_modular/gen_mlx.py
- Command line
-
hf download hf://Red-fuchs/ncm-modular/src/ncm_modular/gen_mlx.py
-
curl -L -o gen_mlx.py https://huggingface.co/Red-fuchs/ncm-modular/resolve/main/src/ncm_modular/gen_mlx.py
6.29 kB
| """Prefix-conditioned NCM generator (MLX) over the frozen wmt14 codec. Matches upstream wmt14 layout: | |
| prefix attends only to itself (pad-masked); level k>=1 positions see prefix + own level (block_diagonal); | |
| RoPE restarts per level; learned level emb; codebook-tied heads; level 0 predicted from last non-pad prefix position.""" | |
| import os, sys, math | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| from paths import WORK | |
| import numpy as np, mlx.core as mx | |
| from mlx import nn | |
| import codec_mlx | |
| from ncm_mlx.official.model import Block, rope_tables | |
| class FrozenCodec: | |
| """thin wrapper: stop-gradient teacher inputs / sampling inputs from codes.""" | |
| def __init__(self, d=WORK+"/mlx/wmt14"): | |
| self.c = codec_mlx.load(d) | |
| self.levels, self.K, self.L = self.c.levels, self.c.K, self.c.L | |
| self.cb = [self.c.W[f"cb.{k}"] for k in range(self.K)] | |
| self.tok = self.c.W["wte"] # (vocab, 384) frozen token embedding | |
| self.dim = self.tok.shape[1] | |
| def encode(self, ids): return self.c.encode(ids) | |
| def teacher_inputs(self, codes): | |
| """codes: list K of (B,l_k) -> inputs for levels 1..K-1: area_k @ cum recon through level k-1.""" | |
| z, outs = None, [] | |
| for k in range(self.K - 1): | |
| q = self.c.contrib(codes[k], k); z = q if z is None else z + q | |
| outs.append(self.c.area[k + 1] @ z) | |
| return outs | |
| def next_input(self, z, k): return self.c.area[k] @ z | |
| def contrib(self, c, k): return self.c.contrib(c, k) | |
| def decode(self, z): return mx.argmax(self.c.decode_logits(z), -1) | |
| class Gen(nn.Module): | |
| def __init__(self, fc: FrozenCodec, P=48, D=512, H=8, nl=8, pad_id=151643, rope_base=10000.0, drop=0.1): | |
| super().__init__() | |
| self.P, self.D, self.pad_id, self.levels, self.K = P, D, pad_id, fc.levels, fc.K | |
| cd = fc.dim | |
| self.in_proj = nn.Linear(cd, D) | |
| self.level_emb = nn.Embedding(self.K - 1, D) | |
| self.blocks = [Block(D, H) for _ in range(nl)] | |
| self.ln_f = nn.LayerNorm(D, eps=1e-6) | |
| self.drop = nn.Dropout(drop) | |
| self.proj = [nn.Linear(D, cd, bias=False) for _ in range(self.K)] # tied-codebook heads | |
| self.log_inv_t = [mx.array(0.4) for _ in range(self.K)] # effective inverse temperature = exp(8*u), init ~24 | |
| self.cdt = mx.float32 | |
| hd = D // H | |
| self._cb = fc.cb; self._tok = fc.tok | |
| self._esq = [(E * E).sum(-1) for E in fc.cb]; self._scale = [mx.maximum(e.mean(), 1e-12) for e in self._esq] | |
| pos = np.concatenate([np.arange(P)] + [np.arange(l) for l in self.levels[1:]]) | |
| self._rope = rope_tables(pos, hd, rope_base) | |
| self._lvl = mx.array(np.concatenate([np.full(l, k) for k, l in enumerate(self.levels[1:])])) | |
| grp = np.concatenate([np.full(P, -1)] + [np.full(l, k) for k, l in enumerate(self.levels[1:])]) | |
| S = len(grp); kv_p = grp[None, :] == -1 | |
| base = np.where(grp[:, None] == -1, kv_p, kv_p | (grp[:, None] == grp[None, :])) | |
| self._base = mx.array(base)[None, None] | |
| # single-level (inference) tables | |
| self._rope_lv = [rope_tables(np.concatenate([np.arange(P), np.arange(l)]), hd, rope_base) for l in self.levels[1:]] | |
| self._rope_p = rope_tables(np.arange(P), hd, rope_base) | |
| def set_compute(self, dt): | |
| self.set_dtype(dt); self.cdt = dt; return self | |
| def head(self, k, h): | |
| E = self._cb[k]; z = self.proj[k](h).astype(mx.float32) | |
| return (2.0 * (z @ E.T) - self._esq[k]) / self._scale[k] * mx.exp(8.0 * self.log_inv_t[k].astype(mx.float32)) | |
| def prefix_emb(self, ptoks): return self.in_proj(self._tok[ptoks].astype(self.cdt)) | |
| def rp(self, r): return (r[0].astype(self.cdt), r[1].astype(self.cdt)) | |
| def keep(self, ptoks): return ptoks != self.pad_id | |
| def _stack(self, h, mask, rope): | |
| for b in self.blocks: h = b(h, mask, rope) | |
| return self.ln_f(h) | |
| def l0_logits_from(self, hp, ptoks): | |
| last = mx.maximum(self.keep(ptoks).sum(1) - 1, 0) | |
| h0 = mx.take_along_axis(hp, last[:, None, None], axis=1) # (B,1,D) | |
| return self.head(0, h0) | |
| def __call__(self, inputs, ptoks): | |
| """teacher-forced: inputs = list of K-1 arrays (B,l_k,cd) for levels 1..K-1 -> list of K logits.""" | |
| x = mx.concatenate(inputs, axis=1).astype(self.cdt) | |
| h = self.drop(self.in_proj(x) + self.level_emb(self._lvl)) | |
| h = mx.concatenate([self.drop(self.prefix_emb(ptoks)), h], axis=1) | |
| keep = mx.concatenate([self.keep(ptoks), mx.ones((x.shape[0], x.shape[1]), dtype=mx.bool_)], 1) | |
| h = self._stack(h, self._base & keep[:, None, None, :], self.rp(self._rope)) | |
| out = [self.l0_logits_from(h[:, :self.P], ptoks)] | |
| o = self.P | |
| for k in range(1, self.K): | |
| l = self.levels[k]; out.append(self.head(k, h[:, o:o + l])); o += l | |
| return out | |
| # ---- inference | |
| def encode_prefix(self, ptoks): | |
| pe = self.prefix_emb(ptoks) | |
| keep = self.keep(ptoks) | |
| hp = self._stack(pe, keep[:, None, None, :] & mx.ones((1, 1, self.P, 1), dtype=mx.bool_), self.rp(self._rope_p)) | |
| return pe, keep, self.l0_logits_from(hp, ptoks) | |
| def level_logits(self, k, inp, pe, keep): | |
| h = self.in_proj(inp.astype(self.cdt)) + self.level_emb.weight[k - 1] | |
| h = mx.concatenate([pe, h], axis=1) | |
| n = inp.shape[1] | |
| kk = mx.concatenate([keep, mx.ones((keep.shape[0], n), dtype=mx.bool_)], 1) | |
| T = self.P + n | |
| rows = mx.arange(T)[:, None]; cols = mx.arange(T)[None, :] | |
| allowed = ~((rows < self.P) & (cols >= self.P)) | |
| h = self._stack(h, allowed[None, None] & kk[:, None, None, :], self.rp(self._rope_lv[k - 1])) | |
| return self.head(k, h[:, self.P:]) | |
| def generate(gen: Gen, fc: FrozenCodec, ptoks): | |
| """greedy; NFE = 1 (prefix/level0) + K-1 level forwards.""" | |
| pe, keep, l0 = gen.encode_prefix(ptoks) | |
| c = mx.argmax(l0, -1); z = fc.contrib(c, 0); codes = [c] | |
| for k in range(1, gen.K): | |
| c = mx.argmax(gen.level_logits(k, fc.next_input(z, k), pe, keep), -1) | |
| codes.append(c); z = z + fc.contrib(c, k) | |
| return fc.decode(z), codes | |
| def count_params(m): | |
| from mlx.utils import tree_flatten | |
| return sum(v.size for _, v in tree_flatten(m.parameters())) | |