Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -14,6 +14,13 @@ from threading import Thread
|
|
| 14 |
MODEL_NAME = os.getenv("MODEL_NAME", "dllm-hub/Qwen3-0.6B-diffusion-bd3lm-v0.1")
|
| 15 |
IS_DIFFUSION = "diffusion" in MODEL_NAME.lower()
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
# Dynamic initialization layer targeting Diffusion Language Models
|
| 18 |
if IS_DIFFUSION:
|
| 19 |
try:
|
|
@@ -79,13 +86,11 @@ def clone_past_key_values(pkv):
|
|
| 79 |
"""Clone KV-cache. Fast path for tuples and Cache objects; falls back to deepcopy."""
|
| 80 |
if pkv is None:
|
| 81 |
return None
|
| 82 |
-
# Fast path: legacy tuple format
|
| 83 |
if isinstance(pkv, tuple):
|
| 84 |
return tuple(
|
| 85 |
(k.clone() if k is not None else None, v.clone() if v is not None else None)
|
| 86 |
for k, v in pkv
|
| 87 |
)
|
| 88 |
-
# Fast path: transformers Cache objects (DynamicCache, etc.)
|
| 89 |
if hasattr(pkv, 'key_cache') and hasattr(pkv, 'value_cache'):
|
| 90 |
try:
|
| 91 |
new_cache = pkv.__class__()
|
|
@@ -97,7 +102,6 @@ def clone_past_key_values(pkv):
|
|
| 97 |
return new_cache
|
| 98 |
except Exception:
|
| 99 |
pass
|
| 100 |
-
# Fallback
|
| 101 |
return copy.deepcopy(pkv)
|
| 102 |
|
| 103 |
|
|
@@ -322,33 +326,39 @@ def generate_stream(model, tokenizer, prompt, steps=128, max_new_tokens=128, blo
|
|
| 322 |
def load_model():
|
| 323 |
global model, tokenizer, device
|
| 324 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
if IS_DIFFUSION:
|
| 327 |
model = AutoModelForMaskedLM.from_pretrained(
|
| 328 |
MODEL_NAME,
|
| 329 |
-
torch_dtype=
|
| 330 |
trust_remote_code=True
|
| 331 |
).to(device).eval()
|
| 332 |
else:
|
| 333 |
model = AutoModelForCausalLM.from_pretrained(
|
| 334 |
MODEL_NAME,
|
| 335 |
-
torch_dtype=
|
| 336 |
trust_remote_code=False
|
| 337 |
).to(device).eval()
|
| 338 |
-
|
| 339 |
-
|
|
|
|
| 340 |
try:
|
| 341 |
model = torch.compile(model, mode="reduce-overhead", fullgraph=False)
|
| 342 |
print("Model compiled with torch.compile.")
|
| 343 |
except Exception as e:
|
| 344 |
print(f"torch.compile skipped: {e}")
|
| 345 |
else:
|
| 346 |
-
print("
|
|
|
|
| 347 |
tokenizer = AutoTokenizer.from_pretrained(
|
| 348 |
MODEL_NAME,
|
| 349 |
trust_remote_code=IS_DIFFUSION
|
| 350 |
)
|
| 351 |
-
print("Model
|
| 352 |
|
| 353 |
|
| 354 |
@app.route('/health', methods=['GET'])
|
|
@@ -371,7 +381,6 @@ def generate_text():
|
|
| 371 |
{"role": "system", "content": system_prompt},
|
| 372 |
{"role": "user", "content": prompt}
|
| 373 |
]
|
| 374 |
-
# enable_thinking=False for ALL routes to prevent Qwen3 from leaking internal monologue
|
| 375 |
encoded = tokenizer.apply_chat_template(
|
| 376 |
messages,
|
| 377 |
add_generation_prompt=True,
|
|
@@ -399,7 +408,8 @@ def generate_text():
|
|
| 399 |
max_new_tokens=max_new_tokens,
|
| 400 |
temperature=temperature,
|
| 401 |
do_sample=True if temperature > 0 else False,
|
| 402 |
-
pad_token_id=tokenizer.eos_token_id
|
|
|
|
| 403 |
)
|
| 404 |
generated_ids = output_ids[0, input_ids.shape[-1]:]
|
| 405 |
generated_text = tokenizer.decode(generated_ids, skip_special_tokens=True)
|
|
@@ -452,7 +462,8 @@ def generate_text_stream():
|
|
| 452 |
output_ids = model.generate(
|
| 453 |
input_ids, max_new_tokens=max_new_tokens, temperature=temperature,
|
| 454 |
do_sample=True if temperature > 0 else False,
|
| 455 |
-
pad_token_id=tokenizer.eos_token_id
|
|
|
|
| 456 |
)
|
| 457 |
generated_ids = output_ids[0, input_ids.shape[-1]:]
|
| 458 |
generated_text = tokenizer.decode(generated_ids, skip_special_tokens=True)
|
|
@@ -505,6 +516,7 @@ def generate_text_sse():
|
|
| 505 |
temperature=temperature,
|
| 506 |
do_sample=True if temperature > 0 else False,
|
| 507 |
pad_token_id=tokenizer.eos_token_id,
|
|
|
|
| 508 |
)
|
| 509 |
|
| 510 |
def _generate():
|
|
@@ -516,7 +528,7 @@ def generate_text_sse():
|
|
| 516 |
|
| 517 |
accumulated = []
|
| 518 |
for text in streamer:
|
| 519 |
-
if not text:
|
| 520 |
continue
|
| 521 |
accumulated.append(text)
|
| 522 |
current = "".join(accumulated)
|
|
|
|
| 14 |
MODEL_NAME = os.getenv("MODEL_NAME", "dllm-hub/Qwen3-0.6B-diffusion-bd3lm-v0.1")
|
| 15 |
IS_DIFFUSION = "diffusion" in MODEL_NAME.lower()
|
| 16 |
|
| 17 |
+
# CPU optimizations: tune threads and disable denormals before any torch work
|
| 18 |
+
if not torch.cuda.is_available():
|
| 19 |
+
torch.set_num_threads(os.cpu_count() or 4)
|
| 20 |
+
torch.set_num_interop_threads(1)
|
| 21 |
+
torch.set_flush_denormal(True)
|
| 22 |
+
print(f"CPU mode: using {torch.get_num_threads()} threads, interop=1, flush_denormal=True")
|
| 23 |
+
|
| 24 |
# Dynamic initialization layer targeting Diffusion Language Models
|
| 25 |
if IS_DIFFUSION:
|
| 26 |
try:
|
|
|
|
| 86 |
"""Clone KV-cache. Fast path for tuples and Cache objects; falls back to deepcopy."""
|
| 87 |
if pkv is None:
|
| 88 |
return None
|
|
|
|
| 89 |
if isinstance(pkv, tuple):
|
| 90 |
return tuple(
|
| 91 |
(k.clone() if k is not None else None, v.clone() if v is not None else None)
|
| 92 |
for k, v in pkv
|
| 93 |
)
|
|
|
|
| 94 |
if hasattr(pkv, 'key_cache') and hasattr(pkv, 'value_cache'):
|
| 95 |
try:
|
| 96 |
new_cache = pkv.__class__()
|
|
|
|
| 102 |
return new_cache
|
| 103 |
except Exception:
|
| 104 |
pass
|
|
|
|
| 105 |
return copy.deepcopy(pkv)
|
| 106 |
|
| 107 |
|
|
|
|
| 326 |
def load_model():
|
| 327 |
global model, tokenizer, device
|
| 328 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 329 |
+
# Use float32 on CPU (bfloat16 is very slow on CPU); keep bfloat16 on GPU
|
| 330 |
+
dtype = torch.bfloat16 if device == "cuda" else torch.float32
|
| 331 |
+
|
| 332 |
+
print(f"Initializing {MODEL_NAME} on {device} with dtype={dtype}... (Diffusion Strategy Flag = {IS_DIFFUSION})")
|
| 333 |
+
|
| 334 |
if IS_DIFFUSION:
|
| 335 |
model = AutoModelForMaskedLM.from_pretrained(
|
| 336 |
MODEL_NAME,
|
| 337 |
+
torch_dtype=dtype,
|
| 338 |
trust_remote_code=True
|
| 339 |
).to(device).eval()
|
| 340 |
else:
|
| 341 |
model = AutoModelForCausalLM.from_pretrained(
|
| 342 |
MODEL_NAME,
|
| 343 |
+
torch_dtype=dtype,
|
| 344 |
trust_remote_code=False
|
| 345 |
).to(device).eval()
|
| 346 |
+
|
| 347 |
+
# Compile model only on GPU causal models; skip on CPU and diffusion
|
| 348 |
+
if device == "cuda" and not IS_DIFFUSION:
|
| 349 |
try:
|
| 350 |
model = torch.compile(model, mode="reduce-overhead", fullgraph=False)
|
| 351 |
print("Model compiled with torch.compile.")
|
| 352 |
except Exception as e:
|
| 353 |
print(f"torch.compile skipped: {e}")
|
| 354 |
else:
|
| 355 |
+
print("torch.compile skipped (CPU or diffusion).")
|
| 356 |
+
|
| 357 |
tokenizer = AutoTokenizer.from_pretrained(
|
| 358 |
MODEL_NAME,
|
| 359 |
trust_remote_code=IS_DIFFUSION
|
| 360 |
)
|
| 361 |
+
print("Model loaded into memory workspace.")
|
| 362 |
|
| 363 |
|
| 364 |
@app.route('/health', methods=['GET'])
|
|
|
|
| 381 |
{"role": "system", "content": system_prompt},
|
| 382 |
{"role": "user", "content": prompt}
|
| 383 |
]
|
|
|
|
| 384 |
encoded = tokenizer.apply_chat_template(
|
| 385 |
messages,
|
| 386 |
add_generation_prompt=True,
|
|
|
|
| 408 |
max_new_tokens=max_new_tokens,
|
| 409 |
temperature=temperature,
|
| 410 |
do_sample=True if temperature > 0 else False,
|
| 411 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 412 |
+
use_cache=True,
|
| 413 |
)
|
| 414 |
generated_ids = output_ids[0, input_ids.shape[-1]:]
|
| 415 |
generated_text = tokenizer.decode(generated_ids, skip_special_tokens=True)
|
|
|
|
| 462 |
output_ids = model.generate(
|
| 463 |
input_ids, max_new_tokens=max_new_tokens, temperature=temperature,
|
| 464 |
do_sample=True if temperature > 0 else False,
|
| 465 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 466 |
+
use_cache=True,
|
| 467 |
)
|
| 468 |
generated_ids = output_ids[0, input_ids.shape[-1]:]
|
| 469 |
generated_text = tokenizer.decode(generated_ids, skip_special_tokens=True)
|
|
|
|
| 516 |
temperature=temperature,
|
| 517 |
do_sample=True if temperature > 0 else False,
|
| 518 |
pad_token_id=tokenizer.eos_token_id,
|
| 519 |
+
use_cache=True,
|
| 520 |
)
|
| 521 |
|
| 522 |
def _generate():
|
|
|
|
| 528 |
|
| 529 |
accumulated = []
|
| 530 |
for text in streamer:
|
| 531 |
+
if not text:
|
| 532 |
continue
|
| 533 |
accumulated.append(text)
|
| 534 |
current = "".join(accumulated)
|