feat: learn framework architecture incompatibilities
This commit is contained in:
@@ -8,6 +8,7 @@ from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
|
||||
from architecture_compatibility import architecture_compatibility_key, architecture_profile
|
||||
from llm_classifier import LLMAssistedClassifier
|
||||
from models import ModelInspection
|
||||
from common import parse_datetime, utc_now
|
||||
@@ -150,10 +151,16 @@ class CandidatePreflightAdvisor:
|
||||
self._llm_blocks = 0
|
||||
self._context_clamps = 0
|
||||
self._ambiguous = 0
|
||||
self._architecture_blocks_applied = 0
|
||||
self._feedback_stats: dict[str, Any] = {}
|
||||
self._architecture_compatibility_blocks: dict[str, dict[str, Any]] = {}
|
||||
|
||||
def set_feedback_stats(self, report: dict[str, Any] | None) -> None:
|
||||
self._feedback_stats = report if isinstance(report, dict) else {}
|
||||
raw_blocks = self._feedback_stats.get("architectureCompatibilityBlocks") or {}
|
||||
self._architecture_compatibility_blocks = (
|
||||
raw_blocks if isinstance(raw_blocks, dict) else {}
|
||||
)
|
||||
for gpu, value in (self._feedback_stats.get("observedGpuMemoryGiB") or {}).items():
|
||||
try:
|
||||
memory_gib = float(value)
|
||||
@@ -190,6 +197,24 @@ class CandidatePreflightAdvisor:
|
||||
with self._lock:
|
||||
self._assessed += 1
|
||||
|
||||
learned_block = self._matching_architecture_block(
|
||||
inspection=inspection,
|
||||
target_gpu=target_gpu,
|
||||
framework=framework,
|
||||
task_type=task_type,
|
||||
)
|
||||
if learned_block is not None:
|
||||
metadata["architectureCompatibilityBlock"] = learned_block
|
||||
with self._lock:
|
||||
self._architecture_blocks_applied += 1
|
||||
return self._hard_block(
|
||||
config_params,
|
||||
"preflight_learned_architecture_incompatible",
|
||||
warnings,
|
||||
ambiguous,
|
||||
metadata,
|
||||
)
|
||||
|
||||
# Empty file_paths means an injected/test inspection lacks structural
|
||||
# metadata. Real discoveries with an empty tree already fail the weight
|
||||
# compatibility gate, so do not make this test/fallback state a blocker.
|
||||
@@ -389,6 +414,33 @@ class CandidatePreflightAdvisor:
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
def _matching_architecture_block(
|
||||
self,
|
||||
*,
|
||||
inspection: ModelInspection,
|
||||
target_gpu: str,
|
||||
framework: str,
|
||||
task_type: str,
|
||||
) -> dict[str, Any] | None:
|
||||
profile = architecture_profile(inspection.model_type, inspection.architectures)
|
||||
if profile is None:
|
||||
return None
|
||||
key = architecture_compatibility_key(
|
||||
target_gpu,
|
||||
framework,
|
||||
task_type,
|
||||
profile["signature"],
|
||||
)
|
||||
if key is None:
|
||||
return None
|
||||
block = self._architecture_compatibility_blocks.get(key)
|
||||
if not isinstance(block, dict):
|
||||
return None
|
||||
expires_at = parse_datetime(block.get("expiresAt"))
|
||||
if expires_at is None or expires_at <= utc_now():
|
||||
return None
|
||||
return dict(block)
|
||||
|
||||
def summary(self) -> dict[str, Any]:
|
||||
with self._lock:
|
||||
summary = {
|
||||
@@ -397,6 +449,10 @@ class CandidatePreflightAdvisor:
|
||||
"hardBlocks": self._hard_blocks,
|
||||
"llmBlocks": self._llm_blocks,
|
||||
"ambiguousCandidates": self._ambiguous,
|
||||
"architectureCompatibilityBlocksLoaded": len(
|
||||
self._architecture_compatibility_blocks
|
||||
),
|
||||
"architectureCompatibilityBlocksApplied": self._architecture_blocks_applied,
|
||||
"contextLengthClamps": self._context_clamps,
|
||||
"knownGpuMemoryGiB": dict(self.gpu_memory_gib),
|
||||
"gpuMemoryEvidence": dict(self.gpu_memory_evidence),
|
||||
|
||||
Reference in New Issue
Block a user