update from asus 106

This commit is contained in:
asus committed 2026-08-05 15:56:11 +07:00
1 parent 6637fb1302
commit 8285400254
28 files changed
+3215 -459

No files matched your search

+64 -69
View File
@@ -18,10 +18,12 @@ DEFAULT_IOU = 0.8
def start(batch_id: int, threshold: float = DEFAULT_THRESHOLD,
iou_threshold: float = DEFAULT_IOU, min_box_frac: float = 0.0,
resume: bool = False, engine: str = "sam3",
resume: bool = False, append: bool = False, engine: str = "base_model",
engines: Optional[List[str]] = None,
class_ids: Optional[List[int]] = None,
engine_classes: Optional[dict[str, List[str]]] = None) -> dict:
engine_classes: Optional[dict[str, List[str]]] = None,
custom_model_path: Optional[str] = None,
target_class_names: Optional[List[str]] = None) -> dict:
batch = batches.get(batch_id)
if batch is None:
raise batches.BatchError("No such batch")
@@ -34,8 +36,9 @@ def start(batch_id: int, threshold: float = DEFAULT_THRESHOLD,
"autolabel",
params={"batch_id": batch_id, "threshold": threshold,
"iou_threshold": iou_threshold, "min_box_frac": min_box_frac,
"resume": resume, "engine": active_engines[0], "engines": active_engines,
"class_ids": class_ids, "engine_classes": engine_classes},
"resume": resume, "append": append, "engine": active_engines[0], "engines": active_engines,
"class_ids": class_ids, "engine_classes": engine_classes,
"custom_model_path": custom_model_path, "target_class_names": target_class_names},
project_id=batch["project_id"],
batch_id=batch_id,
message=f"{batch['date_label']}/{batch['batch_label']} ({'+'.join(e.upper() for e in active_engines)})",
@@ -62,16 +65,7 @@ def _run_autolabel(job) -> None:
raise batches.BatchError("The batch disappeared before labeling started")
project = projects.get(batch["project_id"])
raw_active = job.params.get("engines") or [job.params.get("engine", "sam3")]
expanded_engines = []
for eng in raw_active:
if eng == "both":
expanded_engines.extend(["base_model", "secondary_model"])
elif eng == "sam3+model1":
expanded_engines.extend(["sam3", "base_model"])
else:
expanded_engines.append(eng)
expanded_engines = list(dict.fromkeys(expanded_engines))
selected_engine = job.params.get("engine", "base_model")
frames = batches.frames(batch["id"])
batches.set_status(batch["id"], "labeling")
@@ -86,42 +80,34 @@ def _run_autolabel(job) -> None:
attempted = 0
failures = []
from ultralytics import YOLO
m1_path = projects.training_start_point(project)
with db.cursor() as cur:
cur.execute("SELECT weights_path FROM model_versions WHERE project_id = ? ORDER BY version DESC LIMIT 1", (project["id"],))
row = cur.fetchone()
if row and os.path.isfile(row[0]):
m1_path = row[0]
yolo_models = {}
if "base_model" in expanded_engines or "yolo" in expanded_engines:
job.log(f"Loading Base/Trained Model: {os.path.basename(m1_path)}...")
yolo_models["base_model"] = YOLO(m1_path)
if "secondary_model" in expanded_engines:
m2_path = project["secondary_model_path"] if (project.get("secondary_model_path") and os.path.isfile(project["secondary_model_path"])) else m1_path
label_name = project.get("secondary_model_name") or os.path.basename(m2_path)
job.log(f"Loading Secondary Model: {label_name}...")
yolo_models["secondary_model"] = YOLO(m2_path)
allowed_class_ids = set(job.params["class_ids"]) if job.params.get("class_ids") is not None else None
engine_classes = job.params.get("engine_classes") or {}
conf = job.params.get("threshold", DEFAULT_THRESHOLD)
iou_thresh = job.params.get("iou_threshold", DEFAULT_IOU)
yolo_model = None
sam3_target_classes = []
if "sam3" in expanded_engines:
sam3_classes = engine_classes.get("sam3")
if sam3_classes is not None:
allowed_set = {c.strip().lower() for c in sam3_classes}
sam3_target_classes = [
c for c in project["classes"]
if c["name"].strip().lower() in allowed_set or c["prompt"].strip().lower() in allowed_set
]
custom_path = job.params.get("custom_model_path")
target_class_names = job.params.get("target_class_names")
if selected_engine == "sam3" and not custom_path:
allowed_classes_set = {c.strip().lower() for c in target_class_names} if target_class_names else None
if allowed_classes_set:
sam3_target_classes = [c for c in project["classes"] if c["name"].strip().lower() in allowed_classes_set or c["prompt"].strip().lower() in allowed_classes_set]
# Add any new target class names that aren't in project classes yet
existing_names = {c["name"].strip().lower() for c in project["classes"]}
for name in target_class_names:
if name.strip().lower() not in existing_names:
try:
updated_proj = projects.add_class(project["id"], name=name.strip(), prompt=name.strip())
project["classes"] = updated_proj["classes"]
for new_c in project["classes"]:
if new_c["name"].strip().lower() == name.strip().lower() and new_c not in sam3_target_classes:
sam3_target_classes.append(new_c)
except Exception:
pass
else:
sam3_target_classes = [
c for c in project["classes"]
if (allowed_class_ids is None or c["class_id"] in allowed_class_ids)
]
sam3_target_classes = [c for c in project["classes"]]
prompts = [c["prompt"] for c in sam3_target_classes]
if prompts:
from backend.sam3_engine import engine_is_loaded, get_engine
@@ -130,13 +116,27 @@ def _run_autolabel(job) -> None:
engine = get_engine()
job.log(f"SAM3 ready on {engine.device}; prompts: {', '.join(prompts)}")
else:
job.log("SAM3 selected but 0 prompts match class filter.")
job.log("SAM3 selected but 0 prompts match project classes.")
else:
from ultralytics import YOLO
if custom_path and os.path.isfile(custom_path):
m_path = custom_path
job.log(f"Loading Custom Model: {os.path.basename(m_path)}...")
else:
m_path = projects.training_start_point(project)
with db.cursor() as cur:
cur.execute("SELECT weights_path FROM model_versions WHERE project_id = ? ORDER BY version DESC LIMIT 1", (project["id"],))
row = cur.fetchone()
if row and os.path.isfile(row[0]):
m_path = row[0]
job.log(f"Loading Base Model: {os.path.basename(m_path)}...")
yolo_model = YOLO(m_path)
name_to_class_id = {item["name"].strip().lower(): item["class_id"] for item in project["classes"]}
conf = job.params.get("threshold", DEFAULT_THRESHOLD)
iou_thresh = job.params.get("iou_threshold", DEFAULT_IOU)
allowed_classes_set = {c.strip().lower() for c in target_class_names} if target_class_names else None
job.log(f"Starting multi-engine auto-labeling ({', '.join(expanded_engines)})...")
job.log(f"Starting auto-labeling with {selected_engine}...")
for index, frame in enumerate(frames):
if job.cancelled:
@@ -151,29 +151,21 @@ def _run_autolabel(job) -> None:
frame_file = os.path.join(directory, frame["filename"])
all_raw_detections = []
for eng_key, y_model in yolo_models.items():
allowed_for_eng = engine_classes.get(eng_key)
if allowed_for_eng is not None and len(allowed_for_eng) == 0:
continue
results = y_model.predict(frame_file, conf=conf, verbose=False)
if yolo_model is not None:
results = yolo_model.predict(frame_file, conf=conf, verbose=False)
if results and len(results) > 0:
model_names = results[0].names
for box in results[0].boxes:
cls_idx = int(box.cls[0].item())
cls_name = str(model_names.get(cls_idx, cls_idx)).strip().lower()
if allowed_for_eng is not None and cls_name not in [c.strip().lower() for c in allowed_for_eng]:
if allowed_classes_set is not None and cls_name not in allowed_classes_set:
continue
if cls_name not in name_to_class_id:
try:
updated_proj = projects.add_class(project["id"], {"name": cls_name, "prompt": cls_name})
project["classes"] = updated_proj["classes"]
name_to_class_id = {item["name"].strip().lower(): item["class_id"] for item in project["classes"]}
except Exception:
pass
if cls_name in name_to_class_id:
target_class_id = name_to_class_id[cls_name]
else:
target_class_id = name_to_class_id.get(cls_name)
if target_class_id is None:
continue
score = float(box.conf[0].item())
xyxyn = box.xyxyn[0].tolist()
all_raw_detections.append(labeling.Detection(
@@ -184,7 +176,7 @@ def _run_autolabel(job) -> None:
mask=None
))
if "sam3" in expanded_engines and sam3_target_classes:
elif selected_engine == "sam3" and sam3_target_classes:
prompts = [c["prompt"] for c in sam3_target_classes]
res = labeling.label_image(
frame_file, frame["filename"], prompts, conf,
@@ -208,7 +200,10 @@ def _run_autolabel(job) -> None:
for geometry in _geometries(det, frame["width"], frame["height"], project["label_type"]):
items.append({"class_id": det.class_id, "geometry": geometry, "score": det.score})
review.replace_auto(frame["id"], items)
if job.params.get("append"):
review.append_auto(frame["id"], items)
else:
review.replace_auto(frame["id"], items)
written += len(items)
job.progress(index + 1, len(frames), f"{frame['filename']}: {len(items)} shape(s)")
except Exception as exc: