Text Generation
MLX
Safetensors
English
qwen3-mdlm-adaptive-hybrid
qwen3
diffusion
text-diffusion
chat
Instructions to use goldenfox/marimo-0.6b-mlx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use goldenfox/marimo-0.6b-mlx 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("goldenfox/marimo-0.6b-mlx") 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 goldenfox/marimo-0.6b-mlx with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Generate some text mlx_lm.generate --model "goldenfox/marimo-0.6b-mlx" --prompt "Once upon a time"
- Atomic Chat
| """Generation loop of the adaptive hybrid: AR control, in-block denoising, AR answer. | |
| Numpy port of the inference paths in ``diffusion_lm.hybrid`` and the playground's | |
| streaming loop. Sampling stays in fp64 (Gumbel argmax, the reference semantics of the | |
| torch backend); the RNG is a ``numpy.random.Generator``, so sampled transcripts match the | |
| torch serving path statistically, not token-for-token. | |
| """ | |
| from __future__ import annotations | |
| import time | |
| import numpy as np | |
| from masks import adaptive_block_mask, prefix_causal_blocked | |
| from model import Denoiser | |
| FLOAT_MIN = np.finfo(np.float32).min | |
| def sample_categorical(logits: np.ndarray, temperature: float, rng: np.random.Generator): | |
| """Sample one token per row with fp64 Gumbel noise; argmax at temperature zero.""" | |
| if temperature < 0: | |
| raise ValueError('temperature must be non-negative') | |
| if temperature == 0: | |
| return logits.argmax(axis=-1) | |
| scaled = logits.astype(np.float64) / temperature | |
| uniform = rng.random(scaled.shape).clip(1e-12, 1.0 - 1e-12) | |
| return (scaled - np.log(-np.log(uniform))).argmax(axis=-1) | |
| def apply_repetition_penalty( | |
| logits: np.ndarray, token_ids: list[int], penalty: float | |
| ) -> np.ndarray: | |
| """Divide logits of already-emitted tokens by ``penalty`` (CTRL convention).""" | |
| if penalty == 1.0 or not token_ids: | |
| return logits | |
| index = np.asarray(sorted(set(token_ids))) | |
| adjusted = logits.copy() | |
| selected = logits[index] | |
| adjusted[index] = np.where(selected > 0, selected / penalty, selected * penalty) | |
| return adjusted | |
| def apply_top_p(logits: np.ndarray, top_p: float) -> np.ndarray: | |
| """Restrict sampling to the smallest set of tokens whose mass reaches ``top_p``.""" | |
| if top_p >= 1.0: | |
| return logits | |
| order = np.argsort(-logits, kind='stable') | |
| ordered = logits[order].astype(np.float64) | |
| shifted = np.exp(ordered - ordered.max()) | |
| probabilities = shifted / shifted.sum() | |
| remove = probabilities.cumsum() - probabilities >= top_p | |
| ordered = np.where(remove, FLOAT_MIN, ordered) | |
| restricted = np.empty_like(logits) | |
| restricted[order] = ordered.astype(logits.dtype) | |
| return restricted | |
| def predict_control( | |
| denoiser: Denoiser, | |
| sequence: list[int], | |
| control_ids: list[int], | |
| *, | |
| prefix_len: int, | |
| causal_prefix: bool, | |
| temperature: float, | |
| rng: np.random.Generator, | |
| ) -> int: | |
| """Predict the next control token, restricted to the size/stop menu.""" | |
| seq_len = len(sequence) | |
| blocked = prefix_causal_blocked(prefix_len, seq_len, causal_prefix=causal_prefix) | |
| logits = denoiser.logits(sequence, blocked, [seq_len - 1])[0] | |
| restricted = np.full_like(logits, FLOAT_MIN) | |
| index = np.asarray(control_ids) | |
| restricted[index] = logits[index] | |
| return int(sample_categorical(restricted[None, :], temperature, rng)[0]) | |
| def denoise_block_steps( | |
| denoiser: Denoiser, | |
| sequence: list[int], | |
| size: int, | |
| *, | |
| problem_len: int, | |
| steps: int, | |
| temperature: float, | |
| causal_prefix: bool, | |
| rng: np.random.Generator, | |
| cache_prefix: bool = False, | |
| ): | |
| """Yield ``(step, block_ids)`` while ancestrally denoising one ``<szN>`` block. | |
| The ancestral reverse transition reveals each still-masked position with probability | |
| ``1 / steps_left``, so the final step always completes the block. ``cache_prefix`` | |
| encodes the context once per block and re-feeds the changing rows each step, trimming | |
| the cache back in between. The cache boundary sits BEFORE the ``<szN>`` token: the | |
| trained mask groups that token with its own block, attended bidirectionally, so its | |
| keys depend on the block's current state and must be recomputed every step — priming | |
| it with the context would freeze a key that never saw the block. Everything earlier | |
| never attends forward into the new block, which is what makes its cache sound. | |
| """ | |
| mdlm = denoiser.config['mdlm'] | |
| mask_id = mdlm['mask_token_id'] | |
| size_ids = tuple(int(i) for i in mdlm['size_ids'].values()) | |
| window = np.asarray([*sequence, *([mask_id] * size)], dtype=np.int64) | |
| window_prefix = len(sequence) | |
| prime_len = window_prefix - 1 | |
| blocked = adaptive_block_mask( | |
| window, problem_len, window.shape[0], size_ids, mdlm['end_think_id'], | |
| causal_prefix=causal_prefix, | |
| ) | |
| caches = None | |
| if cache_prefix: | |
| caches = denoiser.new_caches() | |
| denoiser.logits(window[:prime_len], blocked[:prime_len, :prime_len], None, caches) | |
| for step in range(steps): | |
| masked = window == mask_id | |
| if not masked.any(): | |
| break | |
| if caches is not None: | |
| denoiser.trim_caches(caches, prime_len) | |
| positions = np.flatnonzero(masked[prime_len:]) | |
| logits = denoiser.logits( | |
| window[prime_len:], blocked[prime_len:, :], positions, caches | |
| ) | |
| else: | |
| logits = denoiser.logits(window, blocked, np.flatnonzero(masked)) | |
| predictions = sample_categorical(logits, temperature, rng) | |
| proposed = window.copy() | |
| proposed[masked] = predictions | |
| reveal_probability = 1.0 / (steps - step) | |
| reveal = (rng.random(window.shape[0]) < reveal_probability) & masked | |
| window = np.where(reveal, proposed, window) | |
| yield step + 1, [int(t) for t in window[window_prefix:]] | |
| if (window == mask_id).any(): | |
| raise RuntimeError('sampler finished with masked positions') | |
| def decode_answer_steps( | |
| denoiser: Denoiser, | |
| sequence: list[int], | |
| *, | |
| prefix_len: int, | |
| stop_ids: tuple[int, ...], | |
| max_new_tokens: int, | |
| temperature: float, | |
| top_p: float, | |
| repetition_penalty: float, | |
| causal_prefix: bool, | |
| rng: np.random.Generator, | |
| ): | |
| """Yield answer tokens decoded autoregressively with the prefix in a key/value cache.""" | |
| caches = denoiser.new_caches() | |
| generated: list[int] = [] | |
| step_ids = list(sequence) | |
| for _ in range(max(0, max_new_tokens)): | |
| seen = caches[0].offset | |
| length = seen + len(step_ids) | |
| blocked = prefix_causal_blocked(prefix_len, length, causal_prefix=causal_prefix) | |
| logits = denoiser.logits(step_ids, blocked[seen:, :], [len(step_ids) - 1], caches)[0] | |
| logits = apply_repetition_penalty(logits, generated, repetition_penalty) | |
| logits = apply_top_p(logits, top_p) | |
| token = int(sample_categorical(logits[None, :], temperature, rng)[0]) | |
| generated.append(token) | |
| yield token | |
| if token in stop_ids: | |
| break | |
| step_ids = [token] | |
| def block_contents( | |
| think_ids: list[int], *, size_by_id: dict[int, int], pad_id: int, end_id: int | |
| ) -> list[tuple[int, list[int]]]: | |
| """Split the think stream into ``(size, content ids)`` blocks by walking ``<szN>``.""" | |
| blocks = [] | |
| cut = 0 | |
| while cut < len(think_ids): | |
| size = size_by_id.get(think_ids[cut]) | |
| if size is None: | |
| cut += 1 | |
| continue | |
| block = think_ids[cut + 1 : cut + 1 + size] | |
| blocks.append((size, [t for t in block if t not in (pad_id, end_id)])) | |
| cut += 1 + size | |
| return blocks | |
| def stream_turn( | |
| denoiser: Denoiser, | |
| prompt_ids: list[int], | |
| *, | |
| rng: np.random.Generator, | |
| temperature: float = 0.8, | |
| top_p: float = 0.95, | |
| repetition_penalty: float = 1.0, | |
| steps_per_block: int | None = None, | |
| max_answer_tokens: int | None = None, | |
| max_blocks: int = 48, | |
| # Prefix caching during denoising measured 1.7x faster per block on M1 Pro (2026-08-14, | |
| # 2.64s vs 4.44s for sz32 at prefix 500) with cached==uncached logits at fp32 noise level. | |
| cache_blocks: bool = True, | |
| ): | |
| """Stream one assistant turn: control loop, per-block denoising, AR answer. | |
| Yields ``('block', index, size, step, total, block_ids)`` during thinking, | |
| ``('answer', token_id)`` per answer token, and one final ``('done', result)`` where | |
| ``result`` carries the think/answer ids, per-block notes, and wall times. | |
| """ | |
| mdlm = denoiser.config['mdlm'] | |
| max_seq_len = mdlm['max_seq_len'] | |
| end_think_id = mdlm['end_think_id'] | |
| size_by_id = {int(i): int(size) for size, i in mdlm['size_ids'].items()} | |
| control_ids = [*size_by_id.keys(), end_think_id] | |
| causal_prefix = mdlm['causal_prefix'] | |
| steps = steps_per_block or mdlm['steps_per_block'] | |
| answer_limit = max_answer_tokens or mdlm['max_answer_tokens'] | |
| sequence = [*prompt_ids, mdlm['think_id']] | |
| prefix_len = len(prompt_ids) + 1 | |
| terminated = False | |
| think_started = time.perf_counter() | |
| for block_index in range(max_blocks): | |
| control = predict_control( | |
| denoiser, sequence, control_ids, | |
| prefix_len=prefix_len, causal_prefix=causal_prefix, temperature=0.0, rng=rng, | |
| ) | |
| if control == end_think_id: | |
| terminated = True | |
| break | |
| size = size_by_id[control] | |
| if len(sequence) + 1 + size > max_seq_len - 8: | |
| break | |
| sequence.append(control) | |
| block: list[int] = [] | |
| for step, block_ids in denoise_block_steps( | |
| denoiser, sequence, size, | |
| problem_len=len(prompt_ids), steps=steps, temperature=temperature, | |
| causal_prefix=causal_prefix, rng=rng, cache_prefix=cache_blocks, | |
| ): | |
| block = block_ids | |
| yield 'block', block_index, size, step, steps, block_ids | |
| sequence.extend(block) | |
| sequence.append(end_think_id) | |
| think_seconds = time.perf_counter() - think_started | |
| think_ids = sequence[prefix_len:] | |
| answer_ids: list[int] = [] | |
| answer_started = time.perf_counter() | |
| for token in decode_answer_steps( | |
| denoiser, sequence, | |
| prefix_len=prefix_len, stop_ids=(mdlm['im_end_id'], mdlm['eos_id']), | |
| max_new_tokens=min(answer_limit, max_seq_len - len(sequence)), | |
| temperature=temperature, top_p=top_p, repetition_penalty=repetition_penalty, | |
| causal_prefix=causal_prefix, rng=rng, | |
| ): | |
| answer_ids.append(token) | |
| yield 'answer', token | |
| yield 'done', { | |
| 'think_ids': think_ids, | |
| 'answer_ids': answer_ids, | |
| 'blocks': block_contents( | |
| think_ids, size_by_id=size_by_id, | |
| pad_id=mdlm['thought_pad_id'], end_id=end_think_id, | |
| ), | |
| 'terminated': terminated, | |
| 'think_seconds': think_seconds, | |
| 'answer_seconds': time.perf_counter() - answer_started, | |
| } | |