Text Generation
Transformers
Safetensors
Mongolian
rdt
traditional-mongolian
recurrent-depth-transformer
mamba
causal-lm
custom-code
custom_code
Instructions to use Montlok/DoL-1.2-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Montlok/DoL-1.2-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Montlok/DoL-1.2-Base", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Montlok/DoL-1.2-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Montlok/DoL-1.2-Base with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Montlok/DoL-1.2-Base" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Montlok/DoL-1.2-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/Montlok/DoL-1.2-Base
- SGLang
How to use Montlok/DoL-1.2-Base 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 "Montlok/DoL-1.2-Base" \ --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": "Montlok/DoL-1.2-Base", "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 "Montlok/DoL-1.2-Base" \ --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": "Montlok/DoL-1.2-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use Montlok/DoL-1.2-Base with Docker Model Runner:
docker model run hf.co/Montlok/DoL-1.2-Base
Download Model/segmented.py from Montlok/DoL-1.2-Base: direct link, hf CLI and curl.
- Browser
- Download file 18.7 kB
-
https://huggingface.co/Montlok/DoL-1.2-Base/resolve/main/Model/segmented.py
- Command line
-
hf download hf://Montlok/DoL-1.2-Base/Model/segmented.py
-
curl -L -o segmented.py https://huggingface.co/Montlok/DoL-1.2-Base/resolve/main/Model/segmented.py
18.7 kB
| # -*- coding: utf-8 -*- | |
| """Segmented (Block-Transformer-style) recurrent core for the Daffodils RDT. | |
| This core realises the user's target architecture: slice the context into | |
| fixed-length blocks; encode every token with a **causal (forward-only) Mamba**; | |
| take the causal hidden state at each block boundary as that block's *summary*; | |
| run **block-causal attention + shared-weight RDT recurrent depth** over the | |
| ``n_seg`` summaries; finally scatter the *previous* block's refined summary back | |
| to token resolution and decode the next block with a small **causal local | |
| decoder**. Because ``n_seg << n_tok`` the (quadratic) attention / RDT cost drops | |
| sharply relative to running it on every token. | |
| Causality (zero future leakage), end-to-end: | |
| * The block summary for block ``s`` is the causal Mamba state at token index | |
| ``min((s+1)*L_B - 1, L-1)`` — it only ever saw tokens ``<= boundary``. | |
| * Block-causal attention lets summary ``i`` attend to summaries ``<= i`` only. | |
| * Token ``t`` in block ``s`` is decoded from the **refined summary of block | |
| ``s-1``** (which depends only on tokens ``< s*L_B <= t``) plus a causal local | |
| decoder over the token embeddings ``e0[<= t]``. Block ``0`` uses a learned | |
| start context. A block summary therefore only ever conditions the *next* | |
| block, never its own tokens. | |
| Literature: Block Transformer (arXiv:2406.02657), Block-State Transformer | |
| (2306.09539), NSA (2502.11089) for the block-summary attention; Huginn | |
| (2502.05171) for shared-weight RDT with random-r + truncated BPTT; causal SSM | |
| basis Mamba (2312.00752). ``SegmentedCore`` is a drop-in replacement for | |
| ``RecurrentCore`` / ``TwoStageCore``: identical forward signature and return | |
| contract (equal-length ``hidden`` + ``info`` dict). | |
| """ | |
| from __future__ import annotations | |
| import torch | |
| import torch.nn as nn | |
| from torch.utils.checkpoint import checkpoint | |
| from Model.blocks import AttnSubLayer, MambaSubLayer | |
| from Model.layers.rmsnorm import RMSNorm | |
| from Model.two_stage import MHCAttnSubLayer | |
| class SegmentedCore(nn.Module): | |
| def __init__(self, cfg): | |
| super().__init__() | |
| self.cfg = cfg | |
| if cfg.use_act: | |
| raise ValueError("SegmentedCore does not support use_act=True") | |
| if cfg.recurrent_steps <= 0: | |
| raise ValueError("recurrent_steps must be positive") | |
| if cfg.segment_len <= 0: | |
| raise ValueError("segment_len must be positive") | |
| if cfg.segmented_local_layers <= 0: | |
| raise ValueError("segmented_local_layers must be positive") | |
| self.segment_len = int(cfg.segment_len) | |
| self.drift_mode = cfg.recurrent_drift_mode | |
| self.n_streams = cfg.mhc_n_streams | |
| self.inject_scale = cfg.inject_scale | |
| self.inject_decay = cfg.recurrent_inject_decay | |
| self.random_r = bool(cfg.recurrent_random_r) | |
| self.r_min = int(cfg.recurrent_r_min) | |
| self.r_max = int(cfg.recurrent_r_max) | |
| self.grad_ckpt_stage1 = bool(getattr(cfg, "grad_ckpt_blocks", False)) | |
| self.grad_ckpt_stage2 = bool(getattr(cfg, "grad_ckpt_recurrent", False)) | |
| self.grad_ckpt_local = bool(getattr(cfg, "grad_ckpt_blocks", False)) | |
| # Stage 1: causal Mamba token encoder (forward-only). | |
| self.stage1 = nn.ModuleList( | |
| MambaSubLayer(cfg, layer_idx=i) for i in range(cfg.stage1_mamba_layers) | |
| ) | |
| # Stage 2: block-level refinement layers (shared across RDT steps). | |
| if self.drift_mode == "mhc": | |
| self.stage2 = nn.ModuleList( | |
| MHCAttnSubLayer(cfg, layer_idx=i) | |
| for i in range(cfg.stage2_attn_layers) | |
| ) | |
| else: | |
| self.stage2 = nn.ModuleList( | |
| AttnSubLayer(cfg, layer_idx=i) for i in range(cfg.stage2_attn_layers) | |
| ) | |
| if self.drift_mode in {"norm", "both"}: | |
| self.boundary_norm = RMSNorm(cfg.d_model, eps=cfg.rmsnorm_eps) | |
| else: | |
| self.boundary_norm = None | |
| # Stage 3: local causal token decoder + previous-block context plumbing. | |
| self.ctx_proj = nn.Linear(cfg.d_model, cfg.d_model, bias=False) | |
| self.start_ctx = nn.Parameter(torch.zeros(cfg.d_model)) | |
| self.local = nn.ModuleList( | |
| MambaSubLayer(cfg, layer_idx=i) | |
| for i in range(cfg.segmented_local_layers) | |
| ) | |
| # ------------------------------------------------------------------ | |
| # Forward | |
| # ------------------------------------------------------------------ | |
| def forward( | |
| self, | |
| e0: torch.Tensor, | |
| word_pos: torch.Tensor | None = None, | |
| morph_depth: torch.Tensor | None = None, | |
| attn_mask: torch.Tensor | None = None, | |
| causal: bool = True, | |
| steps: int | None = None, | |
| bptt_window: int | None = None, | |
| cache=None, | |
| pos_offset: int = 0, | |
| ) -> tuple[torch.Tensor, dict]: | |
| self._check_inputs(e0, word_pos, morph_depth, attn_mask) | |
| if cache is not None: | |
| return self._forward_cached( | |
| e0, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| total_steps=self._resolve_steps(steps), | |
| cache=cache, | |
| pos_offset=pos_offset, | |
| ) | |
| total_steps = self._resolve_steps(steps) | |
| # --- Stage 1: causal token encoding ------------------------------- | |
| backbone = self._run_stage1( | |
| e0, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=attn_mask, | |
| causal=causal, | |
| ) | |
| bsz, seq_len, _ = e0.shape | |
| boundary_idx = self._boundary_indices(seq_len, e0.device) # [n_seg] | |
| n_seg = boundary_idx.shape[0] | |
| # Block summaries = causal state at each block boundary (zero leakage). | |
| summaries = backbone.index_select(1, boundary_idx) # [B, n_seg, d] | |
| # --- Stage 2: block-causal refinement (RDT) ----------------------- | |
| seg_word_pos = torch.arange(n_seg, device=e0.device).unsqueeze(0).expand( | |
| bsz, n_seg | |
| ) | |
| seg_morph = torch.zeros(bsz, n_seg, dtype=torch.long, device=e0.device) | |
| refined = self._refine( | |
| summaries, | |
| word_pos=seg_word_pos, | |
| morph_depth=seg_morph, | |
| total_steps=total_steps, | |
| bptt_window=bptt_window, | |
| ) # [B, n_seg, d] | |
| # --- Stage 3: scatter previous block's context, local causal decode | |
| ctx_tokens = self._scatter_prev_context(refined, seq_len) # [B, L, d] | |
| h = e0 + self.ctx_proj(ctx_tokens) | |
| h = self._run_local( | |
| h, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=attn_mask, | |
| causal=causal, | |
| ) | |
| info = { | |
| "steps_used": total_steps, | |
| "ponder_cost": e0.new_tensor(0.0), | |
| "global_semantic": self._global_semantic(backbone, attn_mask), | |
| "n_segments": n_seg, | |
| } | |
| return h, info | |
| # ------------------------------------------------------------------ | |
| # Incremental decode (full-forward equivalent when kv_share_budget=0) | |
| # ------------------------------------------------------------------ | |
| def _forward_cached( | |
| self, | |
| e0: torch.Tensor, | |
| word_pos: torch.Tensor | None, | |
| morph_depth: torch.Tensor | None, | |
| total_steps: int, | |
| cache, | |
| pos_offset: int, | |
| ) -> tuple[torch.Tensor, dict]: | |
| """Process the new chunk ``e0`` (``[B, m, d]``) one block-causally. | |
| Stage-1 Mamba and the local decoder carry constant-size recurrent state; | |
| the block-level RDT keeps a causal MLA cache per ``(step, layer)``. | |
| A block summary is | |
| finalized only when its block completes, and a token only ever reads its | |
| *previous* block's refined summary, so the result is identical to a fresh | |
| full forward over the growing prefix (zero future leakage preserved). | |
| """ | |
| if int(self.cfg.kv_share_budget) > 0: | |
| raise NotImplementedError( | |
| "segmented cached decode does not support kv_share_budget > 0. " | |
| "A shared append-only MLA cache corrupts recurrent-step history; " | |
| "keep kv_share_budget=0 for cache-equivalent decode." | |
| ) | |
| bsz, m, dim = e0.shape | |
| device = e0.device | |
| Lb = self.segment_len | |
| backbone = e0 | |
| for i, layer in enumerate(self.stage1): | |
| backbone = layer( | |
| backbone, | |
| attn_mask=None, | |
| cache=cache.mamba_cache(f"seg.stage1.{i}"), | |
| ) | |
| abs_pos = pos_offset + torch.arange(m, device=device) | |
| is_boundary = ((abs_pos + 1) % Lb) == 0 | |
| boundary_local = torch.nonzero(is_boundary, as_tuple=False).flatten() | |
| prior = getattr(cache, "seg_refined", None) | |
| prior_segs = 0 if prior is None else prior.shape[1] | |
| if boundary_local.numel() > 0: | |
| new_summaries = backbone.index_select(1, boundary_local) # [B, k, d] | |
| refined_new = self._refine_cached( | |
| new_summaries, total_steps, cache, seg_offset=prior_segs | |
| ) | |
| if prior is None: | |
| cache.seg_refined = refined_new | |
| else: | |
| cache.seg_refined = torch.cat([prior, refined_new], dim=1) | |
| # Per-token previous-block context (refined[block-1] / start_ctx). | |
| block_of = torch.div(abs_pos, Lb, rounding_mode="floor") | |
| prev_block = block_of - 1 | |
| start = self.start_ctx.to(dtype=e0.dtype).view(1, 1, dim).expand(bsz, m, dim) | |
| seg_refined = getattr(cache, "seg_refined", None) | |
| if seg_refined is not None: | |
| idx = prev_block.clamp(min=0).view(1, m, 1).expand(bsz, m, dim) | |
| gathered = torch.gather(seg_refined, 1, idx) | |
| else: | |
| gathered = start | |
| use_prev = (prev_block >= 0).view(1, m, 1) | |
| ctx = torch.where(use_prev, gathered, start) | |
| h = e0 + self.ctx_proj(ctx) | |
| for i, layer in enumerate(self.local): | |
| h = layer( | |
| h, | |
| attn_mask=None, | |
| cache=cache.mamba_cache(f"seg.local.{i}"), | |
| ) | |
| info = { | |
| "steps_used": total_steps, | |
| "ponder_cost": e0.new_tensor(0.0), | |
| "global_semantic": backbone.mean(dim=1), | |
| } | |
| return h, info | |
| def _refine_cached(self, summaries, total_steps, cache, seg_offset): | |
| bsz, k, _ = summaries.shape | |
| device = summaries.device | |
| seg_wp = torch.arange( | |
| seg_offset, seg_offset + k, device=device | |
| ).unsqueeze(0).expand(bsz, k) | |
| seg_md = torch.zeros(bsz, k, dtype=torch.long, device=device) | |
| def key(step: int, li: int) -> str: | |
| return f"seg.rdt.s{step}.l{li}" | |
| if self.drift_mode == "mhc": | |
| streams = summaries.unsqueeze(-2).expand( | |
| -1, -1, self.n_streams, -1 | |
| ).contiguous() | |
| for step in range(total_steps): | |
| for li, layer in enumerate(self.stage2): | |
| streams = layer( | |
| streams, | |
| word_pos=seg_wp, | |
| morph_depth=seg_md, | |
| attn_mask=None, | |
| causal=True, | |
| cache=cache.mla_cache(key(step, li)), | |
| pos_offset=seg_offset, | |
| ) | |
| return streams.mean(dim=-2) | |
| inject = self.drift_mode in {"decay", "both"} | |
| h = summaries | |
| for step in range(total_steps): | |
| if inject: | |
| scale = self.inject_scale * (self.inject_decay ** step) | |
| h = h + scale * summaries | |
| for li, layer in enumerate(self.stage2): | |
| h = layer( | |
| h, | |
| word_pos=seg_wp, | |
| morph_depth=seg_md, | |
| attn_mask=None, | |
| causal=True, | |
| cache=cache.mla_cache(key(step, li)), | |
| pos_offset=seg_offset, | |
| ) | |
| if self.boundary_norm is not None: | |
| h = self.boundary_norm(h) | |
| return h | |
| # ------------------------------------------------------------------ | |
| # Stage helpers | |
| # ------------------------------------------------------------------ | |
| def _run_stage1(self, x, word_pos, morph_depth, attn_mask, causal): | |
| for layer in self.stage1: | |
| x = self._maybe_ckpt( | |
| layer, | |
| x, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=attn_mask, | |
| causal=causal, | |
| enabled=self.grad_ckpt_stage1, | |
| ) | |
| return x | |
| def _run_local(self, x, word_pos, morph_depth, attn_mask, causal): | |
| for layer in self.local: | |
| x = self._maybe_ckpt( | |
| layer, | |
| x, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=attn_mask, | |
| causal=causal, | |
| enabled=self.grad_ckpt_local, | |
| ) | |
| return x | |
| def _refine(self, summaries, word_pos, morph_depth, total_steps, bptt_window): | |
| if bptt_window is not None: | |
| if bptt_window <= 0: | |
| raise ValueError("bptt_window must be positive") | |
| bptt_window = min(bptt_window, total_steps) | |
| if self.drift_mode == "mhc": | |
| streams = summaries.unsqueeze(-2).expand( | |
| -1, -1, self.n_streams, -1 | |
| ).contiguous() | |
| for step in range(total_steps): | |
| if bptt_window is not None and step < total_steps - bptt_window: | |
| streams = streams.detach() | |
| for layer in self.stage2: | |
| streams = self._maybe_ckpt( | |
| layer, | |
| streams, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=None, | |
| causal=True, | |
| enabled=self.grad_ckpt_stage2, | |
| ) | |
| return streams.mean(dim=-2) | |
| inject = self.drift_mode in {"decay", "both"} | |
| h = summaries | |
| for step in range(total_steps): | |
| if bptt_window is not None and step < total_steps - bptt_window: | |
| h = h.detach() | |
| if inject: | |
| scale = self.inject_scale * (self.inject_decay ** step) | |
| h = h + scale * summaries | |
| for layer in self.stage2: | |
| h = self._maybe_ckpt( | |
| layer, | |
| h, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=None, | |
| causal=True, | |
| enabled=self.grad_ckpt_stage2, | |
| ) | |
| if self.boundary_norm is not None: | |
| h = self.boundary_norm(h) | |
| return h | |
| def _scatter_prev_context(self, refined: torch.Tensor, seq_len: int) -> torch.Tensor: | |
| """Map each token to its *previous* block's refined summary. | |
| Token at position ``t`` (block ``s = t // L_B``) receives ``refined[s-1]``; | |
| block ``0`` receives the learned ``start_ctx``. ``refined[s-1]`` depends | |
| only on tokens ``< s*L_B <= t`` so this is strictly causal. | |
| """ | |
| bsz, n_seg, dim = refined.shape | |
| device = refined.device | |
| seg_of_token = ( | |
| torch.arange(seq_len, device=device) // self.segment_len | |
| ) # [L], in [0, n_seg-1] | |
| prev_seg = seg_of_token - 1 # -1 for block 0 | |
| start = self.start_ctx.to(dtype=refined.dtype).view(1, 1, dim).expand( | |
| bsz, seq_len, dim | |
| ) | |
| gather_idx = prev_seg.clamp(min=0).view(1, seq_len, 1).expand(bsz, seq_len, dim) | |
| gathered = torch.gather(refined, 1, gather_idx) # [B, L, d] | |
| use_prev = (prev_seg >= 0).view(1, seq_len, 1) | |
| return torch.where(use_prev, gathered, start) | |
| def _boundary_indices(self, seq_len: int, device) -> torch.Tensor: | |
| if seq_len <= self.segment_len: | |
| return torch.tensor([seq_len - 1], device=device) | |
| last = torch.arange( | |
| self.segment_len - 1, seq_len, self.segment_len, device=device | |
| ) | |
| if last.numel() == 0 or last[-1].item() != seq_len - 1: | |
| last = torch.cat( | |
| [last, torch.tensor([seq_len - 1], device=device)] | |
| ) | |
| return last | |
| def _resolve_steps(self, steps: int | None) -> int: | |
| if steps is not None: | |
| total = int(steps) | |
| elif self.random_r and self.training: | |
| total = int(torch.randint(self.r_min, self.r_max + 1, (1,)).item()) | |
| else: | |
| total = int(self.cfg.recurrent_steps) | |
| if total <= 0: | |
| raise ValueError("steps must be positive") | |
| return total | |
| def _global_semantic(backbone, attn_mask): | |
| if attn_mask is None: | |
| return backbone.mean(dim=1) | |
| mask = attn_mask.to(dtype=backbone.dtype).unsqueeze(-1) | |
| denom = mask.sum(dim=1).clamp(min=1.0) | |
| return (backbone * mask).sum(dim=1) / denom | |
| def _maybe_ckpt(self, layer, x, word_pos, morph_depth, attn_mask, causal, enabled): | |
| if enabled and self.training and x.requires_grad: | |
| def _fn(x_in): | |
| return layer( | |
| x_in, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=attn_mask, | |
| causal=causal, | |
| ) | |
| return checkpoint(_fn, x, use_reentrant=False) | |
| return layer( | |
| x, | |
| word_pos=word_pos, | |
| morph_depth=morph_depth, | |
| attn_mask=attn_mask, | |
| causal=causal, | |
| ) | |
| def _check_inputs(self, e0, word_pos, morph_depth, attn_mask) -> None: | |
| if e0.ndim != 3: | |
| raise ValueError("e0 must have shape [B, L, d_model]") | |
| bsz, seq_len, dim = e0.shape | |
| if dim != self.cfg.d_model: | |
| raise ValueError(f"expected d_model={self.cfg.d_model}, got {dim}") | |
| if word_pos is not None and word_pos.shape != (bsz, seq_len): | |
| raise ValueError("word_pos must have shape [B, L]") | |
| if morph_depth is not None and morph_depth.shape != (bsz, seq_len): | |
| raise ValueError("morph_depth must have shape [B, L]") | |
| if attn_mask is not None and attn_mask.shape != (bsz, seq_len): | |
| raise ValueError("attn_mask must have shape [B, L]") | |