Validate uploaded YOLO custom workflow
This commit is contained in:
11
README.md
11
README.md
@@ -78,10 +78,13 @@ heatmap/segmentation artifacts, training curves, and weight manifest status.
|
|||||||
The same panel can run `POST /api/acceptance/smoke`, a lightweight live smoke
|
The same panel can run `POST /api/acceptance/smoke`, a lightweight live smoke
|
||||||
that creates an upload dataset, uploads a label, downloads it through the
|
that creates an upload dataset, uploads a label, downloads it through the
|
||||||
artifact API, runs a mock job, checks SSE log streaming, and executes one
|
artifact API, runs a mock job, checks SSE log streaming, and executes one
|
||||||
legacy image/label overlay job on tiny generated PNGs. It also runs model
|
legacy image/label overlay job on tiny generated PNGs. It also launches
|
||||||
family readiness checks: a SegModel/SMP forward pass, a YOLO segmentation
|
`yolo.predict_custom` and `yolo.heatmap_custom` through the normal job queue
|
||||||
prediction on a tiny image, MMSeg config parsing, and local MMSeg pretrained
|
against the uploaded sample image, proving that upload datasets can produce
|
||||||
weight discovery. MMSeg full-model readiness is validated in
|
browsable segmentation and heatmap artifacts. It also runs model family
|
||||||
|
readiness checks: a SegModel/SMP forward pass, a YOLO segmentation prediction
|
||||||
|
on a tiny image, MMSeg config parsing, and local MMSeg pretrained weight
|
||||||
|
discovery. MMSeg full-model readiness is validated in
|
||||||
`SEG_MMSEG_CONDA_ENV` by importing `mmcv._ext` and building a local MMSeg
|
`SEG_MMSEG_CONDA_ENV` by importing `mmcv._ext` and building a local MMSeg
|
||||||
`EncoderDecoder` from the existing config tree.
|
`EncoderDecoder` from the existing config tree.
|
||||||
|
|
||||||
|
|||||||
@@ -267,6 +267,19 @@ def _write_acceptance_images(root: Path) -> tuple[Path, Path, Path]:
|
|||||||
return image_path, label_path, result_dir
|
return image_path, label_path, result_dir
|
||||||
|
|
||||||
|
|
||||||
|
def _relative_to_project(path: Path) -> str:
|
||||||
|
try:
|
||||||
|
return str(path.resolve().relative_to(settings.project_root))
|
||||||
|
except ValueError:
|
||||||
|
return str(path.resolve())
|
||||||
|
|
||||||
|
|
||||||
|
def _result_files(root: Path, suffixes: set[str]) -> list[Path]:
|
||||||
|
if not root.exists():
|
||||||
|
return []
|
||||||
|
return sorted(path for path in root.rglob("*") if path.is_file() and path.suffix.lower() in suffixes)
|
||||||
|
|
||||||
|
|
||||||
def run_model_family_readiness() -> dict[str, Any]:
|
def run_model_family_readiness() -> dict[str, Any]:
|
||||||
"""Exercise the model-family runtime stack without launching full training."""
|
"""Exercise the model-family runtime stack without launching full training."""
|
||||||
source = settings.source_root
|
source = settings.source_root
|
||||||
@@ -501,6 +514,61 @@ def run_live_acceptance(base_url: str = "http://127.0.0.1:8010") -> dict[str, An
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
yolo_weight = settings.source_root / "Seg_All_In_One_YoloModel" / "yolo11n-seg.pt"
|
||||||
|
uploaded_image_source = settings.project_root / "var" / "uploads" / "datasets" / dataset_name / "images"
|
||||||
|
predict_name = f"{dataset_name}_predict_smoke"
|
||||||
|
predict = _create_job_and_wait(
|
||||||
|
base_url,
|
||||||
|
"yolo.predict_custom",
|
||||||
|
{
|
||||||
|
"weights": str(yolo_weight),
|
||||||
|
"source": _relative_to_project(uploaded_image_source),
|
||||||
|
"project": "var/custom_yolo_runs",
|
||||||
|
"name": predict_name,
|
||||||
|
"imgsz": 64,
|
||||||
|
"conf": 0.05,
|
||||||
|
"device": "cpu",
|
||||||
|
"exist_ok": True,
|
||||||
|
},
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
predict_root = settings.project_root / "var" / "custom_yolo_runs" / predict_name
|
||||||
|
predict_outputs = _result_files(predict_root, {".png", ".jpg", ".jpeg"})
|
||||||
|
checks.append(
|
||||||
|
{
|
||||||
|
"name": "uploaded_yolo_predict_job_runner",
|
||||||
|
"passed": predict.get("passed", False) and bool(predict_outputs),
|
||||||
|
"detail": {**predict, "output_count": len(predict_outputs), "outputs": [_relative_to_project(path) for path in predict_outputs[:8]]},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
heatmap_name = f"{dataset_name}_heatmap_smoke"
|
||||||
|
heatmap = _create_job_and_wait(
|
||||||
|
base_url,
|
||||||
|
"yolo.heatmap_custom",
|
||||||
|
{
|
||||||
|
"weights": str(yolo_weight),
|
||||||
|
"source": _relative_to_project(uploaded_image_source),
|
||||||
|
"project": "var/custom_yolo_runs",
|
||||||
|
"name": heatmap_name,
|
||||||
|
"model_key": "YOLO11n-seg",
|
||||||
|
"pt_name": "best.pt",
|
||||||
|
"cam_method": "GradCAM",
|
||||||
|
"target_layers": "model.model.model[9]",
|
||||||
|
"limit": 1,
|
||||||
|
},
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
heatmap_root = settings.project_root / "var" / "custom_yolo_runs" / heatmap_name / "HeartMap_Visual"
|
||||||
|
heatmap_outputs = _result_files(heatmap_root, {".jpg", ".jpeg", ".png"})
|
||||||
|
checks.append(
|
||||||
|
{
|
||||||
|
"name": "uploaded_yolo_heatmap_job_runner",
|
||||||
|
"passed": heatmap.get("passed", False) and len(heatmap_outputs) >= 2,
|
||||||
|
"detail": {**heatmap, "output_count": len(heatmap_outputs), "outputs": [_relative_to_project(path) for path in heatmap_outputs[:8]]},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
mock = _create_job_and_wait(base_url, "mock.echo", {"message": f"acceptance {run_id}"}, timeout=45)
|
mock = _create_job_and_wait(base_url, "mock.echo", {"message": f"acceptance {run_id}"}, timeout=45)
|
||||||
mock_log = mock.get("polled", {}).get("job", {}).get("log_tail", "")
|
mock_log = mock.get("polled", {}).get("job", {}).get("log_tail", "")
|
||||||
checks.append({"name": "mock_job_runner", "passed": mock.get("passed", False) and f"acceptance {run_id}" in mock_log, "detail": mock})
|
checks.append({"name": "mock_job_runner", "passed": mock.get("passed", False) and f"acceptance {run_id}" in mock_log, "detail": mock})
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ def evaluate_project() -> dict:
|
|||||||
"deep_acceptance_api": "/api/acceptance/deep" in backend_text,
|
"deep_acceptance_api": "/api/acceptance/deep" in backend_text,
|
||||||
"deep_acceptance_ui": "runDeepAcceptance" in frontend_text and "深度训练" in frontend_text,
|
"deep_acceptance_ui": "runDeepAcceptance" in frontend_text and "深度训练" in frontend_text,
|
||||||
"deep_yolo_heatmap_validation": "yolo_tiny_heatmap_generation" in acceptance_text,
|
"deep_yolo_heatmap_validation": "yolo_tiny_heatmap_generation" in acceptance_text,
|
||||||
|
"uploaded_yolo_workflow_acceptance": "uploaded_yolo_predict_job_runner" in acceptance_text and "uploaded_yolo_heatmap_job_runner" in acceptance_text,
|
||||||
"agent_api": "/api/agents/evaluate" in backend_text and "/api/agents/validate" in backend_text,
|
"agent_api": "/api/agents/evaluate" in backend_text and "/api/agents/validate" in backend_text,
|
||||||
"agent_panel_ui": "runAgentValidation" in frontend_text and "评价建议" in frontend_text and "Validation Agent" in frontend_text,
|
"agent_panel_ui": "runAgentValidation" in frontend_text and "评价建议" in frontend_text and "Validation Agent" in frontend_text,
|
||||||
"coverage_api": "/api/coverage" in backend_text and coverage["task_build_passed"],
|
"coverage_api": "/api/coverage" in backend_text and coverage["task_build_passed"],
|
||||||
@@ -83,7 +84,7 @@ def evaluate_project() -> dict:
|
|||||||
if coverage["unmapped_user_scripts"]:
|
if coverage["unmapped_user_scripts"]:
|
||||||
suggestions.append(f"Map remaining user-facing scripts: {len(coverage['unmapped_user_scripts'])}")
|
suggestions.append(f"Map remaining user-facing scripts: {len(coverage['unmapped_user_scripts'])}")
|
||||||
if not suggestions:
|
if not suggestions:
|
||||||
suggestions.append("Current platform covers the requested control-plane features, uploaded YOLO dataset train/predict/heatmap actions, and synthetic deep training/heatmap acceptance; next focus is running a real user-supplied dataset through the full workflow.")
|
suggestions.append("Current platform covers the requested control-plane features, uploaded YOLO dataset train/predict/heatmap actions, live uploaded-data YOLO predict/heatmap acceptance, and synthetic deep training acceptance; next focus is a real non-synthetic dataset run.")
|
||||||
|
|
||||||
score = sum(1 for item in checks if item["passed"]) / max(len(checks), 1)
|
score = sum(1 for item in checks if item["passed"]) / max(len(checks), 1)
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user