feat: harden governed PyTorch training programme
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-26 17:18:42 +02:00
parent 2be72fac58
commit 36aa3177e7
8 changed files with 156 additions and 10 deletions
+10 -1
View File
@@ -3,7 +3,7 @@ set -euo pipefail
usage() {
cat <<'EOF'
Train a local operator YOLO building detector from an exported GeoIntel dataset.
Train a local operator YOLO detector from an exported, governed GeoIntel dataset.
Environment variables:
OPERATOR_YOLO_DATASET_DIR Directory containing dataset.yaml.
@@ -44,6 +44,7 @@ TRAIN_IMGSZ="${TRAIN_IMGSZ:-512}"
TRAIN_BATCH="${TRAIN_BATCH:-2}"
TRAIN_WORKERS="${TRAIN_WORKERS:-0}"
TRAIN_DEVICE="${TRAIN_DEVICE:-cpu}"
TRAIN_REQUIRE_CUDA="${TRAIN_REQUIRE_CUDA:-false}"
if [[ -z "${PYTHON_BIN:-}" ]]; then
if [[ -x "/opt/geointel/venv/bin/python" ]]; then
PYTHON_BIN="/opt/geointel/venv/bin/python"
@@ -64,6 +65,7 @@ export TRAIN_IMGSZ
export TRAIN_BATCH
export TRAIN_WORKERS
export TRAIN_DEVICE
export TRAIN_REQUIRE_CUDA
export PYTHON_BIN
export SUMMARY_PATH
@@ -116,6 +118,7 @@ def seed_ultralytics_font() -> None:
seed_ultralytics_font()
from ultralytics import YOLO
import torch
dataset_yaml = Path(os.environ["DATASET_YAML"])
base_model_path = Path(os.environ["YOLO_BASE_MODEL_PATH"])
@@ -128,6 +131,9 @@ image_size = int(os.environ["TRAIN_IMGSZ"])
batch_size = int(os.environ["TRAIN_BATCH"])
workers = int(os.environ["TRAIN_WORKERS"])
device = os.environ["TRAIN_DEVICE"]
require_cuda = os.environ["TRAIN_REQUIRE_CUDA"].strip().lower() in {"1", "true", "yes", "on"}
if require_cuda and (not device.lower().startswith("cuda") or not torch.cuda.is_available()):
raise SystemExit("TRAIN_REQUIRE_CUDA is enabled but the requested CUDA device is unavailable")
model = YOLO(str(base_model_path))
model.train(
@@ -179,6 +185,9 @@ summary = {
"batch_size": batch_size,
"workers": workers,
"device": device,
"cuda_required": require_cuda,
"cuda_available": torch.cuda.is_available(),
"torch_version": torch.__version__,
}
summary_path.parent.mkdir(parents=True, exist_ok=True)
summary_path.write_text(json.dumps(summary, indent=2, sort_keys=True), encoding="utf-8")