Add model family readiness smoke

This commit is contained in:
2026-06-30 13:08:44 +08:00
parent bf9b5c33e0
commit 4d80ec4d75
4 changed files with 104 additions and 2 deletions

View File

@@ -1,6 +1,8 @@
from __future__ import annotations
import json
import subprocess
import sys
import time
import uuid
import urllib.error
@@ -11,6 +13,22 @@ from typing import Any
from .config import settings
def _run_snippet(code: str, cwd: Path | None = None, timeout: int = 60) -> dict[str, Any]:
result = subprocess.run(
[sys.executable, "-c", code],
cwd=str(cwd or settings.project_root),
capture_output=True,
text=True,
timeout=timeout,
)
return {
"passed": result.returncode == 0,
"returncode": result.returncode,
"stdout": result.stdout[-4000:],
"stderr": result.stderr[-4000:],
}
def _request_json(method: str, url: str, payload: dict[str, Any] | None = None, timeout: int = 10) -> dict[str, Any]:
data = None
headers = {"Accept": "application/json"}
@@ -122,6 +140,68 @@ def _write_acceptance_images(root: Path) -> tuple[Path, Path, Path]:
return image_path, label_path, result_dir
def run_model_family_readiness() -> dict[str, Any]:
"""Exercise the model-family runtime stack without launching full training."""
source = settings.source_root
yolo_weight = source / "Seg_All_In_One_YoloModel" / "yolo11n-seg.pt"
mmseg_config = source / "Seg_All_In_One_MMSeg" / "configs" / "fcn" / "fcn_r18-d8_4xb2-80k_cityscapes-512x1024.py"
mmseg_pretrained = source / "Seg_All_In_One_MMSeg" / "My_Local_Model" / "mmcls" / "resnet18.pth"
checks = [
{
"name": "segmodel_smp_forward",
"required": True,
"detail": _run_snippet(
"import torch, segmentation_models_pytorch as smp; "
"m=smp.Unet(encoder_name='resnet18', encoder_weights=None, classes=2).eval(); "
"torch.set_grad_enabled(False); y=m(torch.randn(1,3,64,64)); "
"print(tuple(y.shape))"
),
},
{
"name": "yolo_seg_predict_cpu",
"required": True,
"detail": _run_snippet(
"from ultralytics import YOLO; import numpy as np; "
f"model=YOLO({str(yolo_weight)!r}); "
"r=model.predict(np.zeros((64,64,3), dtype=np.uint8), imgsz=64, verbose=False, save=False, device='cpu'); "
"print(len(r), r[0].orig_shape)"
),
},
{
"name": "mmseg_config_parse",
"required": True,
"detail": _run_snippet(
"from mmengine.config import Config; "
f"cfg=Config.fromfile({str(mmseg_config)!r}); "
"print(cfg.model.type, cfg.train_dataloader.batch_size)"
),
},
{
"name": "mmseg_local_pretrained_weight",
"required": True,
"detail": {"passed": mmseg_pretrained.exists(), "path": str(mmseg_pretrained), "size": mmseg_pretrained.stat().st_size if mmseg_pretrained.exists() else 0},
},
{
"name": "mmseg_full_model_build",
"required": False,
"detail": _run_snippet(
"from mmengine.config import Config; from mmseg.registry import MODELS; "
f"cfg=Config.fromfile({str(mmseg_config)!r}); "
"model=MODELS.build(cfg.model); print(type(model).__name__)",
timeout=90,
),
},
]
for check in checks:
check["passed"] = bool(check["detail"].get("passed"))
return {
"passed": all(item["passed"] for item in checks if item["required"]),
"warnings": [item for item in checks if not item["required"] and not item["passed"]],
"checks": checks,
}
def latest_acceptance_report() -> dict[str, Any]:
path = settings.project_root / "var" / "acceptance" / "latest.json"
if not path.exists():
@@ -188,12 +268,16 @@ def run_live_acceptance(base_url: str = "http://127.0.0.1:8010") -> dict[str, An
}
)
readiness = run_model_family_readiness()
checks.append({"name": "model_family_readiness", "passed": readiness["passed"], "detail": readiness})
report = {
"available": True,
"run_id": run_id,
"base_url": base_url,
"passed": all(item["passed"] for item in checks),
"checks": checks,
"model_family_readiness": readiness,
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
}
latest = acceptance_root / "latest.json"