Text Generation
Transformers
Safetensors
matilda-platypus
matilda
platypus
representation-bridge
qwen3
base-model
custom_code
Instructions to use Maincode/Matilda-Platypus-11B-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Maincode/Matilda-Platypus-11B-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Maincode/Matilda-Platypus-11B-Base", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Maincode/Matilda-Platypus-11B-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Maincode/Matilda-Platypus-11B-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-11B-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-11B-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/Maincode/Matilda-Platypus-11B-Base
- SGLang
How to use Maincode/Matilda-Platypus-11B-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-11B-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-11B-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-11B-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-11B-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use Maincode/Matilda-Platypus-11B-Base with Docker Model Runner:
docker model run hf.co/Maincode/Matilda-Platypus-11B-Base
Remote code revision 2: generate() honours max_length / stopping_criteria / logits_processor and the other standard transformers arguments (revision 1 always produced 128 new tokens, truncating CoT under lm-eval); tie_weights() is a no-op at the top level; card documents the change. Weights unchanged.
Browse files- README.md +10 -6
- configuration_platypus.py +8 -1
- modeling_platypus.py +181 -24
README.md
CHANGED
|
@@ -12,9 +12,6 @@ tags:
|
|
| 12 |
- qwen3
|
| 13 |
- base-model
|
| 14 |
---
|
| 15 |
-
|
| 16 |
-

