JG1310 commited on
Commit
f5dfb21
·
verified ·
1 Parent(s): c0ccec4

promote hybrid: 8B map + 30B read + split build (VRAM) + FLUX preload + CUDA cache

Browse files
Files changed (1) hide show
  1. arcana/gpu_models.py +73 -29
arcana/gpu_models.py CHANGED
@@ -28,21 +28,34 @@ import threading
28
 
29
  # fast multi-connection Hub downloads (the GGUFs/FLUX weights crawl otherwise)
30
  os.environ.setdefault("HF_HUB_ENABLE_HF_TRANSFER", "1")
 
 
 
 
 
 
 
 
 
 
31
 
32
  # ---- model selection (env-overridable) ------------------------------------
 
 
 
 
 
 
 
33
  _DEF_8B = ("bartowski/nvidia_Llama-3.1-Nemotron-Nano-8B-v1-GGUF",
34
  "nvidia_Llama-3.1-Nemotron-Nano-8B-v1-Q4_K_M.gguf")
35
  _DEF_30B = ("unsloth/Nemotron-3-Nano-30B-A3B-GGUF",
36
  "Nemotron-3-Nano-30B-A3B-Q4_K_M.gguf")
37
-
38
- # Mapping model (structured JSON) — the dense 8B (reliable + fast).
39
- MAP_REPO = os.environ.get("LOCAL_MAP_REPO", os.environ.get("LOCAL_LLM_REPO", _DEF_8B[0]))
40
- MAP_FILE = os.environ.get("LOCAL_MAP_FILE", os.environ.get("LOCAL_LLM_FILE", _DEF_8B[1]))
41
  MAP_N_CTX = int(os.environ.get("LOCAL_MAP_N_CTX", "16384"))
42
- # Reading model (prose) — defaults to the SAME 8B; set LOCAL_READ_* to the 30B
43
- # on spaces that should produce the richer readings.
44
- READ_REPO = os.environ.get("LOCAL_READ_REPO", MAP_REPO)
45
- READ_FILE = os.environ.get("LOCAL_READ_FILE", MAP_FILE)
46
  READ_N_CTX = int(os.environ.get("LOCAL_READ_N_CTX", "8192"))
47
 
48
  # Distilled klein (built for 4 steps); set LOCAL_IMAGE_MODEL=...-klein-9B for best.
@@ -104,17 +117,50 @@ def _is_nemotron3(fname: str) -> bool:
104
  return "30b" in f or "nemotron-3-nano-3" in f
105
 
106
 
107
- def _gen(llm, fname: str, system: str, user: str, max_tokens: int, temperature: float) -> str:
108
- """Generate clean (non-reasoning) text, picking the prompt style per model."""
109
- if _is_nemotron3(fname):
110
- # Nemotron-3 ChatML: seed an empty <think></think> to suppress reasoning.
111
- prompt = (f"<|im_start|>system\n{system}<|im_end|>\n"
112
- f"<|im_start|>user\n{user}<|im_end|>\n"
113
- f"<|im_start|>assistant\n<think></think>\n")
114
- out = llm.create_completion(prompt=prompt, max_tokens=max_tokens,
115
- temperature=temperature, stop=["<|im_end|>"])
116
- return (out["choices"][0]["text"] or "").strip()
117
- # Llama-3 template (8B Llama-Nemotron): "detailed thinking off" in system.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  out = llm.create_chat_completion(
119
  messages=[{"role": "system", "content": "detailed thinking off\n\n" + system},
120
  {"role": "user", "content": user}],
