Gate filtered YOLO candidate and harden provenance
This commit is contained in:
+3
-1
@@ -337,7 +337,9 @@ docker exec \
|
||||
|
||||
The training wrapper is intentionally outside the product UI. It runs
|
||||
Ultralytics from the existing runtime, copies the best trained artifact to
|
||||
`TRAIN_MODEL_OUTPUT_PATH` and writes `training_summary.json`. Afterward, treat
|
||||
`TRAIN_MODEL_OUTPUT_PATH` and writes `training_summary.json`. The summary records
|
||||
SHA256 provenance for `dataset.yaml`, the available YOLO dataset summary, the
|
||||
local base model and the copied trained model. Afterward, treat
|
||||
the resulting `.pt` file like any other local model asset: verify preflight,
|
||||
run the real-data matrix and compare persisted QA/QC metrics before activating
|
||||
it as a useful default.
|
||||
|
||||
@@ -82,12 +82,21 @@ mkdir -p "${TRAIN_OUTPUT_DIR}" "$(dirname "${TRAIN_MODEL_OUTPUT_PATH}")"
|
||||
"${PYTHON_BIN}" - <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def sha256_file(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as handle:
|
||||
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def seed_ultralytics_font() -> None:
|
||||
font_candidates = [
|
||||
Path("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"),
|
||||
@@ -141,6 +150,17 @@ if not best_path.exists():
|
||||
raise SystemExit(f"Expected trained model artifact was not created: {best_path}")
|
||||
|
||||
shutil.copy2(best_path, trained_model_output_path)
|
||||
dataset_summary_path = next(
|
||||
(
|
||||
candidate
|
||||
for candidate in (
|
||||
dataset_yaml.parent / "yolo_tile_dataset_summary.json",
|
||||
dataset_yaml.parent / "yolo_dataset_summary.json",
|
||||
)
|
||||
if candidate.is_file()
|
||||
),
|
||||
None,
|
||||
)
|
||||
summary = {
|
||||
"status": "ok",
|
||||
"dataset_yaml": str(dataset_yaml),
|
||||
@@ -149,6 +169,11 @@ summary = {
|
||||
"train_run_name": run_name,
|
||||
"trained_model_path": str(trained_model_output_path),
|
||||
"best_artifact_path": str(best_path),
|
||||
"dataset_yaml_sha256": sha256_file(dataset_yaml),
|
||||
"dataset_summary_path": str(dataset_summary_path) if dataset_summary_path else None,
|
||||
"dataset_summary_sha256": sha256_file(dataset_summary_path) if dataset_summary_path else None,
|
||||
"base_model_sha256": sha256_file(base_model_path),
|
||||
"trained_model_sha256": sha256_file(trained_model_output_path),
|
||||
"epochs": epochs,
|
||||
"image_size": image_size,
|
||||
"batch_size": batch_size,
|
||||
|
||||
Reference in New Issue
Block a user