|
| 17 |
-
|
| 18 |
# Matilda Platypus 11B (base)
|
| 19 |
|
| 20 |
**Any size you want.** Matilda Platypus is a family of intermediate-size language models built by connecting the lower
|
|
@@ -79,7 +76,7 @@ import torch
|
|
| 79 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 80 |
|
| 81 |
repo = "Maincode/Matilda-Platypus-11B-Base"
|
| 82 |
-
tok = AutoTokenizer.from_pretrained(repo)
|
| 83 |
model = AutoModelForCausalLM.from_pretrained(repo, trust_remote_code=True, dtype=torch.bfloat16).cuda()
|
| 84 |
inputs = tok("The capital of Australia is", return_tensors="pt").to("cuda")
|
| 85 |
out = model.generate(**inputs, max_new_tokens=32)
|
|
@@ -88,8 +85,15 @@ print(tok.decode(out[0], skip_special_tokens=True))
|
|
| 88 |
|
| 89 |
The remote code loads the lower block from `Qwen/Qwen3-14B-Base`, the upper
|
| 90 |
block from `upper_block/` and the bridge from `bridge.safetensors`, truncates both parents to the retained layers and
|
| 91 |
-
runs them through their standard `transformers` forward passes with one KV cache per block. `generate`
|
| 92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
## Limitations
|
| 95 |
|
|
|
|
| 12 |
- qwen3
|
| 13 |
- base-model
|
| 14 |
---
|
|
|
|
|
|
|
|
|
|
| 15 |
# Matilda Platypus 11B (base)
|
| 16 |
|
| 17 |
**Any size you want.** Matilda Platypus is a family of intermediate-size language models built by connecting the lower
|
|
|
|
| 76 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 77 |
|
| 78 |
repo = "Maincode/Matilda-Platypus-11B-Base"
|
| 79 |
+
tok = AutoTokenizer.from_pretrained(repo, trust_remote_code=True)
|
| 80 |
model = AutoModelForCausalLM.from_pretrained(repo, trust_remote_code=True, dtype=torch.bfloat16).cuda()
|
| 81 |
inputs = tok("The capital of Australia is", return_tensors="pt").to("cuda")
|
| 82 |
out = model.generate(**inputs, max_new_tokens=32)
|
|
|
|
| 85 |
|
| 86 |
The remote code loads the lower block from `Qwen/Qwen3-14B-Base`, the upper
|
| 87 |
block from `upper_block/` and the bridge from `bridge.safetensors`, truncates both parents to the retained layers and
|
| 88 |
+
runs them through their standard `transformers` forward passes with one KV cache per block. `generate` follows the
|
| 89 |
+
standard `transformers` keyword arguments (`max_new_tokens` / `max_length`, `min_new_tokens`, `stopping_criteria`,
|
| 90 |
+
`logits_processor`, `do_sample`, `temperature`, `top_k`, `top_p`, `repetition_penalty`, `eos_token_id`, `pad_token_id`,
|
| 91 |
+
`streamer`), so the model runs unchanged under lm-eval-harness (`--model hf --model_args pretrained=Maincode/Matilda-Platypus-11B-Base,trust_remote_code=True`).
|
| 92 |
+
Greedy and sampled decoding only; beam search raises `NotImplementedError`. Requires `transformers >= 4.56` (tested on 4.56 and 5.x).
|
| 93 |
+
|
| 94 |
+
Remote-code revision 2 (2026-10-31): revision 1 ignored `max_length` and `stopping_criteria` and always produced 128 new
|
| 95 |
+
tokens, which truncated chain-of-thought answers under lm-eval and under-reported generative benchmarks (GSM8K read ~0.58
|
| 96 |
+
instead of the table value); `tie_weights()` is now a no-op at the top level. Model weights are unchanged.
|
| 97 |
|
| 98 |
## Limitations
|
| 99 |
|
configuration_platypus.py
CHANGED
|
@@ -9,7 +9,8 @@ class MatildaPlatypusConfig(PretrainedConfig):
|
|
| 9 |
|
| 10 |
def __init__(self, lower_model="Qwen/Qwen3-8B-Base", lower_layers=25, upper_model="upper_block",
|
| 11 |
upper_start_layer=25, upper_layers=11, bridge_file="bridge.safetensors",
|
| 12 |
-
lower_hidden_size=4096, upper_hidden_size=2560, vocab_size=151936,
|
|
|
|
| 13 |
self.lower_model = lower_model # hub id, or a sub-folder of this repo
|
| 14 |
self.lower_layers = lower_layers # k: decoder layers kept from the larger parent (layers 1..k)
|
| 15 |
self.upper_model = upper_model # sub-folder holding the adapted smaller parent (HF checkpoint)
|
|
@@ -19,4 +20,10 @@ class MatildaPlatypusConfig(PretrainedConfig):
|
|
| 19 |
self.lower_hidden_size = lower_hidden_size
|
| 20 |
self.upper_hidden_size = upper_hidden_size
|
| 21 |
self.vocab_size = vocab_size
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
super().__init__(**kwargs)
|
|
|
|
| 9 |
|
| 10 |
def __init__(self, lower_model="Qwen/Qwen3-8B-Base", lower_layers=25, upper_model="upper_block",
|
| 11 |
upper_start_layer=25, upper_layers=11, bridge_file="bridge.safetensors",
|
| 12 |
+
lower_hidden_size=4096, upper_hidden_size=2560, vocab_size=151936,
|
| 13 |
+
max_position_embeddings=None, **kwargs):
|
| 14 |
self.lower_model = lower_model # hub id, or a sub-folder of this repo
|
| 15 |
self.lower_layers = lower_layers # k: decoder layers kept from the larger parent (layers 1..k)
|
| 16 |
self.upper_model = upper_model # sub-folder holding the adapted smaller parent (HF checkpoint)
|
|
|
|
| 20 |
self.lower_hidden_size = lower_hidden_size
|
| 21 |
self.upper_hidden_size = upper_hidden_size
|
| 22 |
self.vocab_size = vocab_size
|
| 23 |
+
# context length; filled in from the parents at load time when not given (harnesses read it)
|
| 24 |
+
self.max_position_embeddings = max_position_embeddings
|
| 25 |
+
# The lower block's embedding (d_lower) and the upper block's output head (d_upper) differ in width and are
|
| 26 |
+
# never tied; PretrainedConfig would otherwise default this to True and generic tie_weights() calls would
|
| 27 |
+
# try to tie them.
|
| 28 |
+
kwargs.setdefault("tie_word_embeddings", False)
|
| 29 |
super().__init__(**kwargs)
|
modeling_platypus.py
CHANGED
|
@@ -2,18 +2,30 @@
|
|
| 2 |
|
| 3 |
Self-contained: the two blocks are ordinary Hugging Face Qwen3 checkpoints run through their public forward passes
|
| 4 |
(the lower one truncated to its first k layers with its final norm removed, the upper one starting at layer j with
|
| 5 |
-
`inputs_embeds`), so no custom kernels are involved. `generate` keeps one KV cache per block
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 8 |
-
tok = AutoTokenizer.from_pretrained("
|
| 9 |
-
model = AutoModelForCausalLM.from_pretrained("
|
| 10 |
dtype=torch.bfloat16).cuda()
|
| 11 |
out = model.generate(**tok("The capital of Australia is", return_tensors="pt").to("cuda"), max_new_tokens=32)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
"""
|
| 13 |
from __future__ import annotations
|
| 14 |
|
| 15 |
import os
|
| 16 |
-
|
|
|
|
| 17 |
|
| 18 |
import torch
|
| 19 |
import torch.nn as nn
|
|
@@ -24,6 +36,22 @@ from transformers.modeling_outputs import CausalLMOutputWithPast
|
|
| 24 |
|
| 25 |
from .configuration_platypus import MatildaPlatypusConfig
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
class RepresentationBridge(nn.Module):
|
| 29 |
"""y = W x + b on the residual stream, computed in float32 (W: [d_upper, d_lower])."""
|
|
@@ -39,13 +67,19 @@ class RepresentationBridge(nn.Module):
|
|
| 39 |
|
| 40 |
class MatildaPlatypusForCausalLM(PreTrainedModel):
|
| 41 |
config_class = MatildaPlatypusConfig
|
|
|
|
| 42 |
_supports_cache_class = True
|
|
|
|
| 43 |
|
| 44 |
def __init__(self, config: MatildaPlatypusConfig, lower: Optional[PreTrainedModel] = None,
|
| 45 |
upper: Optional[PreTrainedModel] = None, bridge: Optional[RepresentationBridge] = None):
|
| 46 |
super().__init__(config)
|
| 47 |
self.lower, self.upper, self.bridge = lower, upper, bridge
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
# ------------------------------------------------------------------ loading
|
| 50 |
@classmethod
|
| 51 |
def from_pretrained(cls, pretrained_model_name_or_path, *args, dtype=None, torch_dtype=None, token=None,
|
|
@@ -83,11 +117,27 @@ class MatildaPlatypusForCausalLM(PreTrainedModel):
|
|
| 83 |
bridge.proj.weight.data.copy_(t["W"].float()); bridge.proj.bias.data.copy_(t["b"].float())
|
| 84 |
for p in lower.parameters():
|
| 85 |
p.requires_grad_(False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
model = cls(config, lower, upper, bridge).eval()
|
| 87 |
if device_map is not None and isinstance(device_map, (str, torch.device)) and device_map != "auto":
|
| 88 |
model.to(device_map)
|
| 89 |
return model
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
# ------------------------------------------------------------------ forward
|
| 92 |
@property
|
| 93 |
def dtype(self) -> torch.dtype:
|
|
@@ -112,42 +162,149 @@ class MatildaPlatypusForCausalLM(PreTrainedModel):
|
|
| 112 |
return CausalLMOutputWithPast(logits=logits, past_key_values=(cl, cu) if use_cache else None)
|
| 113 |
|
| 114 |
# ------------------------------------------------------------------ generation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
@torch.no_grad()
|
| 116 |
-
def generate(self, input_ids: torch.LongTensor, attention_mask: Optional[torch.Tensor] = None,
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
if attention_mask is None:
|
| 128 |
attention_mask = torch.ones_like(input_ids)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
out = self.forward(input_ids, attention_mask=attention_mask, use_cache=True)
|
| 130 |
caches = out.past_key_values
|
| 131 |
seq = input_ids
|
| 132 |
-
done = torch.zeros(
|
| 133 |
-
for
|
| 134 |
logits = out.logits[:, -1, :].float()
|
| 135 |
-
if
|
| 136 |
-
|
| 137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
sorted_logits, idx = torch.sort(logits, descending=True)
|
| 139 |
probs = torch.softmax(sorted_logits, dim=-1)
|
| 140 |
-
keep = probs.cumsum(-1) - probs <
|
| 141 |
sorted_logits[~keep] = float("-inf")
|
| 142 |
logits = torch.full_like(logits, float("-inf")).scatter(1, idx, sorted_logits)
|
| 143 |
nxt = torch.multinomial(torch.softmax(logits, dim=-1), 1).squeeze(1)
|
| 144 |
else:
|
| 145 |
nxt = logits.argmax(-1)
|
| 146 |
-
nxt = torch.where(done, torch.full_like(nxt,
|
| 147 |
seq = torch.cat([seq, nxt[:, None]], dim=1)
|
| 148 |
attention_mask = torch.cat([attention_mask, torch.ones_like(nxt[:, None])], dim=1)
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
if bool(done.all()):
|
| 151 |
break
|
| 152 |
out = self.forward(nxt[:, None], attention_mask=attention_mask, past_key_values=caches, use_cache=True)
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
Self-contained: the two blocks are ordinary Hugging Face Qwen3 checkpoints run through their public forward passes
|
| 4 |
(the lower one truncated to its first k layers with its final norm removed, the upper one starting at layer j with
|
| 5 |
+
`inputs_embeds`), so no custom kernels are involved. `generate` keeps one KV cache per block and follows the standard
|
| 6 |
+
`transformers` keyword arguments (`max_new_tokens` / `max_length`, `stopping_criteria`, `logits_processor`, sampling
|
| 7 |
+
knobs, `eos_token_id` / `pad_token_id`, `streamer`), so it runs unchanged under evaluation harnesses such as
|
| 8 |
+
lm-eval-harness (`--model hf --model_args pretrained=...,trust_remote_code=True`). Greedy and sampling only; beam
|
| 9 |
+
search is not implemented and raises.
|
| 10 |
|
| 11 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 12 |
+
tok = AutoTokenizer.from_pretrained("Maincode/Matilda-Platypus-7B-Base")
|
| 13 |
+
model = AutoModelForCausalLM.from_pretrained("Maincode/Matilda-Platypus-7B-Base", trust_remote_code=True,
|
| 14 |
dtype=torch.bfloat16).cuda()
|
| 15 |
out = model.generate(**tok("The capital of Australia is", return_tensors="pt").to("cuda"), max_new_tokens=32)
|
| 16 |
+
|
| 17 |
+
Remote-code revision 2 (2026-10-31): `generate` honours `max_length`, `stopping_criteria`, `logits_processor`,
|
| 18 |
+
`min_new_tokens`, `top_k`, `repetition_penalty`, list-valued `eos_token_id`, `generation_config` and `streamer`, and
|
| 19 |
+
warns instead of silently ignoring unknown arguments; `tie_weights()` is a no-op at the top level (the lower block's
|
| 20 |
+
4096-d embedding and the upper block's 2560-d head must never be tied, and each parent was already tied on load).
|
| 21 |
+
Revision 1 ignored `max_length` and `stopping_criteria` (it always produced its default of 128 new tokens), which
|
| 22 |
+
truncated chain-of-thought answers under lm-eval and under-reported generative benchmarks.
|
| 23 |
"""
|
| 24 |
from __future__ import annotations
|
| 25 |
|
| 26 |
import os
|
| 27 |
+
import warnings
|
| 28 |
+
from typing import Optional, Sequence, Tuple, Union
|
| 29 |
|
| 30 |
import torch
|
| 31 |
import torch.nn as nn
|
|
|
|
| 36 |
|
| 37 |
from .configuration_platypus import MatildaPlatypusConfig
|
| 38 |
|
| 39 |
+
REMOTE_CODE_REVISION = 2
|
| 40 |
+
_DEFAULT_NEW_TOKENS = 128 # used only when neither max_new_tokens, max_length nor a generation_config gives a budget
|
| 41 |
+
|
| 42 |
+
# generate() arguments that would change the result if ignored -> refuse loudly instead of pretending
|
| 43 |
+
_UNSUPPORTED_GENERATE_KWARGS = ("prefix_allowed_tokens_fn", "bad_words_ids", "force_words_ids", "suppress_tokens",
|
| 44 |
+
"begin_suppress_tokens", "forced_bos_token_id", "forced_eos_token_id", "constraints",
|
| 45 |
+
"assistant_model", "guidance_scale", "penalty_alpha", "num_beam_groups",
|
| 46 |
+
"diversity_penalty", "exponential_decay_length_penalty", "sequence_bias",
|
| 47 |
+
"no_repeat_ngram_size", "encoder_repetition_penalty", "typical_p", "epsilon_cutoff",
|
| 48 |
+
"eta_cutoff", "renormalize_logits", "token_healing", "dola_layers", "watermarking_config")
|
| 49 |
+
# generate() arguments that are safe to accept and ignore
|
| 50 |
+
_IGNORED_GENERATE_KWARGS = ("use_cache", "synced_gpus", "output_attentions", "output_hidden_states", "output_scores",
|
| 51 |
+
"output_logits", "return_legacy_cache", "cache_implementation", "cache_config",
|
| 52 |
+
"compile_config", "disable_compile", "negative_prompt_ids", "negative_prompt_attention_mask",
|
| 53 |
+
"kwargs", "tokenizer", "position_ids", "cache_position", "token_type_ids")
|
| 54 |
+
|
| 55 |
|
| 56 |
class RepresentationBridge(nn.Module):
|
| 57 |
"""y = W x + b on the residual stream, computed in float32 (W: [d_upper, d_lower])."""
|
|
|
|
| 67 |
|
| 68 |
class MatildaPlatypusForCausalLM(PreTrainedModel):
|
| 69 |
config_class = MatildaPlatypusConfig
|
| 70 |
+
main_input_name = "input_ids"
|
| 71 |
_supports_cache_class = True
|
| 72 |
+
_tied_weights_keys = None # nothing is tied across the two blocks (see tie_weights)
|
| 73 |
|
| 74 |
def __init__(self, config: MatildaPlatypusConfig, lower: Optional[PreTrainedModel] = None,
|
| 75 |
upper: Optional[PreTrainedModel] = None, bridge: Optional[RepresentationBridge] = None):
|
| 76 |
super().__init__(config)
|
| 77 |
self.lower, self.upper, self.bridge = lower, upper, bridge
|
| 78 |
|
| 79 |
+
@classmethod
|
| 80 |
+
def can_generate(cls) -> bool: # text-generation pipelines ask this before calling .generate()
|
| 81 |
+
return True
|
| 82 |
+
|
| 83 |
# ------------------------------------------------------------------ loading
|
| 84 |
@classmethod
|
| 85 |
def from_pretrained(cls, pretrained_model_name_or_path, *args, dtype=None, torch_dtype=None, token=None,
|
|
|
|
| 117 |
bridge.proj.weight.data.copy_(t["W"].float()); bridge.proj.bias.data.copy_(t["b"].float())
|
| 118 |
for p in lower.parameters():
|
| 119 |
p.requires_grad_(False)
|
| 120 |
+
# context length = the shorter of the two parents (harnesses read this to size their prompts)
|
| 121 |
+
mp = [getattr(c, "max_position_embeddings", None) for c in (lower.config, upper.config)]
|
| 122 |
+
mp = [x for x in mp if isinstance(x, int)]
|
| 123 |
+
if mp and getattr(config, "max_position_embeddings", None) is None:
|
| 124 |
+
config.max_position_embeddings = min(mp)
|
| 125 |
+
config.tie_word_embeddings = False
|
| 126 |
model = cls(config, lower, upper, bridge).eval()
|
| 127 |
if device_map is not None and isinstance(device_map, (str, torch.device)) and device_map != "auto":
|
| 128 |
model.to(device_map)
|
| 129 |
return model
|
| 130 |
|
| 131 |
+
# ------------------------------------------------------------------ weight tying: never across blocks
|
| 132 |
+
def tie_weights(self, *args, **kwargs) -> None:
|
| 133 |
+
"""No-op. The lower block's input embedding (d_lower) and the upper block's output head (d_upper) have
|
| 134 |
+
different widths and must never be tied; each parent block was already tied (if its config says so) when
|
| 135 |
+
it was loaded, and the upper block's token embedding has since been replaced, so re-tying would fail."""
|
| 136 |
+
return None
|
| 137 |
+
|
| 138 |
+
def tie_embeddings_and_encoder_decoder(self) -> None: # transformers 4.x entry point
|
| 139 |
+
return None
|
| 140 |
+
|
| 141 |
# ------------------------------------------------------------------ forward
|
| 142 |
@property
|
| 143 |
def dtype(self) -> torch.dtype:
|
|
|
|
| 162 |
return CausalLMOutputWithPast(logits=logits, past_key_values=(cl, cu) if use_cache else None)
|
| 163 |
|
| 164 |
# ------------------------------------------------------------------ generation
|
| 165 |
+
def _default_eos(self) -> Optional[Union[int, Sequence[int]]]:
|
| 166 |
+
gc = getattr(self.upper, "generation_config", None)
|
| 167 |
+
eos = getattr(gc, "eos_token_id", None) if gc is not None else None
|
| 168 |
+
return eos if eos is not None else getattr(self.upper.config, "eos_token_id", None)
|
| 169 |
+
|
| 170 |
@torch.no_grad()
|
| 171 |
+
def generate(self, input_ids: Optional[torch.LongTensor] = None, attention_mask: Optional[torch.Tensor] = None, *,
|
| 172 |
+
inputs: Optional[torch.LongTensor] = None, generation_config=None,
|
| 173 |
+
max_new_tokens: Optional[int] = None, max_length: Optional[int] = None,
|
| 174 |
+
min_new_tokens: Optional[int] = None, do_sample: Optional[bool] = None,
|
| 175 |
+
temperature: Optional[float] = None, top_k: Optional[int] = None, top_p: Optional[float] = None,
|
| 176 |
+
repetition_penalty: Optional[float] = None,
|
| 177 |
+
eos_token_id: Optional[Union[int, Sequence[int]]] = None, pad_token_id: Optional[int] = None,
|
| 178 |
+
stopping_criteria=None, logits_processor=None, streamer=None,
|
| 179 |
+
num_beams: int = 1, num_return_sequences: int = 1, return_dict_in_generate: bool = False,
|
| 180 |
+
**kwargs) -> torch.LongTensor:
|
| 181 |
+
"""Greedy or sampled decoding with one KV cache per block, following the `transformers.generate` contract.
|
| 182 |
+
|
| 183 |
+
Budget: `max_new_tokens` > `max_length` (total length, prompt included) > `generation_config.max_new_tokens`
|
| 184 |
+
> 128. A row stops at any `eos_token_id` (int or list), when `stopping_criteria` says so, or at the budget;
|
| 185 |
+
finished rows are padded with `pad_token_id`. `logits_processor` (a `LogitsProcessorList`) is applied before
|
| 186 |
+
sampling. Beam search and `num_return_sequences > 1` are not implemented.
|
| 187 |
+
"""
|
| 188 |
+
if input_ids is None:
|
| 189 |
+
input_ids = inputs
|
| 190 |
+
if input_ids is None:
|
| 191 |
+
raise ValueError("generate() needs `input_ids` (or `inputs`)")
|
| 192 |
+
if num_beams != 1 or num_return_sequences != 1:
|
| 193 |
+
raise NotImplementedError("Matilda Platypus implements greedy and sampled decoding only "
|
| 194 |
+
"(num_beams=1, num_return_sequences=1)")
|
| 195 |
+
bad = [k for k in _UNSUPPORTED_GENERATE_KWARGS if kwargs.get(k) not in (None, False, [], 1.0, 0)]
|
| 196 |
+
if bad:
|
| 197 |
+
raise NotImplementedError(f"generate() arguments not supported by Matilda Platypus: {bad}")
|
| 198 |
+
unknown = sorted(k for k in kwargs if k not in _UNSUPPORTED_GENERATE_KWARGS and k not in _IGNORED_GENERATE_KWARGS)
|
| 199 |
+
if unknown:
|
| 200 |
+
warnings.warn(f"MatildaPlatypusForCausalLM.generate() is ignoring unrecognised arguments: {unknown}",
|
| 201 |
+
stacklevel=2)
|
| 202 |
+
gc = generation_config
|
| 203 |
+
|
| 204 |
+
def pick(name, value, default):
|
| 205 |
+
if value is not None:
|
| 206 |
+
return value
|
| 207 |
+
v = getattr(gc, name, None) if gc is not None else None
|
| 208 |
+
return default if v is None else v
|
| 209 |
+
|
| 210 |
+
device = self.device
|
| 211 |
+
input_ids = input_ids.to(device)
|
| 212 |
+
batch, prompt_len = input_ids.shape
|
| 213 |
if attention_mask is None:
|
| 214 |
attention_mask = torch.ones_like(input_ids)
|
| 215 |
+
attention_mask = attention_mask.to(device)
|
| 216 |
+
|
| 217 |
+
# ---- budget
|
| 218 |
+
if max_new_tokens is None and max_length is not None:
|
| 219 |
+
budget = int(max_length) - prompt_len
|
| 220 |
+
else:
|
| 221 |
+
if max_new_tokens is not None and max_length is not None:
|
| 222 |
+
warnings.warn("Both `max_new_tokens` and `max_length` were given; `max_new_tokens` takes precedence.",
|
| 223 |
+
stacklevel=2)
|
| 224 |
+
budget = pick("max_new_tokens", max_new_tokens, None)
|
| 225 |
+
if budget is None:
|
| 226 |
+
budget = _DEFAULT_NEW_TOKENS
|
| 227 |
+
budget = int(budget)
|
| 228 |
+
if budget <= 0:
|
| 229 |
+
warnings.warn(f"generate(): the prompt ({prompt_len} tokens) already fills the requested length; "
|
| 230 |
+
"returning the prompt unchanged.", stacklevel=2)
|
| 231 |
+
return self._wrap(input_ids, return_dict_in_generate)
|
| 232 |
+
min_new = int(pick("min_new_tokens", min_new_tokens, 0) or 0)
|
| 233 |
+
|
| 234 |
+
# ---- special tokens
|
| 235 |
+
eos = pick("eos_token_id", eos_token_id, None)
|
| 236 |
+
if eos is None:
|
| 237 |
+
eos = self._default_eos()
|
| 238 |
+
eos_list = [int(e) for e in (eos if isinstance(eos, (list, tuple)) else ([] if eos is None else [eos]))]
|
| 239 |
+
eos_t = torch.tensor(eos_list, device=device, dtype=input_ids.dtype) if eos_list else None
|
| 240 |
+
pad = pick("pad_token_id", pad_token_id, None)
|
| 241 |
+
if pad is None:
|
| 242 |
+
pad = getattr(self.upper.config, "pad_token_id", None)
|
| 243 |
+
if pad is None:
|
| 244 |
+
pad = eos_list[0] if eos_list else 0
|
| 245 |
+
pad = int(pad)
|
| 246 |
+
|
| 247 |
+
# ---- sampling knobs (greedy unless do_sample)
|
| 248 |
+
sample = bool(pick("do_sample", do_sample, False))
|
| 249 |
+
temp = float(pick("temperature", temperature, 1.0))
|
| 250 |
+
tk = pick("top_k", top_k, None)
|
| 251 |
+
tp = float(pick("top_p", top_p, 1.0))
|
| 252 |
+
rep = float(pick("repetition_penalty", repetition_penalty, 1.0))
|
| 253 |
+
|
| 254 |
+
if streamer is not None and batch == 1:
|
| 255 |
+
streamer.put(input_ids.cpu())
|
| 256 |
out = self.forward(input_ids, attention_mask=attention_mask, use_cache=True)
|
| 257 |
caches = out.past_key_values
|
| 258 |
seq = input_ids
|
| 259 |
+
done = torch.zeros(batch, dtype=torch.bool, device=device)
|
| 260 |
+
for step in range(budget):
|
| 261 |
logits = out.logits[:, -1, :].float()
|
| 262 |
+
if rep != 1.0:
|
| 263 |
+
prev = torch.gather(logits, 1, seq)
|
| 264 |
+
prev = torch.where(prev < 0, prev * rep, prev / rep)
|
| 265 |
+
logits = logits.scatter(1, seq, prev)
|
| 266 |
+
if logits_processor is not None:
|
| 267 |
+
logits = logits_processor(seq, logits)
|
| 268 |
+
if step < min_new and eos_t is not None:
|
| 269 |
+
logits[:, eos_t] = float("-inf")
|
| 270 |
+
if sample:
|
| 271 |
+
logits = logits / max(temp, 1e-5)
|
| 272 |
+
if tk is not None and 0 < int(tk) < logits.shape[-1]:
|
| 273 |
+
kth = torch.topk(logits, int(tk), dim=-1).values[:, -1, None]
|
| 274 |
+
logits = logits.masked_fill(logits < kth, float("-inf"))
|
| 275 |
+
if tp < 1.0:
|
| 276 |
sorted_logits, idx = torch.sort(logits, descending=True)
|
| 277 |
probs = torch.softmax(sorted_logits, dim=-1)
|
| 278 |
+
keep = probs.cumsum(-1) - probs < tp
|
| 279 |
sorted_logits[~keep] = float("-inf")
|
| 280 |
logits = torch.full_like(logits, float("-inf")).scatter(1, idx, sorted_logits)
|
| 281 |
nxt = torch.multinomial(torch.softmax(logits, dim=-1), 1).squeeze(1)
|
| 282 |
else:
|
| 283 |
nxt = logits.argmax(-1)
|
| 284 |
+
nxt = torch.where(done, torch.full_like(nxt, pad), nxt)
|
| 285 |
seq = torch.cat([seq, nxt[:, None]], dim=1)
|
| 286 |
attention_mask = torch.cat([attention_mask, torch.ones_like(nxt[:, None])], dim=1)
|
| 287 |
+
if streamer is not None and batch == 1:
|
| 288 |
+
streamer.put(nxt.cpu())
|
| 289 |
+
if eos_t is not None:
|
| 290 |
+
done |= torch.isin(nxt, eos_t)
|
| 291 |
+
if stopping_criteria is not None:
|
| 292 |
+
flag = stopping_criteria(seq, logits)
|
| 293 |
+
flag = torch.as_tensor(flag, device=device).to(torch.bool)
|
| 294 |
+
done |= flag if flag.dim() else flag.expand(batch)
|
| 295 |
if bool(done.all()):
|
| 296 |
break
|
| 297 |
out = self.forward(nxt[:, None], attention_mask=attention_mask, past_key_values=caches, use_cache=True)
|
| 298 |
+
if streamer is not None:
|
| 299 |
+
streamer.end()
|
| 300 |
+
return self._wrap(seq, return_dict_in_generate)
|
| 301 |
+
|
| 302 |
+
@staticmethod
|
| 303 |
+
def _wrap(seq: torch.LongTensor, return_dict: bool):
|
| 304 |
+
if not return_dict:
|
| 305 |
+
return seq
|
| 306 |
+
try:
|
| 307 |
+
from transformers.generation.utils import GenerateDecoderOnlyOutput
|
| 308 |
+
return GenerateDecoderOnlyOutput(sequences=seq)
|
| 309 |
+
except Exception: # pragma: no cover - very old/new transformers without that class
|
| 310 |
+
return seq
|