Zero-Shot Classification
Transformers
Safetensors
decision2
feature-extraction
decision-model
classification
system-one
custom_code
Instructions to use vllm-sr/Decision-2.0-Sol-2B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use vllm-sr/Decision-2.0-Sol-2B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("zero-shot-classification", model="vllm-sr/Decision-2.0-Sol-2B", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("vllm-sr/Decision-2.0-Sol-2B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download decision2/qwen.py from vllm-sr/Decision-2.0-Sol-2B: direct link, hf CLI and curl.
- Browser
- Download file 15.1 kB
-
https://huggingface.co/vllm-sr/Decision-2.0-Sol-2B/resolve/b42b6ff3efeedcd6534a3169a5db60247b363fb8/decision2/qwen.py
- Command line
-
hf download hf://vllm-sr/Decision-2.0-Sol-2B@b42b6ff3efeedcd6534a3169a5db60247b363fb8/decision2/qwen.py
-
curl -L -o qwen.py https://huggingface.co/vllm-sr/Decision-2.0-Sol-2B/resolve/b42b6ff3efeedcd6534a3169a5db60247b363fb8/decision2/qwen.py
15.1 kB
| """Qwen-family Decision 2.0 checkpoints (full or base-bound LoRA) behind System One. | |
| Model construction, prompt encoding, the candidate head and answer | |
| normalization come from the vendored modules that produced the scored | |
| predictions (``_vendor/dev2model``), byte for byte except where the manifest | |
| records an import-only rewrite. A base-bound adapter's source files are pinned | |
| by repository revision and SHA-256; a supplied or downloaded copy is verified | |
| before use. GPU inference runs the backbone under BF16 autocast with its | |
| BF16-exact Linear weights held in BF16 and every other tensor, the head | |
| included, in FP32; CPU uses FP32. A request's questions run as one padded | |
| batch unless, on a GPU, that batch would put more than 2**30 elements in a | |
| gated-delta q / k / v tensor (``forward_token_budget``); then they run as | |
| several batches. | |
| A package whose manifest names a weight ``storage`` codec (bf16z) is first restored | |
| to exact safetensors files in a cache directory; the restored checkpoint must | |
| reproduce the scored identity. A checkpoint whose ``decision_config.json`` declares | |
| ``readout: label_token`` is read through its tied LM head's label-token logits at | |
| the answer cue (vendored ``label_token.py``) instead of a candidate head. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from contextlib import nullcontext | |
| from pathlib import Path | |
| from typing import Any | |
| from ._vendor.dev2model.data import file_sha256 | |
| def resolve_base(base: dict[str, Any], base_path: str | Path | None) -> Path: | |
| """Local directory holding exactly the pinned base files (downloaded if absent).""" | |
| expected = base["files_sha256"] | |
| if base_path is None: | |
| from huggingface_hub import snapshot_download | |
| base_path = snapshot_download( | |
| base["repo_id"], revision=base["revision"], allow_patterns=sorted(expected) | |
| ) | |
| root = Path(base_path).resolve(strict=True) | |
| for name, digest in expected.items(): | |
| if not (root / name).is_file() or file_sha256(root / name) != digest: | |
| raise ValueError(f"Base file differs from the pinned revision: {name}") | |
| return root | |
| def load_score_bias_entry( | |
| root: Path, manifest: dict[str, Any], model_sha256: str | |
| ) -> dict[int, list[float]] | None: | |
| """Per-level Score offsets bound by the manifest; None when it lists none.""" | |
| entry = manifest.get("score_bias") | |
| if entry is None: | |
| return None | |
| from ._vendor.dev2model.score_bias import load_score_bias | |
| path = root / entry["file"] | |
| if ( | |
| manifest["files_sha256"].get(entry["file"]) != entry["sha256"] | |
| or not path.is_file() | |
| or file_sha256(path) != entry["sha256"] | |
| ): | |
| raise ValueError("Score offsets differ from the packaged score_bias file") | |
| offsets, _ = load_score_bias(path, model_sha256) | |
| if {str(key): value for key, value in offsets.items()} != entry["offsets"]: | |
| raise ValueError("Score offsets differ from MODEL_MANIFEST.json") | |
| return offsets | |
| def keep_linear_bf16(module: Any, torch: Any) -> dict[str, int]: | |
| """Hold the BF16-exact ``nn.Linear`` weights and biases of ``module`` in BF16. | |
| BF16 autocast multiplies every Linear with its weight rounded to BF16, so a | |
| weight that BF16 represents exactly gives the same products whether it is | |
| kept in FP32 and cast on every call or kept in BF16. Everything else stays | |
| FP32: embeddings, norms, gated-delta ``A_log`` / ``dt_bias``, conv filters, | |
| Linear weights BF16 cannot hold exactly (e.g. FP32-trained LoRA factors, | |
| which stay unmerged) and weights shared with any other kind of module. | |
| Returns how many Linear modules hold a BF16 or an FP32 weight. | |
| """ | |
| shared = { | |
| id(parameter) | |
| for layer in module.modules() | |
| if not isinstance(layer, torch.nn.Linear) | |
| for parameter in layer.parameters(recurse=False) | |
| } | |
| counts = {"linear_bf16": 0, "linear_fp32": 0} | |
| for layer in module.modules(): | |
| if not isinstance(layer, torch.nn.Linear): | |
| continue | |
| for parameter in (layer.weight, layer.bias): | |
| if ( | |
| parameter is None | |
| or parameter.dtype != torch.float32 | |
| or id(parameter) in shared | |
| ): | |
| continue | |
| rounded = parameter.data.to(torch.bfloat16) | |
| if torch.equal(rounded.float(), parameter.data): | |
| parameter.data = rounded | |
| counts[ | |
| "linear_bf16" if layer.weight.dtype == torch.bfloat16 else "linear_fp32" | |
| ] += 1 | |
| return counts | |
| INT32_MAX = 2**31 - 1 | |
| def forward_token_budget(config: Any) -> int | None: | |
| """Most padded tokens one GPU forward may hold; None when nothing limits it. | |
| The FLA gated-delta kernels of Qwen3.5-family backbones compute some | |
| element offsets of their [batch, tokens, value heads, head dim] q / k / v | |
| tensors in 32-bit integers (the L2-norm forward and the fused KKT-solve | |
| kernel among them). A forward whose tensors exceed 2**31 - 1 elements reads | |
| and writes the wrong memory for the later batch rows: wrong answers, | |
| non-finite logits or a GPU memory fault. On DEV2.0-27B, forwards with | |
| tensors between about 2**30 and 2**31 elements also hung or crashed the | |
| process, so the budget keeps these tensors within 2**30 elements. | |
| """ | |
| config = getattr(config, "text_config", None) or config | |
| heads = getattr(config, "linear_num_value_heads", None) | |
| if not heads: | |
| return None | |
| width = heads * max(config.linear_key_head_dim, config.linear_value_head_dim) | |
| return (INT32_MAX // 2) // width | |
| def micro_batches(lengths: list[int], budget: int | None) -> list[list[int]]: | |
| """Indices of each forward: one batch when its padded size fits the budget. | |
| Otherwise the questions go longest first into batches whose padded size | |
| (``collate`` pads to the longest, rounded up to 8) stays within the budget, | |
| each batch listing its indices in request order. | |
| """ | |
| def padded(length: int) -> int: | |
| return -(-length // 8) * 8 | |
| if budget is None or padded(max(lengths)) * len(lengths) <= budget: | |
| return [list(range(len(lengths)))] | |
| order = sorted(range(len(lengths)), key=lambda i: (-lengths[i], i)) | |
| if padded(lengths[order[0]]) > budget: | |
| raise ValueError("A single question exceeds the forward token budget") | |
| groups: list[list[int]] = [] | |
| while order: | |
| rows = budget // padded(lengths[order[0]]) | |
| groups.append(sorted(order[:rows])) | |
| order = order[rows:] | |
| return groups | |
| class QwenDecision: | |
| def __init__( | |
| self, | |
| model: Any, | |
| tokenizer: Any, | |
| device: Any, | |
| temperatures: dict, | |
| cap: int, | |
| torch: Any, | |
| score_bias: dict[int, list[float]] | None = None, | |
| residency: dict[str, int] | None = None, | |
| encode_fn: Any = None, | |
| batch_tokens: int | None = None, | |
| ): | |
| self.model = model | |
| self.tokenizer = tokenizer | |
| self.device = device | |
| self.temperatures = temperatures | |
| self.cap = cap | |
| self.torch = torch | |
| self.score_bias = score_bias | |
| self.residency = residency | |
| self.encode_fn = encode_fn | |
| self.batch_tokens = batch_tokens | |
| def load( | |
| cls, | |
| root: Path, | |
| manifest: dict[str, Any], | |
| *, | |
| device: str, | |
| base_path: str | Path | None, | |
| threads: int | None, | |
| bf16_resident: bool = True, | |
| ) -> QwenDecision: | |
| import torch | |
| from ._vendor.dev2model.calibration import load_calibration | |
| from ._vendor.dev2model.decision_model import DecisionModel | |
| from ._vendor.dev2model.infer import checkpoint_fingerprint | |
| if threads: | |
| torch.set_num_threads(threads) | |
| source = None | |
| if manifest["profile"] == "qwen-adapter": | |
| source = resolve_base(manifest["base"], base_path) | |
| model_root = root | |
| if manifest.get("storage"): | |
| from .bf16z import materialize | |
| model_root = materialize(root, manifest) | |
| metadata = json.loads( | |
| (model_root / "decision_config.json").read_text(encoding="utf-8") | |
| ) | |
| residual = metadata.get("dec_residual") is not None | |
| label = metadata.get("readout") == "label_token" | |
| if label: | |
| from ._vendor.dev2model.label_token import label_fingerprint | |
| identity = label_fingerprint(model_root, source) | |
| elif residual: | |
| from ._vendor.dev2model.dec_model import dec_fingerprint | |
| identity = dec_fingerprint(model_root, source) | |
| else: | |
| identity = checkpoint_fingerprint(model_root, source) | |
| if identity["model_sha256"] != manifest["identity"]["model_sha256"]: | |
| raise ValueError("Model identity differs from the scored checkpoint") | |
| score_bias = load_score_bias_entry(root, manifest, identity["model_sha256"]) | |
| calibration = manifest.get("calibration") | |
| if calibration: | |
| temperatures, report = load_calibration( | |
| root / calibration["file"], identity["model_sha256"] | |
| ) | |
| if report.get("inference", {}).get("max_length") not in ( | |
| None, | |
| manifest["max_input_tokens"], | |
| ): | |
| raise ValueError("Calibration context differs from the package limit") | |
| else: | |
| temperatures = {"choice": 1.0, "noul": 1.0, "score": 1.0} | |
| target = torch.device(device) | |
| if target.type == "cuda" and ( | |
| not torch.cuda.is_available() or not torch.cuda.is_bf16_supported() | |
| ): | |
| raise RuntimeError("A CUDA/ROCm BF16 GPU is required for GPU inference") | |
| encode_fn = None | |
| if label: | |
| from ._vendor.dev2model.label_token import ( | |
| encode_label, | |
| load_label_checkpoint, | |
| ) | |
| model, tokenizer = load_label_checkpoint(model_root, source) | |
| encode_fn = encode_label | |
| elif residual: | |
| from ._vendor.dev2model.dec_model import load_dec_checkpoint | |
| model, tokenizer = load_dec_checkpoint(model_root, source) | |
| else: | |
| model, tokenizer = DecisionModel.from_checkpoint( | |
| model_root, source_path=source | |
| ) | |
| model = model.float() | |
| residency = None | |
| if target.type == "cuda" and bf16_resident: | |
| residency = keep_linear_bf16(model.backbone, torch) | |
| model = model.to(target).eval() | |
| if tokenizer.pad_token_id is None and tokenizer.eos_token_id is None: | |
| raise ValueError("Tokenizer needs a pad or EOS token") | |
| batch_tokens = ( | |
| forward_token_budget(model.backbone.config) | |
| if target.type == "cuda" | |
| else None | |
| ) | |
| return cls( | |
| model, | |
| tokenizer, | |
| target, | |
| temperatures, | |
| manifest["max_input_tokens"], | |
| torch, | |
| score_bias, | |
| residency, | |
| encode_fn, | |
| batch_tokens, | |
| ) | |
| def parameter_count(self) -> int: | |
| return sum(p.numel() for p in self.model.parameters()) | |
| def system_one( | |
| self, state: Any, questions: dict[str, Any] | |
| ) -> tuple[dict[str, Any], int]: | |
| from ._vendor.dev2model.data import canonical | |
| from ._vendor.dev2model.decision_model import collate, encode | |
| from ._vendor.dev2model.infer import ( | |
| _api_json_payload, | |
| product_answer, | |
| question_to_row, | |
| ) | |
| if not _api_json_payload(state): | |
| raise ValueError("state must be text, an object, or an array") | |
| try: | |
| canonical(state) | |
| except (TypeError, ValueError) as exc: | |
| raise ValueError("state must contain JSON data") from exc | |
| item = {"id": "request", "state": state} | |
| answers: dict[str, dict[str, Any]] = {} | |
| jobs: list[tuple[str, dict[str, Any], dict[str, Any]]] = [] | |
| tokens = 0 | |
| for qid, question in questions.items(): | |
| try: | |
| row = question_to_row(item, qid, question) | |
| encoded = (self.encode_fn or encode)(row, self.tokenizer, self.cap) | |
| except ValueError as exc: | |
| reason = ( | |
| "max_length_exceeded" | |
| if "exceeds max_length" in str(exc) | |
| else "invalid_question" | |
| ) | |
| answers[qid] = { | |
| "type": ( | |
| question.get("type") if isinstance(question, dict) else None | |
| ), | |
| "error": reason, | |
| } | |
| continue | |
| tokens += len(encoded["ids"]) | |
| jobs.append((qid, row, encoded)) | |
| if not jobs: | |
| return answers, tokens | |
| pad_id = self.tokenizer.pad_token_id | |
| if pad_id is None: | |
| pad_id = self.tokenizer.eos_token_id | |
| logits: list[Any] = [None] * len(jobs) | |
| for group in micro_batches( | |
| [len(encoded["ids"]) for _, _, encoded in jobs], self.batch_tokens | |
| ): | |
| batch = { | |
| key: value.to(self.device) if self.torch.is_tensor(value) else value | |
| for key, value in collate( | |
| [jobs[index][2] for index in group], pad_id | |
| ).items() | |
| } | |
| autocast = ( | |
| self.torch.autocast(device_type="cuda", dtype=self.torch.bfloat16) | |
| if self.device.type == "cuda" | |
| else nullcontext() | |
| ) | |
| with self.torch.inference_mode(), autocast: | |
| output = self.model(**batch) | |
| if len(output) != len(group): | |
| raise RuntimeError( | |
| "Model returned the wrong number of question answers" | |
| ) | |
| for index, values in zip(group, output): | |
| logits[index] = values | |
| if self.score_bias is not None: | |
| from ._vendor.dev2model.score_bias import apply as apply_score_bias | |
| for (qid, row, encoded), values in zip(jobs, logits): | |
| try: | |
| values = values[: len(encoded["keys"])].float().cpu().tolist() | |
| if self.score_bias is not None and row["task_type"] == "score": | |
| values = apply_score_bias( | |
| self.score_bias, values, len(row["options"]) | |
| ) | |
| answers[qid] = product_answer( | |
| row["task_type"], | |
| encoded["keys"], | |
| values, | |
| self.temperatures[row["task_type"]], | |
| [option["description"] for option in row["options"]], | |
| ) | |
| except ValueError: | |
| answers[qid] = { | |
| "type": row["task_type"], | |
| "error": "invalid_model_output", | |
| } | |
| ordered = {qid: answers[qid] for qid in questions} | |
| return ordered, tokens | |