harshatheg commited on
Commit
292b8ea
·
verified ·
1 Parent(s): a0270e2

Fix tuple index unpacking in PyTorch engine

Browse files
Files changed (1) hide show
  1. 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 (CPU & ZeroGPU/CUDA), and cloud environments.
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
- suffixes_str = [item[2] for item in field_items]
 
 
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
- suffix_tokens_list = [tokenizer.encode(s, add_special_tokens=False) for s in suffixes_str]
147
- max_len = max(len(s) for s in suffix_tokens_list)
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
- # Logits at the last token position for each field
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, _) in enumerate(field_items):
190
- best_idx = win_indices[i]
191
- w_prob = win_probs[i]
192
- all_probs = all_field_probs[i]
 
 
 
 
 
 
 
193
 
194
  if fdef.field_type == "boolean":
195
- val = (best_idx == 0)
196
  else:
197
- val = fdef.choices[best_idx]
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,