ClemSummer Claude Opus 5 commited on
Commit
2f4f0ba
Β·
1 Parent(s): 1bbb27c

Fix Space startup crash: drop device_map="auto" for CPU inference

Browse files

On HF cpu-basic, accelerate's "auto" device_map split Qwen across
devices and marked layers for disk offload. PEFT then failed applying
the LoRA adapter over that offload index:

KeyError: 'base_model.model.model.model.embed_tokens'

which killed the uvicorn import of main.py and put the Space in
RUNTIME_ERROR. Load the model whole and move it to the device instead,
and use float32 off-GPU since fp16 on CPU is slow with unimplemented ops.

Also load the model lazily on first /contentdistillery request, so a
model problem can no longer take down captioning and cbow with it, and
strip a stray merge-conflict marker from README.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files changed (2) hide show
  1. README.md +2 -1
  2. ppo_logic.py +39 -15
README.md CHANGED
@@ -14,4 +14,5 @@ This Hugging Face Space includes multiple AI tools:
14
  - πŸ–ΌοΈ ViT image captioning
15
  - πŸ“ PPO-based Reddit summarization (coming soon)
16
 
17
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference<<<<<<< HEAD
 
 
14
  - πŸ–ΌοΈ ViT image captioning
15
  - πŸ“ PPO-based Reddit summarization (coming soon)
16
 
17
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
18
+
ppo_logic.py CHANGED
@@ -5,6 +5,7 @@ from transformers import AutoTokenizer, AutoModelForCausalLM
5
  from peft import PeftModel
6
  import argparse
7
  import os
 
8
 
9
  # -------------------------------
10
  # Config
@@ -15,28 +16,52 @@ CHECKPOINT_DIR = "./qwen_loRA"
15
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
16
  MAX_NEW_TOKENS = 256
17
 
 
 
 
18
  # -------------------------------
19
- # Load tokenizer and model
20
  # -------------------------------
21
- print("πŸ”„ Loading tokenizer and model...")
22
- tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
23
- tokenizer.pad_token = tokenizer.eos_token
 
 
 
 
 
24
 
25
- base_model = AutoModelForCausalLM.from_pretrained(
26
- MODEL_NAME,
27
- torch_dtype=torch.float16,
28
- device_map="auto",
29
- trust_remote_code=True
30
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- model = PeftModel.from_pretrained(base_model, CHECKPOINT_DIR)
33
- model.eval()
34
- model = model.to(DEVICE)
35
 
36
  # -------------------------------
37
  # Generate Summary
38
  # -------------------------------
39
  def generate_summary(post: str) -> str:
 
 
40
  #prompt = f"Instruction: Summarize the post in one sentence.\n\nPost:\n{post}\n\nSummary:"
41
  # prompt = f"Please summarize the following Reddit post in 1–2 sentences:\n\n{post}\n\nSummary:"
42
  prompt = f"Instruction: Summarize the post in 1-2 sentences.\n\nPost:\n{post}\n\nSummary:"
@@ -50,7 +75,6 @@ def generate_summary(post: str) -> str:
50
  do_sample=False,
51
  # top_k=50,
52
  # top_p=0.95,
53
- temperature=1.0,
54
  pad_token_id=tokenizer.pad_token_id,
55
  use_cache=True
56
  )
@@ -71,4 +95,4 @@ if __name__ == "__main__":
71
  print("\nπŸ€– Generating summary...\n")
72
 
73
  summary = generate_summary(args.post)
74
- print("βœ… Summary:\n", summary)
 
5
  from peft import PeftModel
6
  import argparse
7
  import os
8
+ import threading
9
 
10
  # -------------------------------
11
  # Config
 
16
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
17
  MAX_NEW_TOKENS = 256
18
 
19
+ # fp16 is a GPU-only win here: on CPU it is slow and some ops are unimplemented.
20
+ DTYPE = torch.float16 if DEVICE.type == "cuda" else torch.float32
21
+
22
  # -------------------------------
23
+ # Load tokenizer and model (lazily, on first summary request)
24
  # -------------------------------
25
+ _tokenizer = None
26
+ _model = None
27
+ _load_lock = threading.Lock()
28
+
29
+
30
+ def _load():
31
+ """Load the base model + LoRA adapter once, on first use."""
32
+ global _tokenizer, _model
33
 
34
+ with _load_lock:
35
+ if _model is not None:
36
+ return _tokenizer, _model
37
+
38
+ print("πŸ”„ Loading tokenizer and model...")
39
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
40
+ tokenizer.pad_token = tokenizer.eos_token
41
+
42
+ # No device_map="auto": on a CPU-only box accelerate splits the model and
43
+ # offloads layers, which breaks the PEFT adapter load. Load whole, then move.
44
+ base_model = AutoModelForCausalLM.from_pretrained(
45
+ MODEL_NAME,
46
+ torch_dtype=DTYPE,
47
+ trust_remote_code=True
48
+ )
49
+
50
+ model = PeftModel.from_pretrained(base_model, CHECKPOINT_DIR)
51
+ model.eval()
52
+ model = model.to(DEVICE)
53
+
54
+ _tokenizer, _model = tokenizer, model
55
+ print("βœ… Model ready on", DEVICE)
56
+ return _tokenizer, _model
57
 
 
 
 
58
 
59
  # -------------------------------
60
  # Generate Summary
61
  # -------------------------------
62
  def generate_summary(post: str) -> str:
63
+ tokenizer, model = _load()
64
+
65
  #prompt = f"Instruction: Summarize the post in one sentence.\n\nPost:\n{post}\n\nSummary:"
66
  # prompt = f"Please summarize the following Reddit post in 1–2 sentences:\n\n{post}\n\nSummary:"
67
  prompt = f"Instruction: Summarize the post in 1-2 sentences.\n\nPost:\n{post}\n\nSummary:"
 
75
  do_sample=False,
76
  # top_k=50,
77
  # top_p=0.95,
 
78
  pad_token_id=tokenizer.pad_token_id,
79
  use_cache=True
80
  )
 
95
  print("\nπŸ€– Generating summary...\n")
96
 
97
  summary = generate_summary(args.post)
98
+ print("βœ… Summary:\n", summary)