Spaces:
Running on Zero
Running on Zero
Fix tuple index unpacking in PyTorch engine
Browse files- core/engine_torch.py +24 -65
core/engine_torch.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
| 1 |
"""
|
| 2 |
PyTorch / CUDA / CPU Inference Engine for Parallel Constrained Decoding.
|
| 3 |
-
Optimized for Linux containers, Hugging Face Spaces (
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
| 7 |
import time
|
| 8 |
import json
|
| 9 |
import copy
|
|
|
|
| 10 |
import threading
|
| 11 |
from typing import Dict, Any, Generator, Optional, List, Tuple
|
| 12 |
|
|
@@ -28,7 +29,7 @@ _gpu_lock = threading.Lock()
|
|
| 28 |
# Support Hugging Face Spaces ZeroGPU if available
|
| 29 |
try:
|
| 30 |
import spaces
|
| 31 |
-
gpu_decorator = spaces.GPU
|
| 32 |
except Exception:
|
| 33 |
def gpu_decorator(fn=None, **kwargs):
|
| 34 |
if fn is not None:
|
|
@@ -66,42 +67,6 @@ def get_torch_engine():
|
|
| 66 |
return _torch_model, _torch_tokenizer, _torch_device
|
| 67 |
|
| 68 |
|
| 69 |
-
def _extract_choice_logits(
|
| 70 |
-
last_logits: torch.Tensor,
|
| 71 |
-
cands_per_field: List[List[List[int]]],
|
| 72 |
-
temperature: float = 1.0
|
| 73 |
-
) -> Tuple[List[int], List[float], List[List[float]]]:
|
| 74 |
-
"""
|
| 75 |
-
Slices candidate token logits and computes calibrated softmax probabilities.
|
| 76 |
-
last_logits: tensor of shape (M, vocab_size) on device.
|
| 77 |
-
"""
|
| 78 |
-
inv_t = 1.0 / max(temperature, 1e-4)
|
| 79 |
-
win_indices = []
|
| 80 |
-
win_probs = []
|
| 81 |
-
all_field_probs = []
|
| 82 |
-
|
| 83 |
-
for i, cands_list in enumerate(cands_per_field):
|
| 84 |
-
field_logits = last_logits[i]
|
| 85 |
-
choice_scores = []
|
| 86 |
-
for ids in cands_list:
|
| 87 |
-
if not ids:
|
| 88 |
-
choice_scores.append(-1e9)
|
| 89 |
-
elif len(ids) == 1:
|
| 90 |
-
choice_scores.append(field_logits[ids[0]].item())
|
| 91 |
-
else:
|
| 92 |
-
choice_scores.append(field_logits[ids].max().item())
|
| 93 |
-
|
| 94 |
-
scores_t = torch.tensor(choice_scores, dtype=torch.float32) * inv_t
|
| 95 |
-
probs = F.softmax(scores_t, dim=-1).tolist()
|
| 96 |
-
|
| 97 |
-
best_idx = int(torch.argmax(scores_t).item())
|
| 98 |
-
win_indices.append(best_idx)
|
| 99 |
-
win_probs.append(probs[best_idx])
|
| 100 |
-
all_field_probs.append(probs)
|
| 101 |
-
|
| 102 |
-
return win_indices, win_probs, all_field_probs
|
| 103 |
-
|
| 104 |
-
|
| 105 |
@gpu_decorator
|
| 106 |
def run_parallel_generation_torch(
|
| 107 |
context: str,
|
|
@@ -118,8 +83,11 @@ def run_parallel_generation_torch(
|
|
| 118 |
# 1. Compile schema metadata
|
| 119 |
meta = schema.compile_parallel_metadata(tokenizer)
|
| 120 |
field_items = meta["field_items"]
|
|
|
|
| 121 |
cands_per_field = meta["cands_per_field"]
|
| 122 |
-
|
|
|
|
|
|
|
| 123 |
M = len(field_items)
|
| 124 |
|
| 125 |
# 2. High-density semantic catalog prefill
|
|
@@ -143,18 +111,8 @@ def run_parallel_generation_torch(
|
|
| 143 |
t_suf0 = time.perf_counter()
|
| 144 |
pad_id = tokenizer.pad_token_id or tokenizer.eos_token_id or 0
|
| 145 |
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
padded_suffixes = []
|
| 149 |
-
attention_masks = []
|
| 150 |
-
|
| 151 |
-
for s in suffix_tokens_list:
|
| 152 |
-
pad_len = max_len - len(s)
|
| 153 |
-
padded_suffixes.append([pad_id] * pad_len + s)
|
| 154 |
-
attention_masks.append([0] * pad_len + [1] * len(s))
|
| 155 |
-
|
| 156 |
-
suffix_arr = torch.tensor(padded_suffixes, dtype=torch.long, device=device)
|
| 157 |
-
suffix_mask = torch.tensor(attention_masks, dtype=torch.long, device=device)
|
| 158 |
|
| 159 |
# Broadcast KV cache to batch size M
|
| 160 |
with torch.no_grad():
|
|
@@ -172,29 +130,30 @@ def run_parallel_generation_torch(
|
|
| 172 |
full_mask = torch.cat([prefix_mask, suffix_mask], dim=1)
|
| 173 |
|
| 174 |
out = model(suffix_arr, past_key_values=batched_cache, attention_mask=full_mask)
|
| 175 |
-
|
| 176 |
-
last_logits = out.logits[:, -1, :]
|
| 177 |
|
| 178 |
t_suffix_eval = (time.perf_counter() - t_suf0) * 1000
|
| 179 |
|
| 180 |
-
# 4. Slicing & Softmax
|
| 181 |
-
win_indices, win_probs, all_field_probs = _extract_choice_logits(
|
| 182 |
-
last_logits, cands_per_field, temperature=temperature
|
| 183 |
-
)
|
| 184 |
-
|
| 185 |
-
# 5. Assemble typed JSON and telemetry
|
| 186 |
parsed_json = {}
|
| 187 |
field_telemetry = {}
|
| 188 |
|
| 189 |
-
for i, (fname, fdef
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
|
| 194 |
if fdef.field_type == "boolean":
|
| 195 |
-
val = (
|
| 196 |
else:
|
| 197 |
-
val = fdef.choices[
|
| 198 |
|
| 199 |
parsed_json[fname] = {
|
| 200 |
"value": val,
|
|
|
|
| 1 |
"""
|
| 2 |
PyTorch / CUDA / CPU Inference Engine for Parallel Constrained Decoding.
|
| 3 |
+
Optimized for Linux containers, Hugging Face Spaces (ZeroGPU & CUDA), and cloud environments.
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
| 7 |
import time
|
| 8 |
import json
|
| 9 |
import copy
|
| 10 |
+
import re
|
| 11 |
import threading
|
| 12 |
from typing import Dict, Any, Generator, Optional, List, Tuple
|
| 13 |
|
|
|
|
| 29 |
# Support Hugging Face Spaces ZeroGPU if available
|
| 30 |
try:
|
| 31 |
import spaces
|
| 32 |
+
gpu_decorator = spaces.GPU(duration=60)
|
| 33 |
except Exception:
|
| 34 |
def gpu_decorator(fn=None, **kwargs):
|
| 35 |
if fn is not None:
|
|
|
|
| 67 |
return _torch_model, _torch_tokenizer, _torch_device
|
| 68 |
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
@gpu_decorator
|
| 71 |
def run_parallel_generation_torch(
|
| 72 |
context: str,
|
|
|
|
| 83 |
# 1. Compile schema metadata
|
| 84 |
meta = schema.compile_parallel_metadata(tokenizer)
|
| 85 |
field_items = meta["field_items"]
|
| 86 |
+
suffix_lengths = meta["suffix_lengths"]
|
| 87 |
cands_per_field = meta["cands_per_field"]
|
| 88 |
+
prefixes = meta["prefixes"]
|
| 89 |
+
has_collisions = meta["has_collisions"]
|
| 90 |
+
suffixes_batch = meta["suffixes_batch"]
|
| 91 |
M = len(field_items)
|
| 92 |
|
| 93 |
# 2. High-density semantic catalog prefill
|
|
|
|
| 111 |
t_suf0 = time.perf_counter()
|
| 112 |
pad_id = tokenizer.pad_token_id or tokenizer.eos_token_id or 0
|
| 113 |
|
| 114 |
+
suffix_arr = torch.tensor(suffixes_batch, dtype=torch.long, device=device)
|
| 115 |
+
suffix_mask = (suffix_arr != pad_id).long()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
# Broadcast KV cache to batch size M
|
| 118 |
with torch.no_grad():
|
|
|
|
| 130 |
full_mask = torch.cat([prefix_mask, suffix_mask], dim=1)
|
| 131 |
|
| 132 |
out = model(suffix_arr, past_key_values=batched_cache, attention_mask=full_mask)
|
| 133 |
+
suffix_out = out.logits
|
|
|
|
| 134 |
|
| 135 |
t_suffix_eval = (time.perf_counter() - t_suf0) * 1000
|
| 136 |
|
| 137 |
+
# 4. Slicing, Disambiguation & Softmax
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
parsed_json = {}
|
| 139 |
field_telemetry = {}
|
| 140 |
|
| 141 |
+
for i, (fname, fdef) in enumerate(field_items):
|
| 142 |
+
decision_idx = suffix_lengths[i] - 1
|
| 143 |
+
field_logits = suffix_out[i, decision_idx, :]
|
| 144 |
+
cand_tokens = cands_per_field[i]
|
| 145 |
+
|
| 146 |
+
scores = [float(field_logits[tid].item()) for tid in cand_tokens]
|
| 147 |
+
scores_t = torch.tensor(scores, dtype=torch.float32) / max(temperature, 1e-4)
|
| 148 |
+
probs = F.softmax(scores_t, dim=-1).tolist()
|
| 149 |
+
w_idx = int(torch.argmax(scores_t).item())
|
| 150 |
+
w_prob = float(probs[w_idx])
|
| 151 |
+
all_probs = probs
|
| 152 |
|
| 153 |
if fdef.field_type == "boolean":
|
| 154 |
+
val = (w_idx == 0)
|
| 155 |
else:
|
| 156 |
+
val = fdef.choices[w_idx]
|
| 157 |
|
| 158 |
parsed_json[fname] = {
|
| 159 |
"value": val,
|