Spaces:
Running on Zero
Running on Zero
Small files from the Hub, shards from the mount (size-checked); drop flash-linear-attention (no GPU at import on ZeroGPU)
Browse files- app.py +27 -3
- requirements.txt +0 -1
app.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
| 1 |
"""Chat with Whittle-Qwen-3.8-45B-A3B on ZeroGPU.
|
| 2 |
|
| 3 |
-
The model repo is mounted read-only at /models/w45 (no 90 GB download into the Space). The 35 B body runs on a full
|
| 4 |
RTX PRO 6000 (xlarge); the 10 B n-gram table stays in CPU memory, as with llama.cpp's `-ot per_layer_token_embd=CPU`.
|
| 5 |
"""
|
| 6 |
import os
|
|
|
|
| 7 |
import threading
|
| 8 |
|
| 9 |
import spaces # must come before torch/CUDA use on ZeroGPU
|
|
@@ -15,8 +16,31 @@ from whittle_load import load_whittle
|
|
| 15 |
|
| 16 |
REPO = "logic65/Whittle-Qwen-3.8-45B-A3B"
|
| 17 |
MOUNT = "/models/w45"
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
tokenizer = AutoTokenizer.from_pretrained(SOURCE)
|
| 21 |
model = load_whittle(SOURCE, dtype=torch.bfloat16, device_map="cuda").eval()
|
| 22 |
|
|
|
|
| 1 |
"""Chat with Whittle-Qwen-3.8-45B-A3B on ZeroGPU.
|
| 2 |
|
| 3 |
+
The model repo is mounted read-only at /models/w45 (no 90 GB download into the Space); small files come from the Hub. The 35 B body runs on a full
|
| 4 |
RTX PRO 6000 (xlarge); the 10 B n-gram table stays in CPU memory, as with llama.cpp's `-ot per_layer_token_embd=CPU`.
|
| 5 |
"""
|
| 6 |
import os
|
| 7 |
+
import shutil
|
| 8 |
import threading
|
| 9 |
|
| 10 |
import spaces # must come before torch/CUDA use on ZeroGPU
|
|
|
|
| 16 |
|
| 17 |
REPO = "logic65/Whittle-Qwen-3.8-45B-A3B"
|
| 18 |
MOUNT = "/models/w45"
|
| 19 |
+
LOCAL = "/tmp/w45"
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def prepare_local_dir() -> str:
|
| 23 |
+
"""Small files (config, index, tokenizer, template) come straight from the Hub; the weight shards are read from the
|
| 24 |
+
read-only mount through symlinks, after checking every shard's size on the mount against the Hub."""
|
| 25 |
+
from huggingface_hub import HfApi, hf_hub_download
|
| 26 |
+
files = {f.path: f.size for f in HfApi().list_repo_tree(REPO) if "/" not in f.path and getattr(f, "size", None) is not None}
|
| 27 |
+
os.makedirs(LOCAL, exist_ok=True)
|
| 28 |
+
for name, size in sorted(files.items()):
|
| 29 |
+
dst = os.path.join(LOCAL, name)
|
| 30 |
+
if name.endswith(".safetensors"):
|
| 31 |
+
src = os.path.join(MOUNT, name)
|
| 32 |
+
got = os.path.getsize(src) if os.path.exists(src) else None
|
| 33 |
+
print(f"[mount] {name}: Hub {size:,} B, mount {got if got is None else f'{got:,} B'}", flush=True)
|
| 34 |
+
if got != size:
|
| 35 |
+
raise RuntimeError(f"{name} on the mount does not match the Hub ({got} vs {size} bytes)")
|
| 36 |
+
if not os.path.lexists(dst):
|
| 37 |
+
os.symlink(src, dst)
|
| 38 |
+
elif not name.endswith((".md", ".svg", ".py")) and name != ".gitattributes":
|
| 39 |
+
shutil.copy(hf_hub_download(REPO, name), dst)
|
| 40 |
+
return LOCAL
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
SOURCE = prepare_local_dir()
|
| 44 |
tokenizer = AutoTokenizer.from_pretrained(SOURCE)
|
| 45 |
model = load_whittle(SOURCE, dtype=torch.bfloat16, device_map="cuda").eval()
|
| 46 |
|
requirements.txt
CHANGED
|
@@ -3,4 +3,3 @@ transformers>=5.18.0
|
|
| 3 |
accelerate
|
| 4 |
safetensors
|
| 5 |
huggingface_hub>=1.0
|
| 6 |
-
flash-linear-attention==0.5.2
|
|
|
|
| 3 |
accelerate
|
| 4 |
safetensors
|
| 5 |
huggingface_hub>=1.0
|
|
|