@@ -122,19 +168,17 @@ def _gen(llm, fname: str, system: str, user: str, max_tokens: int, temperature:
122
  return (out["choices"][0]["message"]["content"] or "").strip()
123
 
124
 
125
- def llama_map(system: str, user: str, max_tokens: int = 10000,
126
- temperature: float = 0.4) -> str:
127
- """Structured JSON mapping via the small dense model (clean JSON, no grammar —
128
- the dense 8B emits valid JSON and designer.extract_json + retries cover slips)."""
129
- llm = _get_llama(MAP_REPO, MAP_FILE, MAP_N_CTX)
130
- return _gen(llm, MAP_FILE, system, user, max_tokens, temperature)
131
-
132
-
133
  def llama_read(system: str, user: str, max_tokens: int = 9000,
134
  temperature: float = 0.7) -> str:
135
- """Prose readings via the reading model (the 30B where configured → richer)."""
136
  llm = _get_llama(READ_REPO, READ_FILE, READ_N_CTX)
137
- return _gen(llm, READ_FILE, system, user, max_tokens, temperature)
 
 
 
 
 
 
138
 
139
 
140
  def preload_pipe():
 
28
 
29
  # fast multi-connection Hub downloads (the GGUFs/FLUX weights crawl otherwise)
30
  os.environ.setdefault("HF_HUB_ENABLE_HF_TRANSFER", "1")
31
+ # Persist the CUDA JIT cache to disk (the Space disk is huge + persists) so a fresh
32
+ # ZeroGPU worker can skip re-JITting llama.cpp's Blackwell kernels — cuts the cold
33
+ # warm-up on later workers.
34
+ os.environ.setdefault("CUDA_CACHE_PATH", "/data/.nv_cache"
35
+ if os.path.isdir("/data") else os.path.expanduser("~/.nv_cache"))
36
+ os.environ.setdefault("CUDA_CACHE_MAXSIZE", str(2 * 1024 ** 3))
37
+ try:
38
+ os.makedirs(os.environ["CUDA_CACHE_PATH"], exist_ok=True)
39
+ except Exception:
40
+ pass
41
 
42
  # ---- model selection (env-overridable) ------------------------------------
43
+ # HYBRID, by necessity: the 30B-Q4-MoE CANNOT reliably emit the dense 22-card×5-field
44
+ # mapping JSON (tested both ways: reasoning = too slow/GPU-aborts; suppressed = leaves
45
+ # fields empty, fails all retries). The dense 8B-Q4 (Llama-arch) fills the JSON
46
+ # reliably and warms fast. So: 8B MAPS, 30B READS (rich prose). Both Nemotron, both
47
+ # llama.cpp (the right engine for the hybrid-Mamba 30B — transformers can't build its
48
+ # Mamba kernels on ZeroGPU). They run in separate @spaces.GPU calls so the 8B+FLUX
49
+ # (build) and the 30B (reading) never share the 48GB GPU.
50
  _DEF_8B = ("bartowski/nvidia_Llama-3.1-Nemotron-Nano-8B-v1-GGUF",
51
  "nvidia_Llama-3.1-Nemotron-Nano-8B-v1-Q4_K_M.gguf")
52
  _DEF_30B = ("unsloth/Nemotron-3-Nano-30B-A3B-GGUF",
53
  "Nemotron-3-Nano-30B-A3B-Q4_K_M.gguf")
54
+ MAP_REPO = os.environ.get("LOCAL_MAP_REPO", _DEF_8B[0])
55
+ MAP_FILE = os.environ.get("LOCAL_MAP_FILE", _DEF_8B[1])
 
 
56
  MAP_N_CTX = int(os.environ.get("LOCAL_MAP_N_CTX", "16384"))
57
+ READ_REPO = os.environ.get("LOCAL_READ_REPO", _DEF_30B[0])
58
+ READ_FILE = os.environ.get("LOCAL_READ_FILE", _DEF_30B[1])
 
 
59
  READ_N_CTX = int(os.environ.get("LOCAL_READ_N_CTX", "8192"))
60
 
61
  # Distilled klein (built for 4 steps); set LOCAL_IMAGE_MODEL=...-klein-9B for best.
 
117
  return "30b" in f or "nemotron-3-nano-3" in f
118
 
119
 
120
+ def _last_balanced_json(text: str) -> str:
121
+ """Return the LAST top-level {...} block in text (the final answer after any
122
+ reasoning), else the whole text. Lets a reasoning model think first, then we
123
+ take the JSON it emits at the end."""
124
+ objs, depth, start, in_str, esc = [], 0, None, False, False
125
+ for i, c in enumerate(text):
126
+ if in_str:
127
+ if esc: esc = False
128
+ elif c == "\\": esc = True
129
+ elif c == '"': in_str = False
130
+ continue
131
+ if c == '"': in_str = True
132
+ elif c == "{":
133
+ if depth == 0: start = i
134
+ depth += 1
135
+ elif c == "}":
136
+ if depth > 0:
137
+ depth -= 1
138
+ if depth == 0 and start is not None:
139
+ objs.append(text[start:i + 1]); start = None
140
+ return objs[-1] if objs else text
141
+
142
+
143
+ def _suppress_gen(llm, system: str, user: str, max_tokens: int, temperature: float) -> str:
144
+ """Nemotron-3 ChatML with an empty <think></think> seed → clean, non-reasoning
145
+ prose (fast). Used for readings."""
146
+ prompt = (f"<|im_start|>system\n{system}<|im_end|>\n"
147
+ f"<|im_start|>user\n{user}<|im_end|>\n"
148
+ f"<|im_start|>assistant\n<think></think>\n")
149
+ out = llm.create_completion(prompt=prompt, max_tokens=max_tokens,
150
+ temperature=temperature, stop=["<|im_end|>"])
151
+ return (out["choices"][0]["text"] or "").strip()
152
+
153
+
154
+ def llama_map(system: str, user: str, max_tokens: int = 12000,
155
+ temperature: float = 0.5) -> str:
156
+ """Structured JSON mapping — think-SUPPRESSED (fast). Reasoning-then-extract was
157
+ far too slow (16k tokens × 2 passes → GPU-time aborts). Suppressed generation
158
+ with a generous token budget should be clean: the earlier 'empty concept'
159
+ failures were almost certainly JSON truncation from too-low max_tokens, not the
160
+ model. designer.extract_json + a couple retries cover any residual slip."""
161
+ llm = _get_llama(MAP_REPO, MAP_FILE, MAP_N_CTX)
162
+ if _is_nemotron3(MAP_FILE):
163
+ return _suppress_gen(llm, system, user, max_tokens, temperature)
164
  out = llm.create_chat_completion(
165
  messages=[{"role": "system", "content": "detailed thinking off\n\n" + system},
166
  {"role": "user", "content": user}],
 
168
  return (out["choices"][0]["message"]["content"] or "").strip()
169
 
170
 
 
 
 
 
 
 
 
 
171
  def llama_read(system: str, user: str, max_tokens: int = 9000,
172
  temperature: float = 0.7) -> str:
173
+ """Prose readings (think-suppressed for clean, fast output)."""
174
  llm = _get_llama(READ_REPO, READ_FILE, READ_N_CTX)
175
+ if _is_nemotron3(READ_FILE):
176
+ return _suppress_gen(llm, system, user, max_tokens, temperature)
177
+ out = llm.create_chat_completion(
178
+ messages=[{"role": "system", "content": "detailed thinking off\n\n" + system},
179
+ {"role": "user", "content": user}],
180
+ max_tokens=max_tokens, temperature=temperature)
181
+ return (out["choices"][0]["message"]["content"] or "").strip()
182
 
183
 
184
  def preload_pipe():