Text Generation
Transformers
Safetensors
English
gemma4_unified
image-text-to-text
gemma
gemma4
fp8
torchao
quantization
speculative-decoding
dspark
long-context
blackwell
vision
multimodal
conversational
Instructions to use skibare87/gemma-4-12B-it-FP8-DSpark with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use skibare87/gemma-4-12B-it-FP8-DSpark with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="skibare87/gemma-4-12B-it-FP8-DSpark") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("skibare87/gemma-4-12B-it-FP8-DSpark") model = AutoModelForMultimodalLM.from_pretrained("skibare87/gemma-4-12B-it-FP8-DSpark", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use skibare87/gemma-4-12B-it-FP8-DSpark with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "skibare87/gemma-4-12B-it-FP8-DSpark" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "skibare87/gemma-4-12B-it-FP8-DSpark", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/skibare87/gemma-4-12B-it-FP8-DSpark
- SGLang
How to use skibare87/gemma-4-12B-it-FP8-DSpark 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 "skibare87/gemma-4-12B-it-FP8-DSpark" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "skibare87/gemma-4-12B-it-FP8-DSpark", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'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 "skibare87/gemma-4-12B-it-FP8-DSpark" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "skibare87/gemma-4-12B-it-FP8-DSpark", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use skibare87/gemma-4-12B-it-FP8-DSpark with Docker Model Runner:
docker model run hf.co/skibare87/gemma-4-12B-it-FP8-DSpark
vision: images ride the DSpark speculative loop
Browse files- recipe/server.py +61 -10
recipe/server.py
CHANGED
|
@@ -17,6 +17,9 @@ import time
|
|
| 17 |
import threading
|
| 18 |
import queue
|
| 19 |
import uuid
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
os.environ.setdefault("MASTER_ADDR", "127.0.0.1")
|
| 22 |
os.environ.setdefault("MASTER_PORT", "29500")
|
|
@@ -38,12 +41,13 @@ from torch.nn.attention import SDPBackend, sdpa_kernel
|
|
| 38 |
# implement (NotImplementedError). It crashes the cache save. So we can't cache the dynamo frontend;
|
| 39 |
# the ~200s warmup tracing stays. (AOTInductor would avoid dynamo entirely — separate effort.)
|
| 40 |
from types import SimpleNamespace
|
| 41 |
-
from typing import List, Optional
|
| 42 |
import json as _json
|
|
|
|
| 43 |
from fastapi import FastAPI
|
| 44 |
from fastapi.responses import StreamingResponse
|
| 45 |
from pydantic import BaseModel
|
| 46 |
-
from transformers import AutoModelForCausalLM, AutoTokenizer, TorchAoConfig
|
| 47 |
from torchao.quantization import (
|
| 48 |
Float8DynamicActivationFloat8WeightConfig, Float8WeightOnlyConfig, PerRow)
|
| 49 |
from torchao.quantization.quantize_.common.kernel_preference import KernelPreference
|
|
@@ -112,6 +116,10 @@ EV = FP8Gemma4DSparkEvaluator(0, _args)
|
|
| 112 |
print(f"[dspark] TIMING model+quant load: {time.time()-_T0:.1f}s", flush=True)
|
| 113 |
EV.confidence_head_recorder = None # metrics recorder is only started inside evaluate(); we bypass it
|
| 114 |
TOK = EV.tokenizer
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
STOP = resolve_stop_token_ids(EV.target_model, TOK) # gemma real eos set (e.g. [1,106,50]), not a guess
|
| 116 |
_LOCK = threading.Lock()
|
| 117 |
|
|
@@ -156,7 +164,38 @@ app = FastAPI()
|
|
| 156 |
|
| 157 |
class Msg(BaseModel):
|
| 158 |
role: str
|
| 159 |
-
content: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
|
| 162 |
class ChatReq(BaseModel):
|
|
@@ -196,13 +235,25 @@ def _split_think(ids, thinking):
|
|
| 196 |
|
| 197 |
@app.post("/v1/chat/completions")
|
| 198 |
def chat(req: ChatReq):
|
| 199 |
-
msgs = [{"role": m.role, "content": m.content} for m in req.messages]
|
| 200 |
# thinking on by default; a `*-nothink` model alias (routed to this same backend) turns it off
|
| 201 |
thinking = THINKING and not (req.model or "").endswith("-nothink")
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
cid = "chatcmpl-" + uuid.uuid4().hex[:12]
|
| 207 |
created = int(time.time())
|
| 208 |
model = req.model or MODEL_NAME
|
|
@@ -228,7 +279,7 @@ def chat(req: ChatReq):
|
|
| 228 |
EV.args.temperature = temp
|
| 229 |
with sdpa_kernel([SDPBackend.EFFICIENT_ATTENTION, SDPBackend.MATH]), torch.no_grad():
|
| 230 |
EV.generate_one_sample(
|
| 231 |
-
input_ids=ids, stop_token_ids=STOP,
|
| 232 |
stream_callback=lambda t: q.put(t[0].tolist()),
|
| 233 |
)
|
| 234 |
except Exception as e: # surface generation errors to the stream instead of hanging
|
|
@@ -271,7 +322,7 @@ def chat(req: ChatReq):
|
|
| 271 |
EV.args.temperature = temp
|
| 272 |
t = time.time()
|
| 273 |
with sdpa_kernel([SDPBackend.EFFICIENT_ATTENTION, SDPBackend.MATH]), torch.no_grad():
|
| 274 |
-
res = EV.generate_one_sample(input_ids=ids, stop_token_ids=STOP)
|
| 275 |
dt = time.time() - t
|
| 276 |
gen = res.output_ids[0, res.num_input_tokens:].tolist()
|
| 277 |
reasoning, content = _split_think(gen, thinking)
|
|
|
|
| 17 |
import threading
|
| 18 |
import queue
|
| 19 |
import uuid
|
| 20 |
+
import io
|
| 21 |
+
import base64
|
| 22 |
+
import urllib.request
|
| 23 |
|
| 24 |
os.environ.setdefault("MASTER_ADDR", "127.0.0.1")
|
| 25 |
os.environ.setdefault("MASTER_PORT", "29500")
|
|
|
|
| 41 |
# implement (NotImplementedError). It crashes the cache save. So we can't cache the dynamo frontend;
|
| 42 |
# the ~200s warmup tracing stays. (AOTInductor would avoid dynamo entirely — separate effort.)
|
| 43 |
from types import SimpleNamespace
|
| 44 |
+
from typing import Any, List, Optional
|
| 45 |
import json as _json
|
| 46 |
+
from PIL import Image
|
| 47 |
from fastapi import FastAPI
|
| 48 |
from fastapi.responses import StreamingResponse
|
| 49 |
from pydantic import BaseModel
|
| 50 |
+
from transformers import AutoModelForCausalLM, AutoProcessor, AutoTokenizer, TorchAoConfig
|
| 51 |
from torchao.quantization import (
|
| 52 |
Float8DynamicActivationFloat8WeightConfig, Float8WeightOnlyConfig, PerRow)
|
| 53 |
from torchao.quantization.quantize_.common.kernel_preference import KernelPreference
|
|
|
|
| 116 |
print(f"[dspark] TIMING model+quant load: {time.time()-_T0:.1f}s", flush=True)
|
| 117 |
EV.confidence_head_recorder = None # metrics recorder is only started inside evaluate(); we bypass it
|
| 118 |
TOK = EV.tokenizer
|
| 119 |
+
# The multimodal processor (image + text). gemma-4-12B is a VLM; DSpark's target processes the image in
|
| 120 |
+
# the prefill (pixel_values), the KV cache carries it, and the draft speculates over image-aware hidden
|
| 121 |
+
# states — so vision rides the same speculative loop as text. Only loaded once here.
|
| 122 |
+
PROC = AutoProcessor.from_pretrained(TARGET)
|
| 123 |
STOP = resolve_stop_token_ids(EV.target_model, TOK) # gemma real eos set (e.g. [1,106,50]), not a guess
|
| 124 |
_LOCK = threading.Lock()
|
| 125 |
|
|
|
|
| 164 |
|
| 165 |
class Msg(BaseModel):
|
| 166 |
role: str
|
| 167 |
+
content: Any # str, or OpenAI multimodal list: [{"type":"text",...}, {"type":"image_url",...}]
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def _load_image(url: str) -> Image.Image:
|
| 171 |
+
"""Load a PIL image from a data: URI or an http(s) URL."""
|
| 172 |
+
if url.startswith("data:"):
|
| 173 |
+
return Image.open(io.BytesIO(base64.b64decode(url.split(",", 1)[1]))).convert("RGB")
|
| 174 |
+
return Image.open(io.BytesIO(urllib.request.urlopen(url, timeout=20).read())).convert("RGB")
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def _build_chat(messages):
|
| 178 |
+
"""Turn request messages into (chat-for-template, has_images). Accepts plain string content or an
|
| 179 |
+
OpenAI multimodal content list (text parts + image_url/image parts), which become gemma image parts."""
|
| 180 |
+
chat, has_images = [], False
|
| 181 |
+
for m in messages:
|
| 182 |
+
c = m.content
|
| 183 |
+
if isinstance(c, str):
|
| 184 |
+
chat.append({"role": m.role, "content": c})
|
| 185 |
+
continue
|
| 186 |
+
parts = []
|
| 187 |
+
for part in (c or []):
|
| 188 |
+
t = part.get("type") if isinstance(part, dict) else None
|
| 189 |
+
if t == "text":
|
| 190 |
+
parts.append({"type": "text", "text": part.get("text", "")})
|
| 191 |
+
elif t in ("image_url", "image"):
|
| 192 |
+
url = part.get("image_url", {}).get("url") if t == "image_url" else (part.get("image") or part.get("url"))
|
| 193 |
+
parts.append({"type": "image", "image": _load_image(url)})
|
| 194 |
+
has_images = True
|
| 195 |
+
elif isinstance(part, str):
|
| 196 |
+
parts.append({"type": "text", "text": part})
|
| 197 |
+
chat.append({"role": m.role, "content": parts})
|
| 198 |
+
return chat, has_images
|
| 199 |
|
| 200 |
|
| 201 |
class ChatReq(BaseModel):
|
|
|
|
| 235 |
|
| 236 |
@app.post("/v1/chat/completions")
|
| 237 |
def chat(req: ChatReq):
|
|
|
|
| 238 |
# thinking on by default; a `*-nothink` model alias (routed to this same backend) turns it off
|
| 239 |
thinking = THINKING and not (req.model or "").endswith("-nothink")
|
| 240 |
+
chat_msgs, has_images = _build_chat(req.messages)
|
| 241 |
+
if has_images:
|
| 242 |
+
# multimodal: the processor emits input_ids + pixel_values/mm_token_type_ids/image_position_ids;
|
| 243 |
+
# the extra keys ride to the DSpark prefill (prefill_mm) so the target embeds the image and the
|
| 244 |
+
# draft speculates over image-aware hidden states — vision on the same speculative loop as text.
|
| 245 |
+
enc = PROC.apply_chat_template(
|
| 246 |
+
chat_msgs, add_generation_prompt=True, tokenize=True, return_dict=True,
|
| 247 |
+
return_tensors="pt", enable_thinking=thinking,
|
| 248 |
+
).to(EV.device)
|
| 249 |
+
ids = enc["input_ids"]
|
| 250 |
+
prefill_mm = {k: enc[k] for k in enc if k not in ("input_ids", "attention_mask")}
|
| 251 |
+
else:
|
| 252 |
+
ids = TOK.apply_chat_template(
|
| 253 |
+
chat_msgs, add_generation_prompt=True, enable_thinking=thinking,
|
| 254 |
+
return_tensors="pt", return_dict=True,
|
| 255 |
+
)["input_ids"].to(EV.device)
|
| 256 |
+
prefill_mm = None
|
| 257 |
cid = "chatcmpl-" + uuid.uuid4().hex[:12]
|
| 258 |
created = int(time.time())
|
| 259 |
model = req.model or MODEL_NAME
|
|
|
|
| 279 |
EV.args.temperature = temp
|
| 280 |
with sdpa_kernel([SDPBackend.EFFICIENT_ATTENTION, SDPBackend.MATH]), torch.no_grad():
|
| 281 |
EV.generate_one_sample(
|
| 282 |
+
input_ids=ids, stop_token_ids=STOP, prefill_mm=prefill_mm,
|
| 283 |
stream_callback=lambda t: q.put(t[0].tolist()),
|
| 284 |
)
|
| 285 |
except Exception as e: # surface generation errors to the stream instead of hanging
|
|
|
|
| 322 |
EV.args.temperature = temp
|
| 323 |
t = time.time()
|
| 324 |
with sdpa_kernel([SDPBackend.EFFICIENT_ATTENTION, SDPBackend.MATH]), torch.no_grad():
|
| 325 |
+
res = EV.generate_one_sample(input_ids=ids, stop_token_ids=STOP, prefill_mm=prefill_mm)
|
| 326 |
dt = time.time() - t
|
| 327 |
gen = res.output_ids[0, res.num_input_tokens:].tolist()
|
| 328 |
reasoning, content = _split_think(gen, thinking)
|