Image-Text-to-Text
Transformers
Safetensors
PEFT
qwen3_5_moe
classification
structured-prediction
multimodal
lora
Instructions to use suryatmodulus/GPC-1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use suryatmodulus/GPC-1 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="suryatmodulus/GPC-1")# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("suryatmodulus/GPC-1") model = AutoModelForMultimodalLM.from_pretrained("suryatmodulus/GPC-1", device_map="auto") - PEFT
How to use suryatmodulus/GPC-1 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use suryatmodulus/GPC-1 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "suryatmodulus/GPC-1" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "suryatmodulus/GPC-1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/suryatmodulus/GPC-1
- SGLang
How to use suryatmodulus/GPC-1 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 "suryatmodulus/GPC-1" \ --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": "suryatmodulus/GPC-1", "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 "suryatmodulus/GPC-1" \ --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": "suryatmodulus/GPC-1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use suryatmodulus/GPC-1 with Docker Model Runner:
docker model run hf.co/suryatmodulus/GPC-1
| from __future__ import annotations | |
| import json | |
| import hashlib | |
| import os | |
| from pathlib import Path | |
| from typing import Any, Protocol, Sequence | |
| from .assets import load_codebook, load_runtime_manifest, sha256_file | |
| from .compiler import NumericField, compile_numeric, compile_vision_numeric, decode_numeric | |
| from .native_onepass import compile_joint, score_joint | |
| class Backend(Protocol): | |
| model_id: str | |
| def numeric(self, context: str, fields: Sequence[NumericField], image: Any | None = None) -> dict[str, Any]: ... | |
| def atomic(self, context: str, field_key: str, choices: Sequence[Any]) -> dict[str, Any]: ... | |
| def finite_joint(self, context: str, schema: dict[str, Any], candidates: Sequence[dict[str, Any]]) -> dict[str, Any]: ... | |
| class TransformersBackend: | |
| """Pinned Transformers/PEFT backend; no custom CUDA kernels or generation.""" | |
| def _context_limits(manifest: dict[str, Any], model_config: dict[str, Any], | |
| environ: dict[str, str]) -> tuple[int, int]: | |
| capacity = int(model_config["text_config"]["max_position_embeddings"]) | |
| default = int(manifest["admission"]["default_max_input_tokens"]) | |
| limit = int(environ.get("GPC1_MAX_INPUT_TOKENS", str(default))) | |
| if not 0 < limit <= capacity: | |
| raise ValueError(f"GPC1_MAX_INPUT_TOKENS must be between 1 and {capacity}") | |
| padded = int(environ.get("GPC1_MAX_PADDED_TOKENS", str(max(131072, 2 * limit)))) | |
| if padded <= 0: | |
| raise ValueError("GPC1_MAX_PADDED_TOKENS must be positive") | |
| return limit, padded | |
| def _verify_model_file_closure(model_path: Path, expected_files: set[str]) -> None: | |
| top_files={p.name for p in model_path.iterdir() if p.is_file()} | |
| suspicious={name for name in top_files if ( | |
| name.endswith((".safetensors",".json",".jinja",".txt")) | |
| or "config" in name or "tokenizer" in name or "processor" in name or "index" in name)} | |
| if suspicious != expected_files: | |
| raise RuntimeError(f"loader-visible model file closure mismatch: {sorted(suspicious ^ expected_files)}") | |
| def _verify_adapter_file_closure(adapter_path: Path) -> None: | |
| adapter_files={p.name for p in adapter_path.iterdir() if p.is_file()} | |
| if adapter_files != {"adapter_config.json","adapter_model.safetensors"}: | |
| raise RuntimeError("adapter directory must contain exactly the two bound release files") | |
| def _adapter_path(manifest: dict[str, Any], package_root: Path, | |
| environ: dict[str, str]) -> Path: | |
| if manifest.get("weight_format") != "adapter" or not isinstance(manifest.get("adapter"), dict) \ | |
| or manifest.get("merged_full_weights") is not None: | |
| raise RuntimeError("release runtime requires adapter weight metadata only") | |
| return Path(environ.get("GPC1_ADAPTER_PATH", package_root / "adapter")) | |
| def __init__(self) -> None: | |
| import torch | |
| from transformers import AutoProcessor | |
| from transformers import Qwen3_5MoeForConditionalGeneration | |
| self.torch = torch | |
| torch.backends.cuda.matmul.allow_tf32 = False | |
| torch.backends.cudnn.allow_tf32 = False | |
| torch.set_float32_matmul_precision("highest") | |
| self.manifest = load_runtime_manifest() | |
| package_root = Path(__file__).resolve().parents[1] | |
| model_path = Path(os.environ["GPC1_MODEL_PATH"]) | |
| self.max_input_tokens, self.max_padded_tokens = self._context_limits( | |
| self.manifest, json.loads((model_path / "config.json").read_text()), os.environ) | |
| adapter_path = self._adapter_path(self.manifest, package_root, os.environ) | |
| self._verify_artifacts(model_path, adapter_path) | |
| self.processor = AutoProcessor.from_pretrained(model_path, local_files_only=True, | |
| trust_remote_code=False) | |
| base = Qwen3_5MoeForConditionalGeneration.from_pretrained( | |
| model_path, local_files_only=True, trust_remote_code=False, | |
| dtype=torch.bfloat16, attn_implementation="sdpa", | |
| low_cpu_mem_usage=True, device_map={"": 0}) | |
| from peft import PeftModel | |
| self.model = PeftModel.from_pretrained(base, adapter_path, is_trainable=False, | |
| autocast_adapter_dtype=True) | |
| self.model.eval() | |
| for parameter in self.model.parameters(): | |
| parameter.requires_grad_(False) | |
| if base.__class__.__name__ != "Qwen3_5MoeForConditionalGeneration" \ | |
| or getattr(base.config, "model_type", None) != "qwen3_5_moe": | |
| raise RuntimeError("loaded base is not the pinned Qwen3.5 MoE architecture") | |
| adapter_parameters = {name: p for name, p in self.model.named_parameters() if "lora_" in name} | |
| base_dtypes = {p.dtype for name, p in self.model.named_parameters() | |
| if p.is_floating_point() and "lora_" not in name} | |
| if base_dtypes != {torch.bfloat16} or not adapter_parameters \ | |
| or {p.dtype for p in adapter_parameters.values()} != {torch.float32}: | |
| raise RuntimeError("loaded base/adapter dtype inventory differs from BF16/FP32 contract") | |
| from peft.utils import get_peft_model_state_dict | |
| digest = hashlib.sha256() | |
| state = get_peft_model_state_dict(self.model) | |
| for name in sorted(state): | |
| tensor = state[name].detach().cpu().contiguous() | |
| metadata = json.dumps({"dtype":str(tensor.dtype),"name":name,"shape":list(tensor.shape)}, | |
| sort_keys=True,separators=(",", ":")).encode() | |
| raw = tensor.view(torch.uint8).numpy().tobytes() | |
| digest.update(len(metadata).to_bytes(8,"big")); digest.update(metadata) | |
| digest.update(len(raw).to_bytes(8,"big")); digest.update(raw) | |
| if digest.hexdigest() != self.manifest["adapter"]["adapter_tensor_digest"]: | |
| raise RuntimeError("loaded adapter tensor digest mismatch") | |
| self.model_id = self.manifest["served_model_id"] | |
| self.codebook = load_codebook() | |
| self.max_joint_rows = int(os.environ.get("GPC1_MAX_JOINT_ROWS", "32")) | |
| self.max_logit_vectors = int(os.environ.get("GPC1_MAX_LOGIT_VECTORS", "512")) | |
| self.max_logits_bytes = int(os.environ.get("GPC1_MAX_LOGITS_BYTES", str(512 * 1024 * 1024))) | |
| accepted_modes = set(self.manifest["admission"]["accepted_modes"]) | |
| self.admit_vision = "numeric101_image" in accepted_modes \ | |
| and os.environ.get("GPC1_ADMIT_VISION_NUMERIC", "accepted") == "accepted" | |
| self.admit_joint = "finite_joint" in accepted_modes \ | |
| and os.environ.get("GPC1_ADMIT_FINITE_JOINT", "accepted") == "accepted" | |
| cache_mb = int(os.environ.get("GPC1_IMAGE_CACHE_MB", "64")) | |
| if not 0 <= cache_mb <= 64: | |
| raise ValueError("GPC1_IMAGE_CACHE_MB must be an integer between 0 and 64") | |
| self._vision_cache = None | |
| if cache_mb: | |
| from .vision_cache import VisionFeatureCache | |
| self._vision_cache = VisionFeatureCache( | |
| self.model.base_model.model.model.visual, torch, cache_mb * 1024 * 1024) | |
| def _verify_artifacts(self, model_path: Path, adapter_path: Path) -> None: | |
| expected = self.manifest | |
| package_root = Path(__file__).resolve().parents[1] | |
| inventory_path = package_root / "assets" / "base_files.sha256.json" | |
| inventory = json.loads(inventory_path.read_text()) | |
| if inventory["model_id"] != expected["base"]["model_id"] or inventory["revision"] != expected["base"]["revision"]: | |
| raise RuntimeError("model-file inventory identity mismatch") | |
| self._verify_model_file_closure(model_path, set(inventory["files"])) | |
| for relative, digest in inventory["files"].items(): | |
| path = model_path / relative | |
| if not path.is_file() or sha256_file(path) != digest: | |
| raise RuntimeError(f"pinned model file identity mismatch: {relative}") | |
| self._verify_adapter_file_closure(adapter_path) | |
| if sha256_file(adapter_path / "adapter_model.safetensors") != expected["adapter"]["adapter_model_sha256"]: | |
| raise RuntimeError("bundled adapter identity mismatch") | |
| if sha256_file(adapter_path / "adapter_config.json") != expected["adapter"]["adapter_config_sha256"]: | |
| raise RuntimeError("bundled adapter config identity mismatch") | |
| def _forward(self, inputs: dict[str, Any], positions: Sequence[int]) -> Any: | |
| torch = self.torch | |
| device = next(self.model.parameters()).device | |
| moved = {k: v.to(device) if hasattr(v, "to") else v for k, v in inputs.items()} | |
| with torch.inference_mode(): | |
| # Project logits only at requested positions. | |
| output = self.model(**moved, logits_to_keep=[int(p) for p in positions], | |
| use_cache=False, return_dict=True) | |
| if output.logits.ndim != 3 or tuple(output.logits.shape[:2]) != (1, len(positions)): | |
| raise RuntimeError("native sparse logits do not align to query positions") | |
| return output.logits[0].float() | |
| def numeric(self, context: str, fields: Sequence[NumericField], image: Any | None = None) -> dict[str, Any]: | |
| vocab = int(self.model.config.text_config.vocab_size) | |
| if len(fields) * vocab * 4 > self.max_logits_bytes: | |
| raise ValueError("numeric sparse logits exceed byte admission") | |
| if image is None: | |
| compiled = compile_numeric(self.processor.tokenizer, context, fields, self.codebook, | |
| self.max_input_tokens) | |
| ids = self.torch.tensor([compiled.input_ids], dtype=self.torch.long) | |
| mask = self.torch.ones_like(ids) | |
| inputs = {"input_ids": ids, "attention_mask": mask, | |
| "position_ids": mask.cumsum(dim=-1) - 1} | |
| positions = compiled.positions | |
| else: | |
| if not self.admit_vision: | |
| raise ValueError("vision numeric requires an accepted same-hardware parity gate") | |
| vision = compile_vision_numeric(self.processor, image, context, fields, self.codebook, | |
| self.max_input_tokens, self.model.config) | |
| compiled = vision.numeric; inputs = vision.processor_inputs; positions = vision.positions | |
| logits = self._forward(inputs, positions) | |
| token_ids = self.torch.tensor(compiled.candidate_token_ids, device=logits.device) | |
| results = {} | |
| for index, field in enumerate(fields): | |
| raw = logits[index].index_select(0, token_ids).float() | |
| probs = self.torch.softmax(raw, dim=-1).cpu().tolist() | |
| results[field.key] = decode_numeric(probs, field) | |
| return {"fields": results, "accounting": {"backbone_calls": 1, | |
| "physical_rows": 1, "field_slots": len(fields), "truncated": False}, | |
| "semantics": "per-field marginals; not a learned full joint distribution"} | |
| def atomic(self, context: str, field_key: str, choices: Sequence[Any]) -> dict[str, Any]: | |
| if not 2 <= len(choices) <= 255 or len({json.dumps(v,sort_keys=True) for v in choices}) != len(choices): | |
| raise ValueError("atomic choices must contain 2..255 unique JSON values") | |
| schema={"field_order":[field_key],"fields":{field_key:{"type":"enum","choices":list(choices)}}} | |
| support="\n".join(f'{self.codebook[i]["code"]} = '+json.dumps(v,ensure_ascii=False,sort_keys=True,separators=(",",":")) for i,v in enumerate(choices)) | |
| user=("Classify the active field from the complete input.\n\nContext:\n"+context+"\n\n" | |
| "Registered schema gpc1-public-atomic@1:\n"+json.dumps(schema,ensure_ascii=False,sort_keys=True,separators=(",",":")) | |
| +"\n\nAllowed complete outputs in registered semantic order:\n"+support+"\n\nReturn exactly one allowed output.") | |
| prompt=self.processor.tokenizer.apply_chat_template([ | |
| {"role":"system","content":"You are a fixed-schema lookup model. Return exactly one listed opaque code and no other text."}, | |
| {"role":"user","content":user}],tokenize=False,add_generation_prompt=True,enable_thinking=False) | |
| ids=tuple(self.processor.tokenizer.encode(prompt,add_special_tokens=False)) | |
| if len(ids)>self.max_input_tokens: raise ValueError("atomic request exceeds token admission; no truncation performed") | |
| for row in self.codebook[:len(choices)]: | |
| combined=tuple(self.processor.tokenizer.encode(prompt+str(row["code"]),add_special_tokens=False)) | |
| if combined != ids + (int(row["token_id"]),): | |
| raise ValueError("atomic response-boundary tokenization changed") | |
| tensor=self.torch.tensor([ids]); logits=self._forward({"input_ids":tensor,"attention_mask":self.torch.ones_like(tensor)},[len(ids)-1])[0] | |
| indices=self.torch.tensor([int(r["token_id"]) for r in self.codebook[:len(choices)]],device=logits.device) | |
| probs=self.torch.softmax(logits.index_select(0,indices).float(),dim=-1).cpu().tolist(); selected=max(range(len(choices)),key=probs.__getitem__) | |
| return {"value":choices[selected],"probabilities":probs,"selected_index":selected,"calibrated":False, | |
| "accounting":{"backbone_calls":1,"physical_rows":1,"truncated":False}, | |
| "semantics":"conditional distribution over the complete caller-declared choice set"} | |
| def finite_joint(self, context: str, schema: dict[str, Any], candidates: Sequence[dict[str, Any]]) -> dict[str, Any]: | |
| if not self.admit_joint: | |
| raise ValueError("finite_joint requires an accepted same-hardware parity gate") | |
| tokenizer = self.processor.tokenizer | |
| canonical = [json.dumps(v, ensure_ascii=False, sort_keys=True, | |
| separators=(",", ":"), allow_nan=False) for v in candidates] | |
| support = "\n".join(f"{value} = {value}" for value in canonical) | |
| user = ("Select one complete allowed JSON record from the complete input.\n\nContext:\n" + context | |
| + "\n\nRegistered schema gpc1-public-finite-joint@1:\n" | |
| + json.dumps(schema, ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False) | |
| + "\n\nAllowed complete outputs in registered semantic order:\n" + support | |
| + "\n\nReturn exactly one allowed output.") | |
| prompt = tokenizer.apply_chat_template([ | |
| {"role":"system","content":"You are a fixed-schema lookup model. Return exactly one listed complete JSON record and no other text."}, | |
| {"role":"user","content":user}], tokenize=False, add_generation_prompt=True, | |
| enable_thinking=False) | |
| prefix = tuple(tokenizer.encode(prompt, add_special_tokens=False)) | |
| terminal_text = tokenizer.eos_token or "<|im_end|>" | |
| terminal = tuple(tokenizer.encode(terminal_text, add_special_tokens=False)) | |
| suffixes = [] | |
| for value in canonical: | |
| complete = tuple(tokenizer.encode(prompt + value + terminal_text, add_special_tokens=False)) | |
| if complete[:len(prefix)] != prefix: raise ValueError("candidate tokenization changed prompt prefix") | |
| suffixes.append(complete[len(prefix):]) | |
| compiled = compile_joint(prefix, tuple(str(i) for i in range(len(candidates))), suffixes, | |
| terminal, pad_token_id=int(tokenizer.pad_token_id), max_rows=self.max_joint_rows, | |
| max_padded_tokens=self.max_padded_tokens, max_logit_vectors=self.max_logit_vectors, | |
| max_input_tokens=self.max_input_tokens) | |
| vocab = int(self.model.config.text_config.vocab_size) | |
| if compiled.logit_vectors * vocab * 4 > self.max_logits_bytes: | |
| raise ValueError("joint sparse logits exceed byte admission") | |
| device = next(self.model.parameters()).device | |
| result = score_joint(self.model, compiled, device=device) | |
| result["value"] = candidates[result["selected_index"]] | |
| result["semantics"] = "conditional distribution over the complete caller-declared joint support" | |
| return result | |