Skip to content

Commit 6653494

Browse files
committed
Fix eval and dashboard for FujitsuResearch/OneCompressionn PR 23
1 parent 8c63cbe commit 6653494

6 files changed

Lines changed: 91 additions & 23 deletions

File tree

dashboard/README.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ mkdir -p tmp/redis
116116

117117
. .venv/bin/activate
118118
export ONECOMP_DEVICE=cuda
119+
# Local model root — required on worker **and** API when using short local names
120+
# instead of a Hugging Face repo id. See Environment variables.
121+
export LOCAL_MODEL_ROOT="$(pwd)/models"
119122
# Required on nodes without nvcc (CUDA toolkit); see Environment variables below
120123
export VLLM_USE_FLASHINFER_SAMPLER=0
121124
nohup uv run python start_worker.py > /tmp/worker.log 2>&1 &
@@ -130,6 +133,7 @@ srun --jobid=41229 --pty bash # replace 41229 with your JOBID
130133
cd backend/
131134
. .venv/bin/activate
132135
export ONECOMP_DEVICE=cuda
136+
export LOCAL_MODEL_ROOT="$(pwd)/models"
133137
uv run python start_backend.py --reload --port 8001
134138
```
135139

@@ -230,7 +234,33 @@ tail -80 /tmp/vllm-<job-id>.log # when vLLM fails
230234

231235
## Environment variables
232236

233-
All use the `ONECOMP_` prefix. HPC defaults live in `backend/app/core/config.py`.
237+
`ONECOMP_*` settings default in `backend/app/core/config.py`. Other variables
238+
below are read directly from the process environment.
239+
240+
### `LOCAL_MODEL_ROOT` (local model directory)
241+
242+
Set this **before starting both the Celery worker and the API** when jobs use
243+
short local directory names (e.g. `gemma-2-2b-it`) rather than a Hugging Face
244+
repo id (`org/model`). The server maps `model_name` to
245+
`{LOCAL_MODEL_ROOT}/<model_name>` for job validation and quantization.
246+
247+
| Variable | Default | Description |
248+
|---|---|---|
249+
| `LOCAL_MODEL_ROOT` | `/models` | Root directory of pre-downloaded models on shared storage |
250+
251+
Example (run from `backend/`; models live in `backend/models/`):
252+
253+
```bash
254+
export LOCAL_MODEL_ROOT="$(pwd)/models"
255+
```
256+
257+
Use the **same value** in Terminal A (worker) and Terminal B (API). If only
258+
one process has it, jobs may pass validation but fail during quantization with
259+
“not a local folder” / Hugging Face Hub errors.
260+
261+
After changing `LOCAL_MODEL_ROOT`, restart **both** processes (step **3**).
262+
263+
### `ONECOMP_*` (application settings)
234264

235265
| Variable | Default (HPC) | Description |
236266
|---|---|---|
@@ -261,6 +291,7 @@ works but the CUDA toolkit is not installed.
261291
pkill -f start_worker.py
262292
cd backend && . .venv/bin/activate
263293
export ONECOMP_DEVICE=cuda
294+
export LOCAL_MODEL_ROOT="$(pwd)/models"
264295
export VLLM_USE_FLASHINFER_SAMPLER=0
265296
nohup uv run python start_worker.py > /tmp/worker.log 2>&1 &
266297
```
@@ -273,7 +304,9 @@ does not propagate to the worker.
273304
```bash
274305
pkill -f start_worker.py
275306
cd backend && . .venv/bin/activate
276-
ONECOMP_DEVICE=cuda nohup uv run python start_worker.py > /tmp/worker.log 2>&1 &
307+
export ONECOMP_DEVICE=cuda
308+
export LOCAL_MODEL_ROOT="$(pwd)/models"
309+
nohup uv run python start_worker.py > /tmp/worker.log 2>&1 &
277310
```
278311

