Download run_evaluation.py from roudone/Decider-4B: direct link, hf CLI and curl.
- Browser
- Download file 5.03 kB
-
https://huggingface.co/roudone/Decider-4B/resolve/main/run_evaluation.py
- Command line
-
hf download hf://roudone/Decider-4B/run_evaluation.py
-
curl -L -o run_evaluation.py https://huggingface.co/roudone/Decider-4B/resolve/main/run_evaluation.py
5.03 kB
| #!/usr/bin/env python3 | |
| """Launch this release's bundled vllm-fast-text runtime, evaluate the pinned test set, stop server.""" | |
| import argparse | |
| from datetime import datetime, timezone | |
| import hashlib | |
| import json | |
| import os | |
| from pathlib import Path | |
| import socket | |
| import subprocess | |
| import sys | |
| import time | |
| import urllib.request | |
| def verify_release(model): | |
| for line in (model / "SHA256SUMS").read_text().splitlines(): | |
| digest, name = line.split(" ", 1) | |
| rel = Path(name) | |
| if rel.is_absolute() or ".." in rel.parts: | |
| raise ValueError("非法 SHA256SUMS 路径: " + name) | |
| h = hashlib.sha256() | |
| with (model / rel).open("rb") as stream: | |
| for block in iter(lambda: stream.read(8 * 1024 * 1024), b""): | |
| h.update(block) | |
| if h.hexdigest() != digest: | |
| raise ValueError("发布文件已改变,请重新打包和评测: " + name) | |
| def main(): | |
| p = argparse.ArgumentParser(description=__doc__) | |
| p.add_argument("--model-dir", type=Path, required=True) | |
| p.add_argument("--output-dir", type=Path, required=True, | |
| help="必须是新目录,避免把不同模型的预测混用") | |
| p.add_argument("--port", type=int, default=8080) | |
| p.add_argument("--device", default="cuda") | |
| p.add_argument("--startup-timeout", type=float, default=900) | |
| a = p.parse_args() | |
| if sys.version_info < (3, 11): | |
| raise SystemExit("NeoHorse 推理需要 Python >= 3.11;请使用推理环境中的 python 执行。") | |
| import importlib.metadata | |
| model, out = a.model_dir.resolve(), a.output_dir.resolve() | |
| if out.exists(): | |
| raise SystemExit("评测输出目录已存在,请选择新目录。") | |
| verify_release(model) | |
| # Refuse an occupied port so a different running model cannot be scored by mistake. | |
| with socket.socket() as sock: | |
| sock.bind(("127.0.0.1", a.port)) | |
| out.mkdir(parents=True) | |
| try: | |
| gpu = subprocess.check_output(["nvidia-smi", "--query-gpu=name,memory.total,driver_version", | |
| "--format=csv,noheader"], text=True).strip() | |
| except (OSError, subprocess.CalledProcessError): | |
| gpu = "Unavailable (CPU or nvidia-smi unavailable)" | |
| versions = {} | |
| for name in ("torch", "transformers", "safetensors", "flash-linear-attention"): | |
| try: | |
| versions[name] = importlib.metadata.version(name) | |
| except importlib.metadata.PackageNotFoundError: | |
| versions[name] = "not installed" | |
| meta = json.loads((model / "model_manifest.json").read_text()) | |
| metadata = {"started_at": datetime.now(timezone.utc).isoformat(), "device": a.device, | |
| "gpu_inventory": gpu, "cuda_visible_devices": os.environ.get("CUDA_VISIBLE_DEVICES", "not set"), | |
| "python": sys.version, "versions": versions, "temperature": meta["temperature"], | |
| "backbone_dtype": "bfloat16", "head_dtype": "float32", | |
| "request_shape": "all five questions per case, serial HTTP requests, no warmup exclusion", | |
| "release_sha256sums_sha256": hashlib.sha256((model / "SHA256SUMS").read_bytes()).hexdigest()} | |
| (out / "run_metadata.json").write_text(json.dumps(metadata, indent=2) + "\n") | |
| env = os.environ.copy() | |
| # Bind to loopback only; do not inherit API authentication into a private local run. | |
| env.pop("NEOHORSE_API_KEY", None) | |
| # Launch the bundled vllm-fast-text adapter directly; it manages its own | |
| # PYTHONPATH for spawned vLLM workers and has no --device option. | |
| command = [sys.executable, str(model / "vllm-fast-text" / "server.py"), | |
| "--bundle", str(model), "--host", "127.0.0.1", "--port", str(a.port)] | |
| with (out / "server.log").open("w") as log: | |
| server = subprocess.Popen(command, env=env, stdout=log, stderr=subprocess.STDOUT) | |
| try: | |
| deadline = time.monotonic() + a.startup_timeout | |
| while True: | |
| if server.poll() is not None: | |
| raise RuntimeError("模型启动失败,请查看 " + str(out / "server.log")) | |
| try: | |
| with urllib.request.urlopen(f"http://127.0.0.1:{a.port}/healthz", timeout=2) as response: | |
| if response.status == 200: | |
| break | |
| except OSError: | |
| pass | |
| if time.monotonic() > deadline: | |
| raise RuntimeError("等待模型启动超时,请查看 server.log") | |
| time.sleep(1) | |
| subprocess.run([sys.executable, str(model / "evaluation_tools/evaluate.py"), | |
| "--endpoint", f"http://127.0.0.1:{a.port}/v1/systemone", | |
| "--output-dir", str(out)], check=True) | |
| finally: | |
| server.terminate() | |
| try: | |
| server.wait(timeout=15) | |
| except subprocess.TimeoutExpired: | |
| server.kill() | |
| server.wait() | |
| if __name__ == "__main__": | |
| main() | |