Skip to content

Commit 2df4e9e

Browse files
Xrekiclaude
andcommitted
Refactor extract_sample return to ExtractionStatus enum and split success rates.
- Introduce ExtractionStatus(str, Enum): OK, VERIFY_FAILED, EXTRACT_FAILED, ERROR - GraphNetAgent.extract_sample() now returns ExtractionStatus instead of bool - parallel_extract tracks and prints both overall and extraction-only success rates - Per-GPU/Worker summary also shows both rates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0bdf25b commit 2df4e9e

4 files changed

Lines changed: 79 additions & 24 deletions

File tree

graph_net/agent/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
from Hugging Face models.
66
"""
77

8-
from graph_net.agent.graph_net_agent import GraphNetAgent
8+
from graph_net.agent.graph_net_agent import ExtractionStatus, GraphNetAgent
99

10-
__all__ = ["GraphNetAgent"]
10+
__all__ = ["GraphNetAgent", "ExtractionStatus"]

graph_net/agent/graph_net_agent.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
import os
5+
from enum import Enum
56
from pathlib import Path
67
from typing import Optional
78

@@ -23,6 +24,15 @@
2324
from graph_net.agent.sample_verifier import ForwardVerifier
2425

2526

27+
class ExtractionStatus(str, Enum):
28+
"""Extraction result status for a single model."""
29+
30+
OK = "ok"
31+
VERIFY_FAILED = "verify_failed"
32+
EXTRACT_FAILED = "extract_failed"
33+
ERROR = "error"
34+
35+
2636
class GraphNetAgent:
2737
"""GraphNet automatic sample extraction agent"""
2838

@@ -77,7 +87,7 @@ def __init__(
7787
# LLM fixer — only created when llm_retry is requested
7888
self.llm_fixer: Optional[LLMCodeFixer] = LLMCodeFixer() if llm_retry else None
7989

80-
def extract_sample(self, model_id: str) -> bool:
90+
def extract_sample(self, model_id: str) -> ExtractionStatus:
8191
"""
8292
Execute complete sample extraction pipeline from HuggingFace model ID.
8393
@@ -89,7 +99,10 @@ def extract_sample(self, model_id: str) -> bool:
8999
model_id: HuggingFace model ID (e.g., "bert-base-uncased")
90100
91101
Returns:
92-
True if sample extraction succeeded, False otherwise
102+
ExtractionStatus.OK – extraction and verification both passed
103+
ExtractionStatus.VERIFY_FAILED – extraction succeeded but verification failed
104+
ExtractionStatus.EXTRACT_FAILED – extraction (or pre-extraction) failed
105+
ExtractionStatus.ERROR – unexpected error
93106
"""
94107
try:
95108
self.logger.info(f"Starting extraction for model: {model_id}")
@@ -111,21 +124,24 @@ def extract_sample(self, model_id: str) -> bool:
111124

112125
if self.is_duplicate_sample(sample_dir):
113126
self.logger.info("Duplicate sample detected, skipping verification")
114-
return True
127+
return ExtractionStatus.OK
115128

116129
if not self.sample_verifier.verify(sample_dir):
117130
self.logger.error("Sample verification failed")
118-
return False
131+
return ExtractionStatus.VERIFY_FAILED
119132

120133
self.logger.info(f"Successfully extracted sample for {model_id}")
121-
return True
134+
return ExtractionStatus.OK
122135

123-
except (AnalysisError, CodeGenError, ExtractionError, VerificationError) as e:
136+
except VerificationError as e:
124137
self.logger.error(f"Extraction failed for {model_id}: {e}")
125-
return False
138+
return ExtractionStatus.VERIFY_FAILED
139+
except (AnalysisError, CodeGenError, ExtractionError) as e:
140+
self.logger.error(f"Extraction failed for {model_id}: {e}")
141+
return ExtractionStatus.EXTRACT_FAILED
126142
except Exception as e:
127143
self.logger.error(f"Unexpected error for {model_id}: {e}", exc_info=True)
128-
return False
144+
return ExtractionStatus.ERROR
129145

130146
def _llm_retry(
131147
self,

graph_net/agent/parallel_extract.py

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
if str(_GRAPHNET_ROOT) not in sys.path:
3838
sys.path.insert(0, str(_GRAPHNET_ROOT))
3939

40-
from graph_net.agent import GraphNetAgent # noqa: E402
40+
from graph_net.agent import ExtractionStatus, GraphNetAgent # noqa: E402
4141

4242
import torch # noqa: E402
4343

@@ -212,15 +212,18 @@ def worker_fn(
212212
"model_id": model_id,
213213
}
214214
try:
215-
success = agent.extract_sample(model_id)
215+
status = agent.extract_sample(model_id)
216216
elapsed = time.time() - t0
217-
status = "OK" if success else "FAIL"
218-
print(f"{prefix} {status} {model_id} ({elapsed:.1f}s)", flush=True)
219-
result_dict["success"] = success
217+
ok = status == ExtractionStatus.OK
218+
label = "OK" if ok else status.name.replace("_", " ")
219+
print(f"{prefix} {label} {model_id} ({elapsed:.1f}s)", flush=True)
220+
result_dict["success"] = ok
221+
result_dict["status"] = status.value
220222
except Exception as e:
221223
elapsed = time.time() - t0
222224
print(f"{prefix} ERROR {model_id}: {e} ({elapsed:.1f}s)", flush=True)
223225
result_dict["success"] = False
226+
result_dict["status"] = ExtractionStatus.ERROR.value
224227
result_dict["error"] = str(e)
225228

226229
result_dict["elapsed"] = round(elapsed, 2)
@@ -246,31 +249,49 @@ def _print_summary(results: Dict) -> None:
246249
details = results.get("details", [])
247250
total = len(details)
248251
success = sum(1 for d in details if d.get("success"))
252+
extract_success = sum(
253+
1
254+
for d in details
255+
if d.get("status")
256+
in (ExtractionStatus.OK.value, ExtractionStatus.VERIFY_FAILED.value)
257+
)
249258
failed = total - success
250259
rate = (success / total * 100) if total else 0.0
260+
extract_rate = (extract_success / total * 100) if total else 0.0
251261
print("\n" + "=" * 60)
252262
print("[SUMMARY] Parallel Extraction Summary")
253263
print("=" * 60)
254-
print(f" Total : {total}")
255-
print(f" Success: {success}")
256-
print(f" Failed : {failed}")
257-
print(f" Rate : {rate:.2f}%")
264+
print(f" Total : {total}")
265+
print(f" Success : {success} (verify ok)")
266+
print(f" Extract : {extract_success} (graph extracted)")
267+
print(f" Failed : {failed}")
268+
print(f" Rate : {rate:.2f}% (overall)")
269+
print(f" Extract : {extract_rate:.2f}% (extraction only)")
258270
# Per-GPU breakdown
259271
gpu_stats: Dict[int, Dict] = {}
260272
for d in details:
261273
g = d.get("gpu", -1)
262274
if g not in gpu_stats:
263-
gpu_stats[g] = {"total": 0, "success": 0}
275+
gpu_stats[g] = {"total": 0, "success": 0, "extract": 0}
264276
gpu_stats[g]["total"] += 1
265277
if d.get("success"):
266278
gpu_stats[g]["success"] += 1
279+
if d.get("status") in (
280+
ExtractionStatus.OK.value,
281+
ExtractionStatus.VERIFY_FAILED.value,
282+
):
283+
gpu_stats[g]["extract"] += 1
267284

268285
label = "GPU" if results.get("gpus") else "Worker"
269286
print(f"\n Per-{label}:")
270287
for g in sorted(gpu_stats):
271288
gs = gpu_stats[g]
272289
gr = (gs["success"] / gs["total"] * 100) if gs["total"] else 0.0
273-
print(f" {label} {g}: {gs['success']}/{gs['total']} ({gr:.1f}%)")
290+
er = (gs["extract"] / gs["total"] * 100) if gs["total"] else 0.0
291+
print(
292+
f" {label} {g}: success={gs['success']}/{gs['total']} ({gr:.1f}%), "
293+
f"extract={gs['extract']}/{gs['total']} ({er:.1f}%)"
294+
)
274295
print("=" * 60)
275296

276297

@@ -448,10 +469,17 @@ def main() -> int:
448469
entry = result_queue.get(timeout=5)
449470
details.append(entry)
450471
done = len(details)
451-
success_so_far = sum(1 for d in details if d.get("success"))
472+
ok_so_far = sum(1 for d in details if d.get("success"))
473+
extract_ok_so_far = sum(
474+
1
475+
for d in details
476+
if d.get("status")
477+
in (ExtractionStatus.OK.value, ExtractionStatus.VERIFY_FAILED.value)
478+
)
452479
print(
453480
f"[PROGRESS] {done}/{len(model_ids)} done, "
454-
f"success rate so far: {success_so_far/done*100:.1f}%",
481+
f"success={ok_so_far/done*100:.1f}%, "
482+
f"extract={extract_ok_so_far/done*100:.1f}%",
455483
flush=True,
456484
)
457485
except Exception:
@@ -466,6 +494,12 @@ def main() -> int:
466494

467495
end_time = datetime.now()
468496
success_count = sum(1 for d in details if d.get("success"))
497+
extract_success_count = sum(
498+
1
499+
for d in details
500+
if d.get("status")
501+
in (ExtractionStatus.OK.value, ExtractionStatus.VERIFY_FAILED.value)
502+
)
469503
results = {
470504
"start_time": start_time.isoformat(),
471505
"end_time": end_time.isoformat(),
@@ -474,12 +508,17 @@ def main() -> int:
474508
"workspace": workspace,
475509
"total": len(details),
476510
"success": success_count,
511+
"extract_success": extract_success_count,
477512
"failed": len(details) - success_count,
478513
"success_rate": 0.0,
514+
"extract_success_rate": 0.0,
479515
"details": details,
480516
}
481517
if results["total"] > 0:
482518
results["success_rate"] = round(results["success"] / results["total"] * 100, 2)
519+
results["extract_success_rate"] = round(
520+
results["extract_success"] / results["total"] * 100, 2
521+
)
483522

484523
# --- Save results ---
485524
output_file = (

graph_net/agent/sample_verifier/forward_verifier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ForwardVerifier(BaseSampleVerifier):
4141
is verified independently; all must pass.
4242
"""
4343

44-
def __init__(self, timeout: int | None = 300):
44+
def __init__(self, timeout: int = 300):
4545
"""
4646
Args:
4747
timeout: seconds to wait for each forward-pass subprocess

0 commit comments

Comments
 (0)