279312
---
@@ -310,6 +343,7 @@ See [troubleshooting in docs/setup-hpc.md](docs/setup-hpc.md#5-troubleshooting)
310343
| SSH tunnel established but API unreachable | Point `LocalForward` at the GPU node name |
311344
| Chat is slow / keeps polling | `ONECOMP_DEVICE=cuda`, then Stop → Deploy |
312345
| Deploy fails: `Could not find nvcc` | `VLLM_USE_FLASHINFER_SAMPLER=0` on the **worker**, restart worker, Stop → Deploy ([#10](docs/setup-hpc.md#10-vllm-deploy-fails--could-not-find-nvcc)) |
346+
| Local model name fails / “not a local folder” on HF | Set the same `LOCAL_MODEL_ROOT` on **worker and API**, restart both; model dir must be `{LOCAL_MODEL_ROOT}/<name>/` |
313347

314348
### Separating the vLLM venv
315349

dashboard/backend/app/api/jobs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
JobListResponse,
1616
JobResponse,
1717
)
18-
from app.services.huggingface import check_model_exists
18+
from app.services.huggingface import check_model_exists, resolve_model_identifier
1919
from app.services.inference import chat_vllm, stop_inference
2020
from app.worker.celery_app import celery_app
2121
from app.worker.tasks import chat_with_model, deploy_model, run_quantization
@@ -98,7 +98,7 @@ def estimate_wbits(body: EstimateWbitsRequest) -> EstimateWbitsResponse:
9898

9999
try:
100100
result = estimate_wbits_from_vram(
101-
body.model_name,
101+
resolve_model_identifier(body.model_name),
102102
vram_ratio=body.vram_ratio,
103103
total_vram_gb=body.total_vram_gb,
104104
group_size=body.group_size,

dashboard/backend/app/services/huggingface.py

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,67 @@
77

88
import logging
99
import os
10+
from pathlib import Path
1011

1112
import httpx
1213

1314
logger = logging.getLogger(__name__)
1415

1516
_HF_API_BASE = "https://huggingface.co/api/models"
1617
_TIMEOUT = httpx.Timeout(10.0, connect=5.0)
18+
_LOCAL_MODEL_ROOT_ENV = "LOCAL_MODEL_ROOT"
19+
_DEFAULT_LOCAL_MODEL_ROOT = "/models"
1720

1821

19-
def check_model_exists(model_id: str) -> None:
20-
"""Raise ``ValueError`` if ``model_id`` is not resolvable on HuggingFace Hub.
22+
def _local_model_root() -> Path:
23+
return Path(
24+
os.environ.get(_LOCAL_MODEL_ROOT_ENV, _DEFAULT_LOCAL_MODEL_ROOT),
25+
).resolve()
26+
27+
28+
def _local_model_dir(model_id: str) -> Path | None:
29+
"""Return the resolved local model directory when it exists under the allowed root."""
30+
root = _local_model_root()
31+
candidate = (root / model_id).resolve()
32+
try:
33+
candidate.relative_to(root)
34+
except ValueError:
35+
return None
36+
return candidate if candidate.is_dir() else None
37+
38+
39+
def resolve_model_identifier(model_id: str) -> str:
40+
"""Normalize *model_id* and map local names to an absolute filesystem path.
2141
22-
A local path that exists on disk is treated as a valid model identifier,
23-
matching ``transformers.AutoConfig.from_pretrained`` behaviour. This is
24-
important when callers point at an already-downloaded model directory.
42+
Short identifiers such as ``gemma-2-2b-it`` that exist under
43+
``LOCAL_MODEL_ROOT`` are returned as absolute paths so downstream loaders
44+
(``ModelConfig``, ``transformers``) use the local snapshot instead of
45+
HuggingFace Hub.
2546
"""
26-
if not model_id or not model_id.strip():
47+
normalized = model_id.strip()
48+
if not normalized:
2749
raise ValueError("Model name must not be empty.")
2850

29-
model_id = model_id.strip()
51+
absolute = Path(normalized)
52+
if absolute.is_absolute() and absolute.is_dir():
53+
return str(absolute.resolve())
54+
55+
local_dir = _local_model_dir(normalized)
56+
if local_dir is not None:
57+
return str(local_dir)
58+
return normalized
59+
60+
61+
def check_model_exists(model_id: str) -> None:
62+
"""Raise ``ValueError`` if ``model_id`` is not resolvable on HuggingFace Hub.
63+
64+
A model directory under ``LOCAL_MODEL_ROOT`` (default ``/models``) is
65+
treated as a valid local identifier. This matches the deployment layout
66+
where already-downloaded models live on shared storage.
67+
"""
68+
model_id = resolve_model_identifier(model_id)
3069

31-
# Local path takes precedence (matches transformers' resolution order).
32-
if os.path.isdir(model_id):
70+
if Path(model_id).is_dir():
3371
return
3472

3573
token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN")

dashboard/backend/app/worker/tasks.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from app.core.config import settings
1313
from app.core.database import SessionLocal
1414
from app.models.job import Job
15+
from app.services.huggingface import resolve_model_identifier
1516
from app.services.job_store import update_job
1617
from app.worker.celery_app import celery_app
1718

@@ -136,7 +137,8 @@ def _run_real_quantization(job_id: str, model_name: str, quant_method: str, para
136137
update_job(job_id, progress=5)
137138

138139
quant_device = "cuda" if settings.device == "cuda" else "cpu"
139-
model_config = ModelConfig(model_id=model_name, device=quant_device)
140+
resolved_model = resolve_model_identifier(model_name)
141+
model_config = ModelConfig(model_id=resolved_model, device=quant_device)
140142

141143
try:
142144
quantizer_name, force_qep = QUANTIZER_MAP[quant_method]
@@ -164,7 +166,7 @@ def _run_real_quantization(job_id: str, model_name: str, quant_method: str, para
164166

165167
groupsize = 128
166168
est = estimate_wbits_from_vram(
167-
model_name,
169+
resolved_model,
168170
total_vram_gb=params.get("total_vram_gb"),
169171
group_size=groupsize,
170172
logger=logger,

onecomp/eval/evals/mt_bench/judge.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,8 @@ def judge_answers(
104104
f"{probed}"
105105
)
106106

107-
client_kwargs: dict = {
108-
"api_key": api_key,
109-
"base_url": _resolve_judge_base_url(judge_api_base),
110-
}
111-
logger.info("[JUDGE] Using base_url=%s", client_kwargs["base_url"])
112-
client = OpenAI(**client_kwargs)
107+
logger.info("[JUDGE] Initializing judge client")
108+
client = OpenAI(api_key=api_key, base_url=_resolve_judge_base_url(judge_api_base))
113109

114110
question_file = data_dir / "question.jsonl"
115111
questions = {q["question_id"]: q for q in load_questions(question_file)}

onecomp/eval/orchestrator/server.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,6 @@ def _build_argv(self) -> list[str]:
234234
str(self.cfg.max_model_len),
235235
"--dtype",
236236
dtype,
237-
"--api-key",
238-
self.cfg.api_key,
239237
]
240238
if self.cfg.trust_remote_code:
241239
argv.append("--trust-remote-code")

0 commit comments

Comments
 (0)