Text Generation
MLX
English
diffusion_gemma
nvfp4
diffusion-gemma
diffusion-lm
structured-output
decision-making
conversational
modelopt
Instructions to use GenbaLabs/super-decider-mlx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use GenbaLabs/super-decider-mlx with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("GenbaLabs/super-decider-mlx") prompt = "Write a story about Einstein" messages = [{"role": "user", "content": prompt}] prompt = tokenizer.apply_chat_template( messages, add_generation_prompt=True ) text = generate(model, tokenizer, prompt=prompt, verbose=True) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Pi
How to use GenbaLabs/super-decider-mlx with Pi:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "GenbaLabs/super-decider-mlx"
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "mlx-lm": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "GenbaLabs/super-decider-mlx" } ] } } }Run Pi
# Start Pi in your project directory: pi
- MLX LM
How to use GenbaLabs/super-decider-mlx with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Interactive chat REPL mlx_lm.chat --model "GenbaLabs/super-decider-mlx"
Run an OpenAI-compatible server
# Install MLX LM uv tool install mlx-lm # Start the server mlx_lm.server --model "GenbaLabs/super-decider-mlx" # Calling the OpenAI-compatible server with curl curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "GenbaLabs/super-decider-mlx", "messages": [ {"role": "user", "content": "Hello"} ] }' - Hermes Agent
How to use GenbaLabs/super-decider-mlx with Hermes Agent:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "GenbaLabs/super-decider-mlx"
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default GenbaLabs/super-decider-mlx
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use GenbaLabs/super-decider-mlx with OpenClaw:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "GenbaLabs/super-decider-mlx"
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "GenbaLabs/super-decider-mlx" \ --custom-provider-id mlx-lm \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Download superdecider/generate.py from GenbaLabs/super-decider-mlx: direct link, hf CLI and curl.
- Browser
- Download file 8.94 kB
-
https://huggingface.co/GenbaLabs/super-decider-mlx/resolve/main/superdecider/generate.py
- Command line
-
hf download hf://GenbaLabs/super-decider-mlx/superdecider/generate.py
-
curl -L -o generate.py https://huggingface.co/GenbaLabs/super-decider-mlx/resolve/main/superdecider/generate.py
8.94 kB
| """Block-diffusion generation for the MLX DiffusionGemma port. | |
| Port of ``transformers/models/diffusion_gemma/generation_diffusion_gemma.py``: entropy-bound sampler, | |
| linear temperature schedule, stable-and-confident stopping, and the outer canvas loop. | |
| """ | |
| from __future__ import annotations | |
| import math | |
| import mlx.core as mx | |
| from .config import EntropyBoundSamplerConfig, GenerationConfig | |
| from .modeling import DiffusionGemma | |
| def entropy(logits: mx.array) -> mx.array: | |
| """Categorical entropy over the last axis, in float32 (``torch.distributions.Categorical.entropy``).""" | |
| p = mx.softmax(logits.astype(mx.float32), axis=-1) | |
| log_p = mx.log(mx.where(p > 0, p, 1.0)) | |
| return -mx.sum(mx.where(p > 0, p * log_p, 0.0), axis=-1) | |
| class MLXRng: | |
| """Default randomness source: MLX's own generators.""" | |
| def __init__(self, seed: int | None = None): | |
| if seed is not None: | |
| mx.random.seed(seed) | |
| def ints(self, shape: tuple[int, ...], high: int) -> mx.array: | |
| return mx.random.randint(0, high, shape=shape) | |
| def tokens(self, logits: mx.array) -> mx.array: | |
| return mx.random.categorical(logits, axis=-1).astype(mx.int32) | |
| class EntropyBoundSampler: | |
| """Accepts the k lowest-entropy tokens while their joint entropy stays under ``entropy_bound``.""" | |
| def __init__(self, config: EntropyBoundSamplerConfig, canvas_length: int, vocab_size: int): | |
| self.entropy_bound = config.entropy_bound | |
| self.canvas_length = canvas_length | |
| self.vocab_size = vocab_size | |
| self.accepted_token_mask: mx.array | None = None | |
| def initialize_canvas(self, rng) -> mx.array: | |
| return rng.ints((1, self.canvas_length), self.vocab_size) | |
| def accept_canvas(self, current_canvas, denoiser_canvas, logits): | |
| token_entropy = entropy(logits) | |
| order = mx.argsort(token_entropy, axis=-1) | |
| sorted_entropy = mx.take_along_axis(token_entropy, order, axis=-1) | |
| cumulative = mx.cumsum(sorted_entropy, axis=-1) | |
| selected = cumulative - sorted_entropy <= self.entropy_bound | |
| scattered = mx.put_along_axis(mx.zeros_like(selected), order, selected, axis=-1) | |
| self.accepted_token_mask = scattered | |
| return mx.where(scattered, denoiser_canvas, current_canvas) | |
| def renoise_canvas(self, accepted_canvas, rng): | |
| random_canvas = rng.ints(accepted_canvas.shape, self.vocab_size) | |
| return mx.where(self.accepted_token_mask, accepted_canvas, random_canvas) | |
| class LinearTemperatureScheduleLogitsProcessor: | |
| """``logits / (t_min + (t_max - t_min) * cur_step / max_denoising_steps)``.""" | |
| def __init__(self, t_min: float, t_max: float, max_denoising_steps: int): | |
| self.t_min = t_min | |
| self.t_max = t_max | |
| self.max_denoising_steps = max_denoising_steps | |
| def __call__(self, logits: mx.array, cur_step: int) -> mx.array: | |
| temperature = self.t_min + (self.t_max - self.t_min) * (cur_step / self.max_denoising_steps) | |
| return logits / temperature | |
| class StableAndConfidentStoppingCriteria: | |
| """Stop denoising when the argmax canvas is unchanged for ``stability_threshold`` steps and it is confident.""" | |
| def __init__(self, stability_threshold: int, confidence_threshold: float): | |
| self.stability_threshold = stability_threshold | |
| self.confidence_threshold = confidence_threshold | |
| self.history: mx.array | None = None | |
| def reset(self): | |
| self.history = None | |
| def __call__(self, argmax_canvas: mx.array, logits: mx.array) -> bool: | |
| if self.stability_threshold == 0: | |
| stable = mx.ones(argmax_canvas.shape, dtype=mx.bool_) | |
| else: | |
| if self.history is None: | |
| self.history = mx.full((self.stability_threshold, *argmax_canvas.shape), -1, dtype=argmax_canvas.dtype) | |
| stable = mx.all(self.history == argmax_canvas[None], axis=0) | |
| self.history = mx.concatenate([self.history[1:], argmax_canvas[None]], axis=0) | |
| confident = mx.mean(entropy(logits), axis=-1) < self.confidence_threshold | |
| return bool(mx.all(stable & confident)) | |
| def generate( | |
| model: DiffusionGemma, | |
| input_ids: mx.array, | |
| gen_config: GenerationConfig | None = None, | |
| rng=None, | |
| block_ids: mx.array | None = None, | |
| token_logprobs: bool = False, | |
| ) -> mx.array | tuple[mx.array, mx.array]: | |
| """Generate one sequence (batch size 1): runs ``ceil(max_new_tokens / canvas_length)`` canvas blocks. | |
| ``block_ids`` marks prompt groups that attend bidirectionally inside the group (the per-question blocks | |
| of the reference's ``mm_token_type_ids``); they are used for the prefill only, as in the reference. | |
| With ``token_logprobs`` the log-probability the model gave each emitted token at its last denoising step | |
| is returned beside the ids (vLLM's ``choices[].logprobs.token_logprobs``). | |
| """ | |
| gcfg = gen_config or GenerationConfig() | |
| rng = rng or MLXRng() | |
| text = model.text | |
| canvas_length = model.config.canvas_length | |
| ids = input_ids if isinstance(input_ids, mx.array) else mx.array(input_ids) | |
| if ids.ndim == 1: | |
| ids = ids[None] | |
| ids = ids.astype(mx.int32) | |
| eos_ids = [] if gcfg.eos_token_id is None else ( | |
| [gcfg.eos_token_id] if isinstance(gcfg.eos_token_id, int) else list(gcfg.eos_token_id) | |
| ) | |
| pad_token_id = gcfg.pad_token_id | |
| sampler = EntropyBoundSampler(gcfg.sampler_config, canvas_length, text.vocab_size) | |
| processor = LinearTemperatureScheduleLogitsProcessor(gcfg.t_min, gcfg.t_max, gcfg.max_denoising_steps) | |
| stopper = StableAndConfidentStoppingCriteria(gcfg.stability_threshold, gcfg.confidence_threshold) | |
| cur_len = ids.shape[1] | |
| prompt_len = cur_len | |
| lps: list = [] | |
| max_length = cur_len + gcfg.max_new_tokens | |
| cache = None | |
| encoder_positions = mx.arange(cur_len) | |
| decoder_positions = mx.arange(cur_len, cur_len + canvas_length) | |
| for block in range(math.ceil(gcfg.max_new_tokens / canvas_length)): | |
| # 1.a. Encode the new tokens (the whole prompt first, then one canvas per block). | |
| toks = ids if block == 0 else ids[:, -canvas_length:] | |
| _, cache = model.encode(toks, encoder_positions, cache, block_ids if block == 0 else None) | |
| # 1.b. Start the denoising loop from a random canvas. | |
| current_canvas = sampler.initialize_canvas(rng) | |
| argmax_canvas, self_conditioning = current_canvas, None | |
| finished = False | |
| stopper.reset() | |
| # 1.c. Denoise, iterating in reverse order as denoising is the reverse diffusion process. | |
| for cur_step in reversed(range(1, gcfg.max_denoising_steps + 1)): | |
| logits = model.denoise(current_canvas, cache, decoder_positions, self_conditioning) | |
| processed = processor(logits, cur_step) | |
| denoiser_canvas = rng.tokens(processed) | |
| new_argmax_canvas = mx.argmax(processed, axis=-1).astype(mx.int32) | |
| accepted = sampler.accept_canvas(current_canvas, denoiser_canvas, processed) | |
| new_current_canvas = sampler.renoise_canvas(accepted, rng) | |
| if not finished: | |
| finished = stopper(new_argmax_canvas, processed) | |
| self_conditioning = processed.astype(model.embed_tokens.dtype) | |
| current_canvas, argmax_canvas = new_current_canvas, new_argmax_canvas | |
| if finished: | |
| break | |
| if token_logprobs: | |
| logp = processed.astype(mx.float32) | |
| logp = logp - mx.logsumexp(logp, axis=-1, keepdims=True) | |
| lps.append(mx.take_along_axis(logp, argmax_canvas[..., None], axis=-1)[..., 0]) | |
| # 1.d/1.e. Append the canvas, then stop on EOS (padding out the rest of the canvas) or max length. | |
| ids = mx.concatenate([ids, argmax_canvas], axis=-1) | |
| new_tokens = ids[:, -canvas_length:] | |
| if eos_ids: | |
| is_eos = new_tokens == eos_ids[0] | |
| for eos in eos_ids[1:]: | |
| is_eos = is_eos | (new_tokens == eos) | |
| if bool(mx.any(is_eos)): | |
| if pad_token_id is not None: | |
| first_eos = mx.argmax(is_eos.astype(mx.int32), axis=-1, keepdims=True) | |
| keep = mx.arange(canvas_length)[None] <= first_eos | |
| new_tokens = mx.where(keep, new_tokens, mx.array(pad_token_id)) | |
| ids = mx.concatenate([ids[:, :-canvas_length], new_tokens], axis=-1) | |
| return _with_logprobs(ids, lps) | |
| if ids.shape[1] >= max_length: | |
| return _with_logprobs(ids, lps) | |
| # 1.f. Positions for the next canvas. | |
| cur_len += canvas_length | |
| encoder_positions = decoder_positions | |
| decoder_positions = mx.arange(cur_len, cur_len + canvas_length) | |
| return _with_logprobs(ids, lps) | |
| def _with_logprobs(ids: mx.array, lps: list) -> mx.array | tuple[mx.array, mx.array]: | |
| if not lps: | |
| return ids | |
| return ids, mx.concatenate(lps, axis=-1).astype(mx.float32) | |