Text Generation
Transformers
Safetensors
matilda-platypus
matilda
platypus
representation-bridge
qwen3
base-model
custom_code
Instructions to use Maincode/Matilda-Platypus-6B-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Maincode/Matilda-Platypus-6B-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Maincode/Matilda-Platypus-6B-Base", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Maincode/Matilda-Platypus-6B-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Maincode/Matilda-Platypus-6B-Base with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Maincode/Matilda-Platypus-6B-Base" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Maincode/Matilda-Platypus-6B-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/Maincode/Matilda-Platypus-6B-Base
- SGLang
How to use Maincode/Matilda-Platypus-6B-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 "Maincode/Matilda-Platypus-6B-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": "Maincode/Matilda-Platypus-6B-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 "Maincode/Matilda-Platypus-6B-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": "Maincode/Matilda-Platypus-6B-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use Maincode/Matilda-Platypus-6B-Base with Docker Model Runner:
docker model run hf.co/Maincode/Matilda-Platypus-6B-Base
File size: 17,976 Bytes
50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf 50731ef 9ef97cf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | """Matilda Platypus: lower block of a larger Qwen3 parent -> Representation Bridge -> upper block of a smaller parent.
Self-contained: the two blocks are ordinary Hugging Face Qwen3 checkpoints run through their public forward passes
(the lower one truncated to its first k layers with its final norm removed, the upper one starting at layer j with
`inputs_embeds`), so no custom kernels are involved. `generate` keeps one KV cache per block and follows the standard
`transformers` keyword arguments (`max_new_tokens` / `max_length`, `stopping_criteria`, `logits_processor`, sampling
knobs, `eos_token_id` / `pad_token_id`, `streamer`), so it runs unchanged under evaluation harnesses such as
lm-eval-harness (`--model hf --model_args pretrained=...,trust_remote_code=True`). Greedy and sampling only; beam
search is not implemented and raises.
from transformers import AutoModelForCausalLM, AutoTokenizer
tok = AutoTokenizer.from_pretrained("Maincode/Matilda-Platypus-7B-Base")
model = AutoModelForCausalLM.from_pretrained("Maincode/Matilda-Platypus-7B-Base", trust_remote_code=True,
dtype=torch.bfloat16).cuda()
out = model.generate(**tok("The capital of Australia is", return_tensors="pt").to("cuda"), max_new_tokens=32)
Remote-code revision 2 (2026-10-31): `generate` honours `max_length`, `stopping_criteria`, `logits_processor`,
`min_new_tokens`, `top_k`, `repetition_penalty`, list-valued `eos_token_id`, `generation_config` and `streamer`, and
warns instead of silently ignoring unknown arguments; `tie_weights()` is a no-op at the top level (the lower block's
4096-d embedding and the upper block's 2560-d head must never be tied, and each parent was already tied on load).
Revision 1 ignored `max_length` and `stopping_criteria` (it always produced its default of 128 new tokens), which
truncated chain-of-thought answers under lm-eval and under-reported generative benchmarks.
"""
from __future__ import annotations
import os
import warnings
from typing import Optional, Sequence, Tuple, Union
import torch
import torch.nn as nn
from safetensors.torch import load_file
from transformers import AutoModelForCausalLM, PreTrainedModel
from transformers.cache_utils import DynamicCache
from transformers.modeling_outputs import CausalLMOutputWithPast
from .configuration_platypus import MatildaPlatypusConfig
REMOTE_CODE_REVISION = 2
_DEFAULT_NEW_TOKENS = 128 # used only when neither max_new_tokens, max_length nor a generation_config gives a budget
# generate() arguments that would change the result if ignored -> refuse loudly instead of pretending
_UNSUPPORTED_GENERATE_KWARGS = ("prefix_allowed_tokens_fn", "bad_words_ids", "force_words_ids", "suppress_tokens",
"begin_suppress_tokens", "forced_bos_token_id", "forced_eos_token_id", "constraints",
"assistant_model", "guidance_scale", "penalty_alpha", "num_beam_groups",
"diversity_penalty", "exponential_decay_length_penalty", "sequence_bias",
"no_repeat_ngram_size", "encoder_repetition_penalty", "typical_p", "epsilon_cutoff",
"eta_cutoff", "renormalize_logits", "token_healing", "dola_layers", "watermarking_config")
# generate() arguments that are safe to accept and ignore
_IGNORED_GENERATE_KWARGS = ("use_cache", "synced_gpus", "output_attentions", "output_hidden_states", "output_scores",
"output_logits", "return_legacy_cache", "cache_implementation", "cache_config",
"compile_config", "disable_compile", "negative_prompt_ids", "negative_prompt_attention_mask",
"kwargs", "tokenizer", "position_ids", "cache_position", "token_type_ids")
class RepresentationBridge(nn.Module):
"""y = W x + b on the residual stream, computed in float32 (W: [d_upper, d_lower])."""
def __init__(self, d_lower: int, d_upper: int):
super().__init__()
self.proj = nn.Linear(d_lower, d_upper, bias=True)
def forward(self, x: torch.Tensor) -> torch.Tensor:
with torch.autocast(device_type=x.device.type, enabled=False):
return self.proj(x.float())
class MatildaPlatypusForCausalLM(PreTrainedModel):
config_class = MatildaPlatypusConfig
main_input_name = "input_ids"
_supports_cache_class = True
_tied_weights_keys = None # nothing is tied across the two blocks (see tie_weights)
def __init__(self, config: MatildaPlatypusConfig, lower: Optional[PreTrainedModel] = None,
upper: Optional[PreTrainedModel] = None, bridge: Optional[RepresentationBridge] = None):
super().__init__(config)
self.lower, self.upper, self.bridge = lower, upper, bridge
@classmethod
def can_generate(cls) -> bool: # text-generation pipelines ask this before calling .generate()
return True
# ------------------------------------------------------------------ loading
@classmethod
def from_pretrained(cls, pretrained_model_name_or_path, *args, dtype=None, torch_dtype=None, token=None,
revision=None, device_map=None, **kwargs):
from huggingface_hub import snapshot_download
path = str(pretrained_model_name_or_path)
local = path if os.path.isdir(path) else snapshot_download(path, token=token, revision=revision)
config = MatildaPlatypusConfig.from_pretrained(local)
dt = dtype or torch_dtype or torch.bfloat16
lower_src = os.path.join(local, config.lower_model) if os.path.isdir(os.path.join(local, config.lower_model)) else config.lower_model
lower = AutoModelForCausalLM.from_pretrained(lower_src, dtype=dt, token=token)
upper = AutoModelForCausalLM.from_pretrained(os.path.join(local, config.upper_model), dtype=dt)
k, j, m = config.lower_layers, config.upper_start_layer, config.upper_layers
# lower block: first k decoder layers, no final norm (the bridge takes the raw residual stream)
lower.model.layers = nn.ModuleList(list(lower.model.layers)[:k])
lower.model.norm = nn.Identity()
lower.config.num_hidden_layers = k
if getattr(lower.config, "layer_types", None):
lower.config.layer_types = list(lower.config.layer_types)[:k]
lower.lm_head = nn.Identity()
# upper block: layers j.. of the smaller parent, re-indexed so a fresh KV cache is contiguous
layers = list(upper.model.layers)[j:j + m]
for n, layer in enumerate(layers):
if hasattr(layer, "self_attn"):
layer.self_attn.layer_idx = n
if hasattr(layer, "layer_idx"):
layer.layer_idx = n
upper.model.layers = nn.ModuleList(layers)
upper.config.num_hidden_layers = m
if getattr(upper.config, "layer_types", None):
upper.config.layer_types = list(upper.config.layer_types)[j:j + m]
upper.model.embed_tokens = nn.Identity() # the upper block never embeds tokens
bridge = RepresentationBridge(config.lower_hidden_size, config.upper_hidden_size)
t = load_file(os.path.join(local, config.bridge_file))
bridge.proj.weight.data.copy_(t["W"].float()); bridge.proj.bias.data.copy_(t["b"].float())
for p in lower.parameters():
p.requires_grad_(False)
# context length = the shorter of the two parents (harnesses read this to size their prompts)
mp = [getattr(c, "max_position_embeddings", None) for c in (lower.config, upper.config)]
mp = [x for x in mp if isinstance(x, int)]
if mp and getattr(config, "max_position_embeddings", None) is None:
config.max_position_embeddings = min(mp)
config.tie_word_embeddings = False
model = cls(config, lower, upper, bridge).eval()
if device_map is not None and isinstance(device_map, (str, torch.device)) and device_map != "auto":
model.to(device_map)
return model
# ------------------------------------------------------------------ weight tying: never across blocks
def tie_weights(self, *args, **kwargs) -> None:
"""No-op. The lower block's input embedding (d_lower) and the upper block's output head (d_upper) have
different widths and must never be tied; each parent block was already tied (if its config says so) when
it was loaded, and the upper block's token embedding has since been replaced, so re-tying would fail."""
return None
def tie_embeddings_and_encoder_decoder(self) -> None: # transformers 4.x entry point
return None
# ------------------------------------------------------------------ forward
@property
def dtype(self) -> torch.dtype:
return self.upper.lm_head.weight.dtype
def get_input_embeddings(self):
return self.lower.model.embed_tokens
def get_output_embeddings(self):
return self.upper.lm_head
def forward(self, input_ids: torch.LongTensor, attention_mask: Optional[torch.Tensor] = None,
past_key_values: Optional[Tuple[DynamicCache, DynamicCache]] = None, use_cache: bool = False,
**kwargs) -> CausalLMOutputWithPast:
cl, cu = past_key_values if past_key_values is not None else (None, None)
if use_cache and cl is None:
cl, cu = DynamicCache(), DynamicCache()
lo = self.lower.model(input_ids=input_ids, attention_mask=attention_mask, past_key_values=cl, use_cache=use_cache)
h = self.bridge(lo.last_hidden_state).to(self.dtype)
up = self.upper.model(inputs_embeds=h, attention_mask=attention_mask, past_key_values=cu, use_cache=use_cache)
logits = self.upper.lm_head(up.last_hidden_state)
return CausalLMOutputWithPast(logits=logits, past_key_values=(cl, cu) if use_cache else None)
# ------------------------------------------------------------------ generation
def _default_eos(self) -> Optional[Union[int, Sequence[int]]]:
gc = getattr(self.upper, "generation_config", None)
eos = getattr(gc, "eos_token_id", None) if gc is not None else None
return eos if eos is not None else getattr(self.upper.config, "eos_token_id", None)
@torch.no_grad()
def generate(self, input_ids: Optional[torch.LongTensor] = None, attention_mask: Optional[torch.Tensor] = None, *,
inputs: Optional[torch.LongTensor] = None, generation_config=None,
max_new_tokens: Optional[int] = None, max_length: Optional[int] = None,
min_new_tokens: Optional[int] = None, do_sample: Optional[bool] = None,
temperature: Optional[float] = None, top_k: Optional[int] = None, top_p: Optional[float] = None,
repetition_penalty: Optional[float] = None,
eos_token_id: Optional[Union[int, Sequence[int]]] = None, pad_token_id: Optional[int] = None,
stopping_criteria=None, logits_processor=None, streamer=None,
num_beams: int = 1, num_return_sequences: int = 1, return_dict_in_generate: bool = False,
**kwargs) -> torch.LongTensor:
"""Greedy or sampled decoding with one KV cache per block, following the `transformers.generate` contract.
Budget: `max_new_tokens` > `max_length` (total length, prompt included) > `generation_config.max_new_tokens`
> 128. A row stops at any `eos_token_id` (int or list), when `stopping_criteria` says so, or at the budget;
finished rows are padded with `pad_token_id`. `logits_processor` (a `LogitsProcessorList`) is applied before
sampling. Beam search and `num_return_sequences > 1` are not implemented.
"""
if input_ids is None:
input_ids = inputs
if input_ids is None:
raise ValueError("generate() needs `input_ids` (or `inputs`)")
if num_beams != 1 or num_return_sequences != 1:
raise NotImplementedError("Matilda Platypus implements greedy and sampled decoding only "
"(num_beams=1, num_return_sequences=1)")
bad = [k for k in _UNSUPPORTED_GENERATE_KWARGS if kwargs.get(k) not in (None, False, [], 1.0, 0)]
if bad:
raise NotImplementedError(f"generate() arguments not supported by Matilda Platypus: {bad}")
unknown = sorted(k for k in kwargs if k not in _UNSUPPORTED_GENERATE_KWARGS and k not in _IGNORED_GENERATE_KWARGS)
if unknown:
warnings.warn(f"MatildaPlatypusForCausalLM.generate() is ignoring unrecognised arguments: {unknown}",
stacklevel=2)
gc = generation_config
def pick(name, value, default):
if value is not None:
return value
v = getattr(gc, name, None) if gc is not None else None
return default if v is None else v
device = self.device
input_ids = input_ids.to(device)
batch, prompt_len = input_ids.shape
if attention_mask is None:
attention_mask = torch.ones_like(input_ids)
attention_mask = attention_mask.to(device)
# ---- budget
if max_new_tokens is None and max_length is not None:
budget = int(max_length) - prompt_len
else:
if max_new_tokens is not None and max_length is not None:
warnings.warn("Both `max_new_tokens` and `max_length` were given; `max_new_tokens` takes precedence.",
stacklevel=2)
budget = pick("max_new_tokens", max_new_tokens, None)
if budget is None:
budget = _DEFAULT_NEW_TOKENS
budget = int(budget)
if budget <= 0:
warnings.warn(f"generate(): the prompt ({prompt_len} tokens) already fills the requested length; "
"returning the prompt unchanged.", stacklevel=2)
return self._wrap(input_ids, return_dict_in_generate)
min_new = int(pick("min_new_tokens", min_new_tokens, 0) or 0)
# ---- special tokens
eos = pick("eos_token_id", eos_token_id, None)
if eos is None:
eos = self._default_eos()
eos_list = [int(e) for e in (eos if isinstance(eos, (list, tuple)) else ([] if eos is None else [eos]))]
eos_t = torch.tensor(eos_list, device=device, dtype=input_ids.dtype) if eos_list else None
pad = pick("pad_token_id", pad_token_id, None)
if pad is None:
pad = getattr(self.upper.config, "pad_token_id", None)
if pad is None:
pad = eos_list[0] if eos_list else 0
pad = int(pad)
# ---- sampling knobs (greedy unless do_sample)
sample = bool(pick("do_sample", do_sample, False))
temp = float(pick("temperature", temperature, 1.0))
tk = pick("top_k", top_k, None)
tp = float(pick("top_p", top_p, 1.0))
rep = float(pick("repetition_penalty", repetition_penalty, 1.0))
if streamer is not None and batch == 1:
streamer.put(input_ids.cpu())
out = self.forward(input_ids, attention_mask=attention_mask, use_cache=True)
caches = out.past_key_values
seq = input_ids
done = torch.zeros(batch, dtype=torch.bool, device=device)
for step in range(budget):
logits = out.logits[:, -1, :].float()
if rep != 1.0:
prev = torch.gather(logits, 1, seq)
prev = torch.where(prev < 0, prev * rep, prev / rep)
logits = logits.scatter(1, seq, prev)
if logits_processor is not None:
logits = logits_processor(seq, logits)
if step < min_new and eos_t is not None:
logits[:, eos_t] = float("-inf")
if sample:
logits = logits / max(temp, 1e-5)
if tk is not None and 0 < int(tk) < logits.shape[-1]:
kth = torch.topk(logits, int(tk), dim=-1).values[:, -1, None]
logits = logits.masked_fill(logits < kth, float("-inf"))
if tp < 1.0:
sorted_logits, idx = torch.sort(logits, descending=True)
probs = torch.softmax(sorted_logits, dim=-1)
keep = probs.cumsum(-1) - probs < tp
sorted_logits[~keep] = float("-inf")
logits = torch.full_like(logits, float("-inf")).scatter(1, idx, sorted_logits)
nxt = torch.multinomial(torch.softmax(logits, dim=-1), 1).squeeze(1)
else:
nxt = logits.argmax(-1)
nxt = torch.where(done, torch.full_like(nxt, pad), nxt)
seq = torch.cat([seq, nxt[:, None]], dim=1)
attention_mask = torch.cat([attention_mask, torch.ones_like(nxt[:, None])], dim=1)
if streamer is not None and batch == 1:
streamer.put(nxt.cpu())
if eos_t is not None:
done |= torch.isin(nxt, eos_t)
if stopping_criteria is not None:
flag = stopping_criteria(seq, logits)
flag = torch.as_tensor(flag, device=device).to(torch.bool)
done |= flag if flag.dim() else flag.expand(batch)
if bool(done.all()):
break
out = self.forward(nxt[:, None], attention_mask=attention_mask, past_key_values=caches, use_cache=True)
if streamer is not None:
streamer.end()
return self._wrap(seq, return_dict_in_generate)
@staticmethod
def _wrap(seq: torch.LongTensor, return_dict: bool):
if not return_dict:
return seq
try:
from transformers.generation.utils import GenerateDecoderOnlyOutput
return GenerateDecoderOnlyOutput(sequences=seq)
except Exception: # pragma: no cover - very old/new transformers without that class
return seq
|