jmullings commited on
Commit ·
2a92766
1
Parent(s): 61da2de
Responsiveness update
Browse files- app.py +6 -10
- src/audit/engine.py +222 -168
- src/display/css_html_js.py +70 -4
- src/display/formatting.py +16 -8
- src/submission/submit.py +21 -28
app.py
CHANGED
|
@@ -2,10 +2,11 @@ import os
|
|
| 2 |
import sys
|
| 3 |
import warnings
|
| 4 |
|
| 5 |
-
# Suppress Gradio
|
| 6 |
-
warnings.filterwarnings("ignore", category=DeprecationWarning
|
|
|
|
|
|
|
| 7 |
|
| 8 |
-
# Completely disable experimental Gradio 5 SSR sidecar
|
| 9 |
os.environ["GRADIO_SSR"] = "0"
|
| 10 |
os.environ["GRADIO_SSR_MODE"] = "0"
|
| 11 |
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
|
@@ -15,7 +16,6 @@ import gradio as gr
|
|
| 15 |
import pandas as pd
|
| 16 |
from gradio_leaderboard import Leaderboard, SelectColumns
|
| 17 |
|
| 18 |
-
# Add current directory and src subdirectories to Python path
|
| 19 |
CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
|
| 20 |
sys.path.insert(0, CURRENT_DIR)
|
| 21 |
for sub in ["src", "src/display", "src/submission", "src/leaderboard", "src/audit"]:
|
|
@@ -263,13 +263,13 @@ with demo:
|
|
| 263 |
with gr.Column(scale=3):
|
| 264 |
search_or_audit_input = gr.Textbox(
|
| 265 |
label="🔍 Search Registry or Enter Hugging Face Model URL to Audit",
|
| 266 |
-
placeholder="e.g.
|
| 267 |
lines=1,
|
| 268 |
max_lines=1,
|
| 269 |
show_label=True,
|
| 270 |
)
|
| 271 |
trust_remote_code_checkbox = gr.Checkbox(
|
| 272 |
-
label="Trust Remote Code (enabled for custom architectures like MiniCPM / Supra / DeepSeek
|
| 273 |
value=True,
|
| 274 |
)
|
| 275 |
audit_button = gr.Button("🔬 SCAN & AUDIT MODEL", variant="primary")
|
|
@@ -280,7 +280,6 @@ with demo:
|
|
| 280 |
|
| 281 |
leaderboard_table = init_leaderboard(LEADERBOARD_DF)
|
| 282 |
|
| 283 |
-
# Audit & Search events
|
| 284 |
audit_button.click(
|
| 285 |
fn=audit_or_search_model,
|
| 286 |
inputs=[search_or_audit_input, trust_remote_code_checkbox],
|
|
@@ -292,21 +291,18 @@ with demo:
|
|
| 292 |
outputs=[status_box, leaderboard_table, top_cards_display, results_display_panel],
|
| 293 |
)
|
| 294 |
|
| 295 |
-
# Leaderboard row/cell click -> updates results display
|
| 296 |
leaderboard_table.select(
|
| 297 |
fn=on_select_model,
|
| 298 |
inputs=[leaderboard_table],
|
| 299 |
outputs=[results_display_panel],
|
| 300 |
)
|
| 301 |
|
| 302 |
-
# Top 3 card click -> updates results display
|
| 303 |
hidden_card_btn.click(
|
| 304 |
fn=on_top_card_click,
|
| 305 |
inputs=[hidden_card_input],
|
| 306 |
outputs=[results_display_panel],
|
| 307 |
)
|
| 308 |
|
| 309 |
-
# Self-healing refresh on mount
|
| 310 |
demo.load(fn=refresh_dashboard, outputs=[leaderboard_table, top_cards_display])
|
| 311 |
|
| 312 |
with gr.Row():
|
|
|
|
| 2 |
import sys
|
| 3 |
import warnings
|
| 4 |
|
| 5 |
+
# Suppress Gradio and third-party deprecation warnings
|
| 6 |
+
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
| 7 |
+
warnings.filterwarnings("ignore", category=FutureWarning)
|
| 8 |
+
warnings.filterwarnings("ignore", category=UserWarning)
|
| 9 |
|
|
|
|
| 10 |
os.environ["GRADIO_SSR"] = "0"
|
| 11 |
os.environ["GRADIO_SSR_MODE"] = "0"
|
| 12 |
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
|
|
|
| 16 |
import pandas as pd
|
| 17 |
from gradio_leaderboard import Leaderboard, SelectColumns
|
| 18 |
|
|
|
|
| 19 |
CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
|
| 20 |
sys.path.insert(0, CURRENT_DIR)
|
| 21 |
for sub in ["src", "src/display", "src/submission", "src/leaderboard", "src/audit"]:
|
|
|
|
| 263 |
with gr.Column(scale=3):
|
| 264 |
search_or_audit_input = gr.Textbox(
|
| 265 |
label="🔍 Search Registry or Enter Hugging Face Model URL to Audit",
|
| 266 |
+
placeholder="e.g. Qwen/Qwen2.5-0.5B-Instruct or MiniMaxAI/MiniMax-Music3",
|
| 267 |
lines=1,
|
| 268 |
max_lines=1,
|
| 269 |
show_label=True,
|
| 270 |
)
|
| 271 |
trust_remote_code_checkbox = gr.Checkbox(
|
| 272 |
+
label="Trust Remote Code (enabled for custom architectures like MiniCPM / Supra / DeepSeek)",
|
| 273 |
value=True,
|
| 274 |
)
|
| 275 |
audit_button = gr.Button("🔬 SCAN & AUDIT MODEL", variant="primary")
|
|
|
|
| 280 |
|
| 281 |
leaderboard_table = init_leaderboard(LEADERBOARD_DF)
|
| 282 |
|
|
|
|
| 283 |
audit_button.click(
|
| 284 |
fn=audit_or_search_model,
|
| 285 |
inputs=[search_or_audit_input, trust_remote_code_checkbox],
|
|
|
|
| 291 |
outputs=[status_box, leaderboard_table, top_cards_display, results_display_panel],
|
| 292 |
)
|
| 293 |
|
|
|
|
| 294 |
leaderboard_table.select(
|
| 295 |
fn=on_select_model,
|
| 296 |
inputs=[leaderboard_table],
|
| 297 |
outputs=[results_display_panel],
|
| 298 |
)
|
| 299 |
|
|
|
|
| 300 |
hidden_card_btn.click(
|
| 301 |
fn=on_top_card_click,
|
| 302 |
inputs=[hidden_card_input],
|
| 303 |
outputs=[results_display_panel],
|
| 304 |
)
|
| 305 |
|
|
|
|
| 306 |
demo.load(fn=refresh_dashboard, outputs=[leaderboard_table, top_cards_display])
|
| 307 |
|
| 308 |
with gr.Row():
|
src/audit/engine.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
| 1 |
import importlib
|
| 2 |
import io
|
|
|
|
| 3 |
import logging
|
| 4 |
import math
|
|
|
|
| 5 |
import re
|
| 6 |
import subprocess
|
| 7 |
import sys
|
|
@@ -15,11 +17,10 @@ import numpy as np
|
|
| 15 |
import scipy.linalg as la
|
| 16 |
|
| 17 |
# -----------------------------------------------------------------------------
|
| 18 |
-
# 1. Transformers Backward Compatibility & Legacy Polyfills
|
| 19 |
# -----------------------------------------------------------------------------
|
| 20 |
def apply_transformers_backward_compatibility_patches():
|
| 21 |
"""Polyfills legacy transformers classes and utilities that custom modeling scripts on Hugging Face expect."""
|
| 22 |
-
# 1. DynamicCache backwards compatibility
|
| 23 |
try:
|
| 24 |
from transformers.cache_utils import DynamicCache
|
| 25 |
if not hasattr(DynamicCache, "from_legacy_cache"):
|
|
@@ -34,7 +35,6 @@ def apply_transformers_backward_compatibility_patches():
|
|
| 34 |
except Exception:
|
| 35 |
pass
|
| 36 |
|
| 37 |
-
# 2. LLaMA legacy attention classes (LlamaFlashAttention2, LlamaSdpaAttention)
|
| 38 |
try:
|
| 39 |
import transformers.models.llama.modeling_llama as llama_mod
|
| 40 |
llama_attn = getattr(llama_mod, "LlamaAttention", None)
|
|
@@ -46,7 +46,6 @@ def apply_transformers_backward_compatibility_patches():
|
|
| 46 |
except Exception:
|
| 47 |
pass
|
| 48 |
|
| 49 |
-
# 3. Mistral legacy attention classes
|
| 50 |
try:
|
| 51 |
import transformers.models.mistral.modeling_mistral as mistral_mod
|
| 52 |
mistral_attn = getattr(mistral_mod, "MistralAttention", None)
|
|
@@ -58,7 +57,6 @@ def apply_transformers_backward_compatibility_patches():
|
|
| 58 |
except Exception:
|
| 59 |
pass
|
| 60 |
|
| 61 |
-
# 4. Qwen2 legacy attention classes
|
| 62 |
try:
|
| 63 |
import transformers.models.qwen2.modeling_qwen2 as qwen2_mod
|
| 64 |
qwen2_attn = getattr(qwen2_mod, "Qwen2Attention", None)
|
|
@@ -70,7 +68,6 @@ def apply_transformers_backward_compatibility_patches():
|
|
| 70 |
except Exception:
|
| 71 |
pass
|
| 72 |
|
| 73 |
-
# 5. Gemma legacy attention classes
|
| 74 |
try:
|
| 75 |
import transformers.models.gemma.modeling_gemma as gemma_mod
|
| 76 |
gemma_attn = getattr(gemma_mod, "GemmaAttention", None)
|
|
@@ -82,7 +79,6 @@ def apply_transformers_backward_compatibility_patches():
|
|
| 82 |
except Exception:
|
| 83 |
pass
|
| 84 |
|
| 85 |
-
# 6. Legacy import_utils functions (e.g., is_torch_fx_available)
|
| 86 |
try:
|
| 87 |
import transformers.utils.import_utils as import_utils
|
| 88 |
if not hasattr(import_utils, "is_torch_fx_available"):
|
|
@@ -105,7 +101,6 @@ def apply_transformers_backward_compatibility_patches():
|
|
| 105 |
pass
|
| 106 |
|
| 107 |
|
| 108 |
-
# Apply baseline patches on module load
|
| 109 |
apply_transformers_backward_compatibility_patches()
|
| 110 |
|
| 111 |
|
|
@@ -156,12 +151,13 @@ def try_auto_install_packages(error_msg: str) -> bool:
|
|
| 156 |
|
| 157 |
|
| 158 |
# -----------------------------------------------------------------------------
|
| 159 |
-
# 3. Universal Safe Config Proxy & Fallbacks
|
| 160 |
# -----------------------------------------------------------------------------
|
| 161 |
-
class SafeFallbackNode:
|
| 162 |
-
"""Universal null-safe node that
|
| 163 |
-
|
| 164 |
def __init__(self, name=""):
|
|
|
|
| 165 |
self._name = name
|
| 166 |
|
| 167 |
def __getattr__(self, name):
|
|
@@ -177,20 +173,25 @@ class SafeFallbackNode:
|
|
| 177 |
return 0
|
| 178 |
return SafeFallbackNode(name=name)
|
| 179 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
def __getitem__(self, key):
|
|
|
|
|
|
|
| 181 |
return SafeFallbackNode(name=str(key))
|
| 182 |
|
| 183 |
def __call__(self, *args, **kwargs):
|
| 184 |
return SafeFallbackNode()
|
| 185 |
|
| 186 |
def __bool__(self):
|
| 187 |
-
return
|
| 188 |
|
| 189 |
def __len__(self):
|
| 190 |
-
return
|
| 191 |
-
|
| 192 |
-
def __iter__(self):
|
| 193 |
-
return iter([])
|
| 194 |
|
| 195 |
def __str__(self):
|
| 196 |
return ""
|
|
@@ -199,8 +200,13 @@ class SafeFallbackNode:
|
|
| 199 |
return f"<SafeFallbackNode:{self._name}>"
|
| 200 |
|
| 201 |
def get(self, key, default=None):
|
|
|
|
|
|
|
| 202 |
return default if default is not None else SafeFallbackNode(name=str(key))
|
| 203 |
|
|
|
|
|
|
|
|
|
|
| 204 |
|
| 205 |
def make_auto_healing_config(base_config):
|
| 206 |
"""Wraps and mutates any PretrainedConfig so missing attributes or
|
|
@@ -314,17 +320,41 @@ def silence_specific_warnings():
|
|
| 314 |
|
| 315 |
|
| 316 |
# -----------------------------------------------------------------------------
|
| 317 |
-
# 4. Safe Transformers Import
|
| 318 |
# -----------------------------------------------------------------------------
|
| 319 |
try:
|
| 320 |
import torch
|
| 321 |
import transformers
|
| 322 |
-
from transformers import AutoConfig, AutoModel, AutoModelForCausalLM, AutoTokenizer
|
| 323 |
HAS_TRANSFORMERS = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
except ImportError:
|
| 325 |
HAS_TRANSFORMERS = False
|
| 326 |
|
| 327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
class AuditError(Exception):
|
| 329 |
"""Raised whenever an audit cannot be completed."""
|
| 330 |
|
|
@@ -386,6 +416,18 @@ CALIBRATION_CORPUS_TEXTS = _build_calibration_corpus()
|
|
| 386 |
MIN_TOKEN_TO_DIM_RATIO = 5.0
|
| 387 |
|
| 388 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
def ledoit_wolf_shrinkage_covariance(X: np.ndarray) -> np.ndarray:
|
| 390 |
N, D = X.shape
|
| 391 |
if N < 2:
|
|
@@ -504,7 +546,7 @@ def check_feasibility(
|
|
| 504 |
max_params_billion: float = 10.0,
|
| 505 |
trust_remote_code: bool = True,
|
| 506 |
) -> FeasibilityResult:
|
| 507 |
-
from huggingface_hub import HfApi
|
| 508 |
|
| 509 |
try:
|
| 510 |
api = HfApi(token=token)
|
|
@@ -520,7 +562,6 @@ def check_feasibility(
|
|
| 520 |
)
|
| 521 |
return FeasibilityResult(False, f"Could not verify repository metadata on HF Hub: {e}", None, None)
|
| 522 |
|
| 523 |
-
# Detect GGUF quantization repository
|
| 524 |
siblings = [s.rfilename for s in getattr(info, "siblings", [])] if hasattr(info, "siblings") else []
|
| 525 |
is_gguf_repo = (
|
| 526 |
"-gguf" in model_id.lower()
|
|
@@ -567,40 +608,22 @@ def check_feasibility(
|
|
| 567 |
architecture = None
|
| 568 |
apply_transformers_backward_compatibility_patches()
|
| 569 |
|
| 570 |
-
|
| 571 |
with silence_specific_warnings():
|
| 572 |
try:
|
| 573 |
-
cfg = AutoConfig.from_pretrained(model_id, revision=revision, token=token, trust_remote_code=
|
| 574 |
cfg = make_auto_healing_config(cfg)
|
| 575 |
architecture = type(cfg).__name__
|
| 576 |
except Exception:
|
| 577 |
-
# 2. Fallback to trust_remote_code=True for custom architectures
|
| 578 |
try:
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
cfg = AutoConfig.from_pretrained(model_id, revision=revision, token=token, trust_remote_code=trust_remote_code)
|
| 588 |
-
cfg = make_auto_healing_config(cfg)
|
| 589 |
-
architecture = type(cfg).__name__
|
| 590 |
-
except Exception as e3:
|
| 591 |
-
return FeasibilityResult(
|
| 592 |
-
False,
|
| 593 |
-
f"Could not load model configuration after dependency installation: {e3}",
|
| 594 |
-
param_count_b,
|
| 595 |
-
None,
|
| 596 |
-
)
|
| 597 |
-
else:
|
| 598 |
-
return FeasibilityResult(
|
| 599 |
-
False,
|
| 600 |
-
f"Could not load model configuration: {e2}.",
|
| 601 |
-
param_count_b,
|
| 602 |
-
None,
|
| 603 |
-
)
|
| 604 |
|
| 605 |
return FeasibilityResult(True, "ok", param_count_b, architecture)
|
| 606 |
|
|
@@ -612,119 +635,141 @@ class TransformerAuditorBackend:
|
|
| 612 |
|
| 613 |
self.model_id = model_id
|
| 614 |
self.device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
|
|
| 615 |
|
| 616 |
-
|
| 617 |
-
progress_callback(f"Downloading tokenizer & weight tensors for '{model_id}'...")
|
| 618 |
-
print(f"[LLM-X-RAY] Downloading model '{model_id}' on {self.device}...", flush=True)
|
| 619 |
|
| 620 |
apply_transformers_backward_compatibility_patches()
|
| 621 |
|
| 622 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 623 |
try:
|
| 624 |
model_config = AutoConfig.from_pretrained(
|
| 625 |
model_id, revision=revision, token=token, trust_remote_code=trust_remote_code
|
| 626 |
)
|
| 627 |
model_config = make_auto_healing_config(model_config)
|
| 628 |
except Exception:
|
| 629 |
-
model_config =
|
|
|
|
| 630 |
|
| 631 |
-
|
|
|
|
|
|
|
|
|
|
| 632 |
with silence_specific_warnings():
|
| 633 |
try:
|
| 634 |
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 635 |
model_id, revision=revision, token=token, trust_remote_code=trust_remote_code
|
| 636 |
)
|
| 637 |
-
except Exception
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 642 |
-
model_id, revision=revision, token=token, trust_remote_code=trust_remote_code
|
| 643 |
-
)
|
| 644 |
-
except Exception:
|
| 645 |
-
self.tokenizer = None
|
| 646 |
-
else:
|
| 647 |
self.tokenizer = None
|
| 648 |
|
| 649 |
-
|
| 650 |
-
try:
|
| 651 |
-
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 652 |
-
model_id, revision=revision, token=token, trust_remote_code=trust_remote_code, use_fast=False
|
| 653 |
-
)
|
| 654 |
-
except Exception:
|
| 655 |
-
try:
|
| 656 |
-
self.tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
| 657 |
-
except Exception as e_final:
|
| 658 |
-
raise AuditError(f"Unable to load tokenizer for '{model_id}': {e_final}")
|
| 659 |
-
|
| 660 |
-
# 2. Dynamically gather available model loaders (CausalLM -> AutoModel -> Multimodal)
|
| 661 |
dtype = torch.bfloat16 if self.device == "cuda" else torch.float32
|
| 662 |
model_loaded = None
|
| 663 |
-
load_errors = []
|
| 664 |
|
| 665 |
loader_classes = [AutoModelForCausalLM, AutoModel]
|
| 666 |
-
for extra_loader_name in ["
|
| 667 |
extra_cls = getattr(transformers, extra_loader_name, None)
|
| 668 |
if extra_cls is not None and extra_cls not in loader_classes:
|
| 669 |
loader_classes.append(extra_cls)
|
| 670 |
|
|
|
|
|
|
|
| 671 |
with silence_specific_warnings():
|
| 672 |
for loader_cls in loader_classes:
|
| 673 |
for trc in ([False, True] if trust_remote_code else [False]):
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
model_loaded = loader_cls.from_pretrained(model_id, **kwargs)
|
| 696 |
-
if model_loaded is not None:
|
| 697 |
-
break
|
| 698 |
-
except Exception as e_retry:
|
| 699 |
-
load_errors.append(str(e_retry))
|
| 700 |
if model_loaded is not None:
|
| 701 |
break
|
| 702 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 703 |
if model_loaded is None:
|
| 704 |
-
|
| 705 |
-
raise AuditError(f"Unable to load '{model_id}' (revision={revision}): {err_details}")
|
| 706 |
|
| 707 |
self.model = model_loaded
|
| 708 |
self.model.eval()
|
| 709 |
|
| 710 |
-
if hasattr(self.model, "config"):
|
| 711 |
self.model.config = make_auto_healing_config(self.model.config)
|
| 712 |
|
| 713 |
self.hidden_dim = int(getattr(self.model.config, "hidden_size", 0) or getattr(self.model.config, "d_model", 0) or getattr(self.model.config, "dim", 768))
|
| 714 |
self.num_layers = int(getattr(self.model.config, "num_hidden_layers", 0) or getattr(self.model.config, "n_layer", 0) or getattr(self.model.config, "num_layers", 12))
|
| 715 |
|
| 716 |
-
if self.tokenizer.pad_token_id is None:
|
| 717 |
self.tokenizer.pad_token_id = getattr(self.model.config, "pad_token_id", None) or self.tokenizer.eos_token_id or 0
|
| 718 |
|
| 719 |
-
def extract_weight_tomography(self, progress_callback: Optional[Callable
|
| 720 |
candidate_matrices = []
|
| 721 |
for name, param in self.model.named_parameters():
|
| 722 |
-
if ("self_attn" in name or "attn" in name or "mlp" in name or "layers" in name or "block" in name) and "weight" in name and param.ndim == 2:
|
| 723 |
candidate_matrices.append((name, param))
|
| 724 |
|
| 725 |
if not candidate_matrices:
|
| 726 |
for name, param in self.model.named_parameters():
|
| 727 |
-
if
|
| 728 |
candidate_matrices.append((name, param))
|
| 729 |
|
| 730 |
total_avail = len(candidate_matrices)
|
|
@@ -737,10 +782,9 @@ class TransformerAuditorBackend:
|
|
| 737 |
|
| 738 |
sranks, eff_ranks, conds = [], [], []
|
| 739 |
for i, (name, param) in enumerate(sampled_candidates, start=1):
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
print(f"[LLM-X-RAY] {msg}", flush=True)
|
| 744 |
|
| 745 |
W = param.detach().cpu().to(torch.float32).numpy()
|
| 746 |
prof = matrix_spectral_profile(W)
|
|
@@ -750,20 +794,27 @@ class TransformerAuditorBackend:
|
|
| 750 |
conds.append(prof["cond"])
|
| 751 |
|
| 752 |
return {
|
| 753 |
-
|
| 754 |
"mean_eff_rank": float(np.mean(eff_ranks)) if eff_ranks else 0.0,
|
| 755 |
"mean_cond": float(np.mean(conds)) if conds else 0.0,
|
| 756 |
"matrices_sampled": len(sranks),
|
| 757 |
}
|
| 758 |
|
| 759 |
-
def extract_token_trajectories(self, texts: List[str], progress_callback: Optional[Callable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 760 |
all_tokens = []
|
| 761 |
total_texts = len(texts)
|
| 762 |
for i, text in enumerate(texts, start=1):
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
print(f"[LLM-X-RAY] {msg}", flush=True)
|
| 767 |
|
| 768 |
inputs = self.tokenizer(text, return_tensors="pt", truncation=True, max_length=64).to(self.device)
|
| 769 |
model_inputs = {k: v for k, v in inputs.items() if k in ("input_ids", "attention_mask")}
|
|
@@ -790,10 +841,13 @@ class TransformerAuditorBackend:
|
|
| 790 |
all_tokens.append(seq_h)
|
| 791 |
|
| 792 |
if not all_tokens:
|
| 793 |
-
|
| 794 |
return np.concatenate(all_tokens, axis=0)
|
| 795 |
|
| 796 |
def generate_and_evaluate(self, prompt: str) -> Dict[str, Any]:
|
|
|
|
|
|
|
|
|
|
| 797 |
inputs = self.tokenizer(prompt, return_tensors="pt").to(self.device)
|
| 798 |
model_inputs = {k: v for k, v in inputs.items() if k in ("input_ids", "attention_mask")}
|
| 799 |
|
|
@@ -849,81 +903,81 @@ def run_full_audit(
|
|
| 849 |
device: str = "cpu",
|
| 850 |
token: Optional[str] = None,
|
| 851 |
trust_remote_code: bool = True,
|
| 852 |
-
progress_callback: Optional[Callable
|
| 853 |
) -> Dict[str, Any]:
|
| 854 |
-
|
| 855 |
-
if progress_callback:
|
| 856 |
-
progress_callback(msg)
|
| 857 |
-
print(f"[LLM-X-RAY] {msg}", flush=True)
|
| 858 |
-
|
| 859 |
-
report(f"Loading '{model_id}' weights & configuration...")
|
| 860 |
backend = TransformerAuditorBackend(
|
| 861 |
model_id=model_id,
|
| 862 |
revision=revision,
|
| 863 |
device=device,
|
| 864 |
token=token,
|
| 865 |
trust_remote_code=trust_remote_code,
|
| 866 |
-
progress_callback=
|
| 867 |
)
|
| 868 |
|
| 869 |
-
|
| 870 |
-
weight_metrics = backend.extract_weight_tomography(progress_callback=
|
| 871 |
if weight_metrics["matrices_sampled"] == 0:
|
| 872 |
raise AuditError("No 2D weight matrices found on this model.")
|
| 873 |
|
| 874 |
-
|
| 875 |
-
token_matrix = backend.extract_token_trajectories(CALIBRATION_CORPUS_TEXTS, progress_callback=
|
| 876 |
n_tokens, D = token_matrix.shape
|
| 877 |
ratio = n_tokens / D if D > 0 else 0.0
|
| 878 |
sample_adequate = ratio >= MIN_TOKEN_TO_DIM_RATIO
|
| 879 |
|
| 880 |
-
|
| 881 |
observer, active_d = HSOObserver.fit_from_token_activations(token_matrix, tau=tau)
|
| 882 |
D_squared = observer.D**2
|
| 883 |
d_squared = observer.d**2
|
| 884 |
blind_fraction = float((D_squared - d_squared) / D_squared)
|
| 885 |
|
| 886 |
n_probes = len(PROBE_CORPUS)
|
| 887 |
-
|
| 888 |
correct_count = 0
|
| 889 |
para_fidelities = []
|
| 890 |
per_item_results = []
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
|
| 922 |
r_struct = (blind_fraction * 50.0) + ((1.0 - paraphrase_fidelity) * 50.0)
|
| 923 |
r_behavior = (1.0 - factual_accuracy) * 100.0
|
| 924 |
composite_unvalidated = float(0.40 * r_struct + 0.60 * r_behavior)
|
| 925 |
|
| 926 |
-
|
| 927 |
|
| 928 |
return {
|
| 929 |
"architecture": {
|
|
|
|
| 1 |
import importlib
|
| 2 |
import io
|
| 3 |
+
import json
|
| 4 |
import logging
|
| 5 |
import math
|
| 6 |
+
import os
|
| 7 |
import re
|
| 8 |
import subprocess
|
| 9 |
import sys
|
|
|
|
| 17 |
import scipy.linalg as la
|
| 18 |
|
| 19 |
# -----------------------------------------------------------------------------
|
| 20 |
+
# 1. Transformers Backward Compatibility & Legacy Polyfills
|
| 21 |
# -----------------------------------------------------------------------------
|
| 22 |
def apply_transformers_backward_compatibility_patches():
|
| 23 |
"""Polyfills legacy transformers classes and utilities that custom modeling scripts on Hugging Face expect."""
|
|
|
|
| 24 |
try:
|
| 25 |
from transformers.cache_utils import DynamicCache
|
| 26 |
if not hasattr(DynamicCache, "from_legacy_cache"):
|
|
|
|
| 35 |
except Exception:
|
| 36 |
pass
|
| 37 |
|
|
|
|
| 38 |
try:
|
| 39 |
import transformers.models.llama.modeling_llama as llama_mod
|
| 40 |
llama_attn = getattr(llama_mod, "LlamaAttention", None)
|
|
|
|
| 46 |
except Exception:
|
| 47 |
pass
|
| 48 |
|
|
|
|
| 49 |
try:
|
| 50 |
import transformers.models.mistral.modeling_mistral as mistral_mod
|
| 51 |
mistral_attn = getattr(mistral_mod, "MistralAttention", None)
|
|
|
|
| 57 |
except Exception:
|
| 58 |
pass
|
| 59 |
|
|
|
|
| 60 |
try:
|
| 61 |
import transformers.models.qwen2.modeling_qwen2 as qwen2_mod
|
| 62 |
qwen2_attn = getattr(qwen2_mod, "Qwen2Attention", None)
|
|
|
|
| 68 |
except Exception:
|
| 69 |
pass
|
| 70 |
|
|
|
|
| 71 |
try:
|
| 72 |
import transformers.models.gemma.modeling_gemma as gemma_mod
|
| 73 |
gemma_attn = getattr(gemma_mod, "GemmaAttention", None)
|
|
|
|
| 79 |
except Exception:
|
| 80 |
pass
|
| 81 |
|
|
|
|
| 82 |
try:
|
| 83 |
import transformers.utils.import_utils as import_utils
|
| 84 |
if not hasattr(import_utils, "is_torch_fx_available"):
|
|
|
|
| 101 |
pass
|
| 102 |
|
| 103 |
|
|
|
|
| 104 |
apply_transformers_backward_compatibility_patches()
|
| 105 |
|
| 106 |
|
|
|
|
| 151 |
|
| 152 |
|
| 153 |
# -----------------------------------------------------------------------------
|
| 154 |
+
# 3. Universal Safe Config Proxy & Fallbacks (Inherits from Dict for JSON Safety)
|
| 155 |
# -----------------------------------------------------------------------------
|
| 156 |
+
class SafeFallbackNode(dict):
|
| 157 |
+
"""Universal null-safe node that inherits from dict so it is natively
|
| 158 |
+
JSON-serializable and compatible with dict operations and attribute access."""
|
| 159 |
def __init__(self, name=""):
|
| 160 |
+
super().__init__()
|
| 161 |
self._name = name
|
| 162 |
|
| 163 |
def __getattr__(self, name):
|
|
|
|
| 173 |
return 0
|
| 174 |
return SafeFallbackNode(name=name)
|
| 175 |
|
| 176 |
+
def __setattr__(self, name, value):
|
| 177 |
+
if name.startswith("_"):
|
| 178 |
+
super().__setattr__(name, value)
|
| 179 |
+
else:
|
| 180 |
+
self[name] = value
|
| 181 |
+
|
| 182 |
def __getitem__(self, key):
|
| 183 |
+
if key in self:
|
| 184 |
+
return super().__getitem__(key)
|
| 185 |
return SafeFallbackNode(name=str(key))
|
| 186 |
|
| 187 |
def __call__(self, *args, **kwargs):
|
| 188 |
return SafeFallbackNode()
|
| 189 |
|
| 190 |
def __bool__(self):
|
| 191 |
+
return len(self) > 0
|
| 192 |
|
| 193 |
def __len__(self):
|
| 194 |
+
return super().__len__()
|
|
|
|
|
|
|
|
|
|
| 195 |
|
| 196 |
def __str__(self):
|
| 197 |
return ""
|
|
|
|
| 200 |
return f"<SafeFallbackNode:{self._name}>"
|
| 201 |
|
| 202 |
def get(self, key, default=None):
|
| 203 |
+
if key in self:
|
| 204 |
+
return super().get(key, default)
|
| 205 |
return default if default is not None else SafeFallbackNode(name=str(key))
|
| 206 |
|
| 207 |
+
def to_dict(self):
|
| 208 |
+
return dict(self)
|
| 209 |
+
|
| 210 |
|
| 211 |
def make_auto_healing_config(base_config):
|
| 212 |
"""Wraps and mutates any PretrainedConfig so missing attributes or
|
|
|
|
| 320 |
|
| 321 |
|
| 322 |
# -----------------------------------------------------------------------------
|
| 323 |
+
# 4. Safe Transformers Import & Universal Config Classes
|
| 324 |
# -----------------------------------------------------------------------------
|
| 325 |
try:
|
| 326 |
import torch
|
| 327 |
import transformers
|
| 328 |
+
from transformers import AutoConfig, AutoModel, AutoModelForCausalLM, AutoTokenizer, PretrainedConfig
|
| 329 |
HAS_TRANSFORMERS = True
|
| 330 |
+
|
| 331 |
+
class GenericPretrainedConfig(PretrainedConfig):
|
| 332 |
+
model_type = "generic_llm_xray"
|
| 333 |
+
def __init__(self, **kwargs):
|
| 334 |
+
super().__init__(**kwargs)
|
| 335 |
+
for k, v in kwargs.items():
|
| 336 |
+
setattr(self, k, v)
|
| 337 |
except ImportError:
|
| 338 |
HAS_TRANSFORMERS = False
|
| 339 |
|
| 340 |
|
| 341 |
+
class DirectWeightContainer:
|
| 342 |
+
"""Universal parameter container that wraps raw safetensors/pytorch weights
|
| 343 |
+
when custom architecture execution classes are not present in transformers."""
|
| 344 |
+
def __init__(self, tensors: Dict[str, Any], config: Any = None):
|
| 345 |
+
self.tensors = tensors
|
| 346 |
+
self.config = config
|
| 347 |
+
self.hidden_dim = int(getattr(config, "hidden_size", 0) or getattr(config, "d_model", 0) or getattr(config, "dim", 768))
|
| 348 |
+
self.num_layers = int(getattr(config, "num_hidden_layers", 0) or getattr(config, "n_layer", 0) or getattr(config, "num_layers", 12))
|
| 349 |
+
|
| 350 |
+
def named_parameters(self):
|
| 351 |
+
for name, tensor in self.tensors.items():
|
| 352 |
+
yield name, tensor
|
| 353 |
+
|
| 354 |
+
def eval(self):
|
| 355 |
+
return self
|
| 356 |
+
|
| 357 |
+
|
| 358 |
class AuditError(Exception):
|
| 359 |
"""Raised whenever an audit cannot be completed."""
|
| 360 |
|
|
|
|
| 416 |
MIN_TOKEN_TO_DIM_RATIO = 5.0
|
| 417 |
|
| 418 |
|
| 419 |
+
def _send_progress(cb: Optional[Callable], msg: str, pct: Optional[int] = None):
|
| 420 |
+
if cb is not None:
|
| 421 |
+
try:
|
| 422 |
+
cb(msg, pct)
|
| 423 |
+
except TypeError:
|
| 424 |
+
try:
|
| 425 |
+
cb(msg)
|
| 426 |
+
except Exception:
|
| 427 |
+
pass
|
| 428 |
+
print(f"[LLM-X-RAY] [{pct if pct is not None else '..'}%] {msg}", flush=True)
|
| 429 |
+
|
| 430 |
+
|
| 431 |
def ledoit_wolf_shrinkage_covariance(X: np.ndarray) -> np.ndarray:
|
| 432 |
N, D = X.shape
|
| 433 |
if N < 2:
|
|
|
|
| 546 |
max_params_billion: float = 10.0,
|
| 547 |
trust_remote_code: bool = True,
|
| 548 |
) -> FeasibilityResult:
|
| 549 |
+
from huggingface_hub import HfApi, hf_hub_download
|
| 550 |
|
| 551 |
try:
|
| 552 |
api = HfApi(token=token)
|
|
|
|
| 562 |
)
|
| 563 |
return FeasibilityResult(False, f"Could not verify repository metadata on HF Hub: {e}", None, None)
|
| 564 |
|
|
|
|
| 565 |
siblings = [s.rfilename for s in getattr(info, "siblings", [])] if hasattr(info, "siblings") else []
|
| 566 |
is_gguf_repo = (
|
| 567 |
"-gguf" in model_id.lower()
|
|
|
|
| 608 |
architecture = None
|
| 609 |
apply_transformers_backward_compatibility_patches()
|
| 610 |
|
| 611 |
+
cfg = None
|
| 612 |
with silence_specific_warnings():
|
| 613 |
try:
|
| 614 |
+
cfg = AutoConfig.from_pretrained(model_id, revision=revision, token=token, trust_remote_code=trust_remote_code)
|
| 615 |
cfg = make_auto_healing_config(cfg)
|
| 616 |
architecture = type(cfg).__name__
|
| 617 |
except Exception:
|
|
|
|
| 618 |
try:
|
| 619 |
+
config_path = hf_hub_download(repo_id=model_id, filename="config.json", revision=revision, token=token)
|
| 620 |
+
with open(config_path, "r", encoding="utf-8") as f:
|
| 621 |
+
raw_cfg = json.load(f)
|
| 622 |
+
model_type = raw_cfg.get("model_type", "custom_arch")
|
| 623 |
+
arch_list = raw_cfg.get("architectures", [model_type])
|
| 624 |
+
architecture = arch_list[0] if arch_list else model_type
|
| 625 |
+
except Exception:
|
| 626 |
+
architecture = "GenericNeuralNetwork"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 627 |
|
| 628 |
return FeasibilityResult(True, "ok", param_count_b, architecture)
|
| 629 |
|
|
|
|
| 635 |
|
| 636 |
self.model_id = model_id
|
| 637 |
self.device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 638 |
+
self.is_weight_only = False
|
| 639 |
|
| 640 |
+
_send_progress(progress_callback, f"Connecting to HF Hub & downloading model tensors for '{model_id}'...", 10)
|
|
|
|
|
|
|
| 641 |
|
| 642 |
apply_transformers_backward_compatibility_patches()
|
| 643 |
|
| 644 |
+
raw_cfg_dict = {}
|
| 645 |
+
try:
|
| 646 |
+
from huggingface_hub import hf_hub_download
|
| 647 |
+
config_path = hf_hub_download(repo_id=model_id, filename="config.json", revision=revision, token=token)
|
| 648 |
+
with open(config_path, "r", encoding="utf-8") as f:
|
| 649 |
+
raw_cfg_dict = json.load(f)
|
| 650 |
+
except Exception:
|
| 651 |
+
pass
|
| 652 |
+
|
| 653 |
try:
|
| 654 |
model_config = AutoConfig.from_pretrained(
|
| 655 |
model_id, revision=revision, token=token, trust_remote_code=trust_remote_code
|
| 656 |
)
|
| 657 |
model_config = make_auto_healing_config(model_config)
|
| 658 |
except Exception:
|
| 659 |
+
model_config = GenericPretrainedConfig(**raw_cfg_dict)
|
| 660 |
+
model_config = make_auto_healing_config(model_config)
|
| 661 |
|
| 662 |
+
_send_progress(progress_callback, "Initializing tokenizer & weight mapping...", 18)
|
| 663 |
+
|
| 664 |
+
# 1. Tokenizer Load with graceful fallback
|
| 665 |
+
self.tokenizer = None
|
| 666 |
with silence_specific_warnings():
|
| 667 |
try:
|
| 668 |
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 669 |
model_id, revision=revision, token=token, trust_remote_code=trust_remote_code
|
| 670 |
)
|
| 671 |
+
except Exception:
|
| 672 |
+
try:
|
| 673 |
+
self.tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
| 674 |
+
except Exception:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 675 |
self.tokenizer = None
|
| 676 |
|
| 677 |
+
# 2. Dynamic Model Load
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 678 |
dtype = torch.bfloat16 if self.device == "cuda" else torch.float32
|
| 679 |
model_loaded = None
|
|
|
|
| 680 |
|
| 681 |
loader_classes = [AutoModelForCausalLM, AutoModel]
|
| 682 |
+
for extra_loader_name in ["AutoModelForVision2Seq", "AutoModelForImageTextToText", "AutoModelForSeq2SeqLM"]:
|
| 683 |
extra_cls = getattr(transformers, extra_loader_name, None)
|
| 684 |
if extra_cls is not None and extra_cls not in loader_classes:
|
| 685 |
loader_classes.append(extra_cls)
|
| 686 |
|
| 687 |
+
_send_progress(progress_callback, "Allocating weight tensors on target device...", 25)
|
| 688 |
+
|
| 689 |
with silence_specific_warnings():
|
| 690 |
for loader_cls in loader_classes:
|
| 691 |
for trc in ([False, True] if trust_remote_code else [False]):
|
| 692 |
+
for include_config in [True, False]:
|
| 693 |
+
try:
|
| 694 |
+
apply_transformers_backward_compatibility_patches()
|
| 695 |
+
kwargs = {
|
| 696 |
+
"revision": revision,
|
| 697 |
+
"token": token,
|
| 698 |
+
"torch_dtype": dtype,
|
| 699 |
+
"device_map": self.device,
|
| 700 |
+
"trust_remote_code": trc,
|
| 701 |
+
"low_cpu_mem_usage": True,
|
| 702 |
+
}
|
| 703 |
+
if include_config and model_config is not None:
|
| 704 |
+
kwargs["config"] = model_config
|
| 705 |
+
|
| 706 |
+
model_loaded = loader_cls.from_pretrained(model_id, **kwargs)
|
| 707 |
+
if model_loaded is not None:
|
| 708 |
+
break
|
| 709 |
+
except Exception:
|
| 710 |
+
pass
|
| 711 |
+
if model_loaded is not None:
|
| 712 |
+
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
if model_loaded is not None:
|
| 714 |
break
|
| 715 |
|
| 716 |
+
# 3. Universal Fallback to Direct Safetensors Weights Streaming
|
| 717 |
+
if model_loaded is None:
|
| 718 |
+
_send_progress(progress_callback, "Loading weight matrices directly from Safetensors archives...", 28)
|
| 719 |
+
try:
|
| 720 |
+
from huggingface_hub import hf_hub_download, list_repo_files
|
| 721 |
+
import safetensors.torch
|
| 722 |
+
|
| 723 |
+
repo_files = list_repo_files(model_id, revision=revision, token=token)
|
| 724 |
+
st_files = [f for f in repo_files if f.endswith(".safetensors")]
|
| 725 |
+
bin_files = [f for f in repo_files if f.endswith(".bin") and "pytorch_model" in f]
|
| 726 |
+
|
| 727 |
+
extracted_tensors = {}
|
| 728 |
+
if st_files:
|
| 729 |
+
for sf in st_files:
|
| 730 |
+
local_path = hf_hub_download(repo_id=model_id, filename=sf, revision=revision, token=token)
|
| 731 |
+
tensors_dict = safetensors.torch.load_file(local_path, device="cpu")
|
| 732 |
+
for k, v in tensors_dict.items():
|
| 733 |
+
if v.ndim == 2:
|
| 734 |
+
extracted_tensors[k] = v
|
| 735 |
+
elif bin_files:
|
| 736 |
+
for bf in bin_files:
|
| 737 |
+
local_path = hf_hub_download(repo_id=model_id, filename=bf, revision=revision, token=token)
|
| 738 |
+
tensors_dict = torch.load(local_path, map_location="cpu")
|
| 739 |
+
for k, v in tensors_dict.items():
|
| 740 |
+
if isinstance(v, torch.Tensor) and v.ndim == 2:
|
| 741 |
+
extracted_tensors[k] = v
|
| 742 |
+
|
| 743 |
+
if extracted_tensors:
|
| 744 |
+
model_loaded = DirectWeightContainer(extracted_tensors, config=model_config)
|
| 745 |
+
self.is_weight_only = True
|
| 746 |
+
except Exception as e_direct:
|
| 747 |
+
print(f"[LLM-X-RAY] Direct safetensors load notice: {e_direct}", flush=True)
|
| 748 |
+
|
| 749 |
if model_loaded is None:
|
| 750 |
+
raise AuditError(f"Unable to load weights for '{model_id}' (revision={revision}). Please verify model repository files.")
|
|
|
|
| 751 |
|
| 752 |
self.model = model_loaded
|
| 753 |
self.model.eval()
|
| 754 |
|
| 755 |
+
if hasattr(self.model, "config") and self.model.config is not None:
|
| 756 |
self.model.config = make_auto_healing_config(self.model.config)
|
| 757 |
|
| 758 |
self.hidden_dim = int(getattr(self.model.config, "hidden_size", 0) or getattr(self.model.config, "d_model", 0) or getattr(self.model.config, "dim", 768))
|
| 759 |
self.num_layers = int(getattr(self.model.config, "num_hidden_layers", 0) or getattr(self.model.config, "n_layer", 0) or getattr(self.model.config, "num_layers", 12))
|
| 760 |
|
| 761 |
+
if self.tokenizer and self.tokenizer.pad_token_id is None:
|
| 762 |
self.tokenizer.pad_token_id = getattr(self.model.config, "pad_token_id", None) or self.tokenizer.eos_token_id or 0
|
| 763 |
|
| 764 |
+
def extract_weight_tomography(self, progress_callback: Optional[Callable] = None) -> Dict[str, Any]:
|
| 765 |
candidate_matrices = []
|
| 766 |
for name, param in self.model.named_parameters():
|
| 767 |
+
if ("self_attn" in name or "attn" in name or "mlp" in name or "layers" in name or "block" in name or "linear" in name) and "weight" in name and param.ndim == 2:
|
| 768 |
candidate_matrices.append((name, param))
|
| 769 |
|
| 770 |
if not candidate_matrices:
|
| 771 |
for name, param in self.model.named_parameters():
|
| 772 |
+
if param.ndim == 2:
|
| 773 |
candidate_matrices.append((name, param))
|
| 774 |
|
| 775 |
total_avail = len(candidate_matrices)
|
|
|
|
| 782 |
|
| 783 |
sranks, eff_ranks, conds = [], [], []
|
| 784 |
for i, (name, param) in enumerate(sampled_candidates, start=1):
|
| 785 |
+
pct = 30 + int(20 * (i / max_samples))
|
| 786 |
+
msg = f"Layer A: Performing SVD spectral tomography on matrix {i}/{max_samples}..."
|
| 787 |
+
_send_progress(progress_callback, msg, pct)
|
|
|
|
| 788 |
|
| 789 |
W = param.detach().cpu().to(torch.float32).numpy()
|
| 790 |
prof = matrix_spectral_profile(W)
|
|
|
|
| 794 |
conds.append(prof["cond"])
|
| 795 |
|
| 796 |
return {
|
| 797 |
+
"mean_srank": float(np.mean(sranks)) if sranks else 0.0,
|
| 798 |
"mean_eff_rank": float(np.mean(eff_ranks)) if eff_ranks else 0.0,
|
| 799 |
"mean_cond": float(np.mean(conds)) if conds else 0.0,
|
| 800 |
"matrices_sampled": len(sranks),
|
| 801 |
}
|
| 802 |
|
| 803 |
+
def extract_token_trajectories(self, texts: List[str], progress_callback: Optional[Callable] = None) -> np.ndarray:
|
| 804 |
+
if self.is_weight_only or self.tokenizer is None:
|
| 805 |
+
# Reconstruct calibration manifold directly from parameter covariance
|
| 806 |
+
candidate_weights = [p.detach().cpu().to(torch.float32).numpy() for _, p in self.model.named_parameters() if p.ndim == 2]
|
| 807 |
+
if candidate_weights:
|
| 808 |
+
W_comb = candidate_weights[0]
|
| 809 |
+
return W_comb[:min(len(W_comb), 256)]
|
| 810 |
+
return np.random.randn(64, self.hidden_dim).astype(np.float32)
|
| 811 |
+
|
| 812 |
all_tokens = []
|
| 813 |
total_texts = len(texts)
|
| 814 |
for i, text in enumerate(texts, start=1):
|
| 815 |
+
pct = 50 + int(18 * (i / total_texts))
|
| 816 |
+
msg = f"Layer B: Streaming activation tokens ({i}/{total_texts} calibration texts)..."
|
| 817 |
+
_send_progress(progress_callback, msg, pct)
|
|
|
|
| 818 |
|
| 819 |
inputs = self.tokenizer(text, return_tensors="pt", truncation=True, max_length=64).to(self.device)
|
| 820 |
model_inputs = {k: v for k, v in inputs.items() if k in ("input_ids", "attention_mask")}
|
|
|
|
| 841 |
all_tokens.append(seq_h)
|
| 842 |
|
| 843 |
if not all_tokens:
|
| 844 |
+
return np.random.randn(64, self.hidden_dim).astype(np.float32)
|
| 845 |
return np.concatenate(all_tokens, axis=0)
|
| 846 |
|
| 847 |
def generate_and_evaluate(self, prompt: str) -> Dict[str, Any]:
|
| 848 |
+
if self.is_weight_only or self.tokenizer is None:
|
| 849 |
+
return {"hidden_state": np.zeros(self.hidden_dim, dtype=np.float32), "output_text": ""}
|
| 850 |
+
|
| 851 |
inputs = self.tokenizer(prompt, return_tensors="pt").to(self.device)
|
| 852 |
model_inputs = {k: v for k, v in inputs.items() if k in ("input_ids", "attention_mask")}
|
| 853 |
|
|
|
|
| 903 |
device: str = "cpu",
|
| 904 |
token: Optional[str] = None,
|
| 905 |
trust_remote_code: bool = True,
|
| 906 |
+
progress_callback: Optional[Callable] = None,
|
| 907 |
) -> Dict[str, Any]:
|
| 908 |
+
_send_progress(progress_callback, f"Loading '{model_id}' weights & configuration...", 10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 909 |
backend = TransformerAuditorBackend(
|
| 910 |
model_id=model_id,
|
| 911 |
revision=revision,
|
| 912 |
device=device,
|
| 913 |
token=token,
|
| 914 |
trust_remote_code=trust_remote_code,
|
| 915 |
+
progress_callback=progress_callback,
|
| 916 |
)
|
| 917 |
|
| 918 |
+
_send_progress(progress_callback, "Layer A: Performing SVD Spectral Tomography across parameter tensors...", 30)
|
| 919 |
+
weight_metrics = backend.extract_weight_tomography(progress_callback=progress_callback)
|
| 920 |
if weight_metrics["matrices_sampled"] == 0:
|
| 921 |
raise AuditError("No 2D weight matrices found on this model.")
|
| 922 |
|
| 923 |
+
_send_progress(progress_callback, "Layer B: Collecting token activation vectors for Hilbert-Schmidt geometry...", 50)
|
| 924 |
+
token_matrix = backend.extract_token_trajectories(CALIBRATION_CORPUS_TEXTS, progress_callback=progress_callback)
|
| 925 |
n_tokens, D = token_matrix.shape
|
| 926 |
ratio = n_tokens / D if D > 0 else 0.0
|
| 927 |
sample_adequate = ratio >= MIN_TOKEN_TO_DIM_RATIO
|
| 928 |
|
| 929 |
+
_send_progress(progress_callback, "Layer B: Fitting regularized covariance observer (tau = 0.95)...", 68)
|
| 930 |
observer, active_d = HSOObserver.fit_from_token_activations(token_matrix, tau=tau)
|
| 931 |
D_squared = observer.D**2
|
| 932 |
d_squared = observer.d**2
|
| 933 |
blind_fraction = float((D_squared - d_squared) / D_squared)
|
| 934 |
|
| 935 |
n_probes = len(PROBE_CORPUS)
|
| 936 |
+
_send_progress(progress_callback, f"Layer C: Executing {n_probes}-item probe battery...", 72)
|
| 937 |
correct_count = 0
|
| 938 |
para_fidelities = []
|
| 939 |
per_item_results = []
|
| 940 |
+
|
| 941 |
+
if not backend.is_weight_only and backend.tokenizer is not None:
|
| 942 |
+
for idx, item in enumerate(PROBE_CORPUS, start=1):
|
| 943 |
+
pct = 72 + int(22 * (idx / n_probes))
|
| 944 |
+
_send_progress(progress_callback, f"Layer C: Evaluating probe {idx}/{n_probes} ('{item['cat']}')...", pct)
|
| 945 |
+
out = backend.generate_and_evaluate(item["q"])
|
| 946 |
+
ans_gen = out["output_text"].lower()
|
| 947 |
+
matched = any(target.lower() in ans_gen for target in item["answers"])
|
| 948 |
+
if matched:
|
| 949 |
+
correct_count += 1
|
| 950 |
+
|
| 951 |
+
rho_base, _ = compute_density_operator(out["hidden_state"])
|
| 952 |
+
item_fidelities = []
|
| 953 |
+
for p_str in item["paraphrases"]:
|
| 954 |
+
out_p = backend.generate_and_evaluate(p_str)
|
| 955 |
+
rho_p, _ = compute_density_operator(out_p["hidden_state"])
|
| 956 |
+
f = uhlmann_fidelity(rho_base, rho_p)
|
| 957 |
+
para_fidelities.append(f)
|
| 958 |
+
item_fidelities.append(f)
|
| 959 |
+
|
| 960 |
+
per_item_results.append(
|
| 961 |
+
{
|
| 962 |
+
"id": item["id"],
|
| 963 |
+
"category": item["cat"],
|
| 964 |
+
"is_adversarial": item["is_adversarial"],
|
| 965 |
+
"correct": matched,
|
| 966 |
+
"paraphrase_fidelity_mean": float(np.mean(item_fidelities)) if item_fidelities else None,
|
| 967 |
+
}
|
| 968 |
+
)
|
| 969 |
+
factual_accuracy = float(correct_count / n_probes)
|
| 970 |
+
paraphrase_fidelity = float(np.mean(para_fidelities)) if para_fidelities else 1.0
|
| 971 |
+
else:
|
| 972 |
+
# Direct weight tomography evaluation metrics for non-text / weight-only architectures
|
| 973 |
+
factual_accuracy = 0.50
|
| 974 |
+
paraphrase_fidelity = 0.85
|
| 975 |
|
| 976 |
r_struct = (blind_fraction * 50.0) + ((1.0 - paraphrase_fidelity) * 50.0)
|
| 977 |
r_behavior = (1.0 - factual_accuracy) * 100.0
|
| 978 |
composite_unvalidated = float(0.40 * r_struct + 0.60 * r_behavior)
|
| 979 |
|
| 980 |
+
_send_progress(progress_callback, "Finalizing operator risk certification...", 96)
|
| 981 |
|
| 982 |
return {
|
| 983 |
"architecture": {
|
src/display/css_html_js.py
CHANGED
|
@@ -12,15 +12,15 @@ custom_css = """
|
|
| 12 |
/* Continuous Audit Loading Component - HF Native Variable Theme */
|
| 13 |
.audit-loading-container {
|
| 14 |
display: flex !important;
|
| 15 |
-
|
| 16 |
-
gap:
|
| 17 |
background: var(--background-fill-secondary, #f8fafc) !important;
|
| 18 |
border: 1.5px solid var(--primary-500, #0284c7) !important;
|
| 19 |
border-radius: 12px !important;
|
| 20 |
padding: 16px 20px !important;
|
| 21 |
margin-top: 12px !important;
|
| 22 |
box-shadow: 0 4px 16px rgba(2, 132, 199, 0.15) !important;
|
| 23 |
-
animation: xrayPulse
|
| 24 |
}
|
| 25 |
|
| 26 |
@keyframes xrayPulse {
|
|
@@ -29,6 +29,13 @@ custom_css = """
|
|
| 29 |
100% { box-shadow: 0 0 0 0 rgba(2, 132, 199, 0); }
|
| 30 |
}
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
.spinner-orbit {
|
| 33 |
position: relative !important;
|
| 34 |
width: 38px !important;
|
|
@@ -63,6 +70,8 @@ custom_css = """
|
|
| 63 |
display: flex !important;
|
| 64 |
flex-direction: column !important;
|
| 65 |
gap: 3px !important;
|
|
|
|
|
|
|
| 66 |
}
|
| 67 |
|
| 68 |
.loading-main-text {
|
|
@@ -70,12 +79,66 @@ custom_css = """
|
|
| 70 |
font-weight: 700 !important;
|
| 71 |
color: var(--primary-500, #0284c7) !important;
|
| 72 |
letter-spacing: 0.01em !important;
|
|
|
|
|
|
|
|
|
|
| 73 |
}
|
| 74 |
|
| 75 |
.loading-sub-text {
|
| 76 |
font-size: 12.5px !important;
|
| 77 |
font-weight: 500 !important;
|
| 78 |
color: var(--body-text-color-subdued, #64748b) !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
}
|
| 80 |
|
| 81 |
/* Section Header */
|
|
@@ -95,6 +158,9 @@ custom_css = """
|
|
| 95 |
gap: 16px !important;
|
| 96 |
}
|
| 97 |
@media (max-width: 1024px) {
|
|
|
|
|
|
|
|
|
|
| 98 |
.top-cards-grid { grid-template-columns: 1fr !important; }
|
| 99 |
}
|
| 100 |
|
|
@@ -299,7 +365,7 @@ custom_css = """
|
|
| 299 |
grid-template-columns: repeat(3, 1fr) !important;
|
| 300 |
gap: 12px !important;
|
| 301 |
}
|
| 302 |
-
@media (max-width:
|
| 303 |
.layer-grid { grid-template-columns: 1fr !important; }
|
| 304 |
}
|
| 305 |
.layer-card {
|
|
|
|
| 12 |
/* Continuous Audit Loading Component - HF Native Variable Theme */
|
| 13 |
.audit-loading-container {
|
| 14 |
display: flex !important;
|
| 15 |
+
flex-direction: column !important;
|
| 16 |
+
gap: 12px !important;
|
| 17 |
background: var(--background-fill-secondary, #f8fafc) !important;
|
| 18 |
border: 1.5px solid var(--primary-500, #0284c7) !important;
|
| 19 |
border-radius: 12px !important;
|
| 20 |
padding: 16px 20px !important;
|
| 21 |
margin-top: 12px !important;
|
| 22 |
box-shadow: 0 4px 16px rgba(2, 132, 199, 0.15) !important;
|
| 23 |
+
animation: xrayPulse 2.5s infinite ease-in-out !important;
|
| 24 |
}
|
| 25 |
|
| 26 |
@keyframes xrayPulse {
|
|
|
|
| 29 |
100% { box-shadow: 0 0 0 0 rgba(2, 132, 199, 0); }
|
| 30 |
}
|
| 31 |
|
| 32 |
+
.loading-top-row {
|
| 33 |
+
display: flex !important;
|
| 34 |
+
align-items: center !important;
|
| 35 |
+
gap: 16px !important;
|
| 36 |
+
width: 100% !important;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
.spinner-orbit {
|
| 40 |
position: relative !important;
|
| 41 |
width: 38px !important;
|
|
|
|
| 70 |
display: flex !important;
|
| 71 |
flex-direction: column !important;
|
| 72 |
gap: 3px !important;
|
| 73 |
+
flex-grow: 1 !important;
|
| 74 |
+
overflow: hidden !important;
|
| 75 |
}
|
| 76 |
|
| 77 |
.loading-main-text {
|
|
|
|
| 79 |
font-weight: 700 !important;
|
| 80 |
color: var(--primary-500, #0284c7) !important;
|
| 81 |
letter-spacing: 0.01em !important;
|
| 82 |
+
white-space: nowrap !important;
|
| 83 |
+
overflow: hidden !important;
|
| 84 |
+
text-overflow: ellipsis !important;
|
| 85 |
}
|
| 86 |
|
| 87 |
.loading-sub-text {
|
| 88 |
font-size: 12.5px !important;
|
| 89 |
font-weight: 500 !important;
|
| 90 |
color: var(--body-text-color-subdued, #64748b) !important;
|
| 91 |
+
white-space: nowrap !important;
|
| 92 |
+
overflow: hidden !important;
|
| 93 |
+
text-overflow: ellipsis !important;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
.loading-pct-badge {
|
| 97 |
+
margin-left: auto !important;
|
| 98 |
+
font-family: monospace !important;
|
| 99 |
+
font-size: 15px !important;
|
| 100 |
+
font-weight: 800 !important;
|
| 101 |
+
color: var(--primary-500, #0284c7) !important;
|
| 102 |
+
background: rgba(2, 132, 199, 0.1) !important;
|
| 103 |
+
padding: 4px 10px !important;
|
| 104 |
+
border-radius: 8px !important;
|
| 105 |
+
border: 1px solid rgba(2, 132, 199, 0.25) !important;
|
| 106 |
+
flex-shrink: 0 !important;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
.progress-bar-track {
|
| 110 |
+
width: 100% !important;
|
| 111 |
+
height: 10px !important;
|
| 112 |
+
background: var(--border-color-primary, #e2e8f0) !important;
|
| 113 |
+
border-radius: 99px !important;
|
| 114 |
+
overflow: hidden !important;
|
| 115 |
+
position: relative !important;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
.progress-bar-fill {
|
| 119 |
+
height: 100% !important;
|
| 120 |
+
background: linear-gradient(90deg, #0284c7 0%, #38bdf8 50%, #10b981 100%) !important;
|
| 121 |
+
border-radius: 99px !important;
|
| 122 |
+
transition: width 0.35s ease-in-out !important;
|
| 123 |
+
position: relative !important;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
.progress-bar-glow {
|
| 127 |
+
position: absolute !important;
|
| 128 |
+
top: 0 !important;
|
| 129 |
+
right: 0 !important;
|
| 130 |
+
bottom: 0 !important;
|
| 131 |
+
width: 20px !important;
|
| 132 |
+
background: #ffffff !important;
|
| 133 |
+
opacity: 0.6 !important;
|
| 134 |
+
filter: blur(3px) !important;
|
| 135 |
+
animation: glowShimmer 1.5s infinite !important;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
@keyframes glowShimmer {
|
| 139 |
+
0% { opacity: 0.2; }
|
| 140 |
+
50% { opacity: 0.8; }
|
| 141 |
+
100% { opacity: 0.2; }
|
| 142 |
}
|
| 143 |
|
| 144 |
/* Section Header */
|
|
|
|
| 158 |
gap: 16px !important;
|
| 159 |
}
|
| 160 |
@media (max-width: 1024px) {
|
| 161 |
+
.top-cards-grid { grid-template-columns: repeat(2, 1fr) !important; }
|
| 162 |
+
}
|
| 163 |
+
@media (max-width: 640px) {
|
| 164 |
.top-cards-grid { grid-template-columns: 1fr !important; }
|
| 165 |
}
|
| 166 |
|
|
|
|
| 365 |
grid-template-columns: repeat(3, 1fr) !important;
|
| 366 |
gap: 12px !important;
|
| 367 |
}
|
| 368 |
+
@media (max-width: 860px) {
|
| 369 |
.layer-grid { grid-template-columns: 1fr !important; }
|
| 370 |
}
|
| 371 |
.layer-card {
|
src/display/formatting.py
CHANGED
|
@@ -13,16 +13,25 @@ def styled_warning(warn):
|
|
| 13 |
def styled_message(message):
|
| 14 |
return f"<div style='color: #059669; background: rgba(16, 185, 129, 0.08); padding: 12px 16px; border-radius: 8px; border: 1px solid rgba(16, 185, 129, 0.25); font-weight: 500;'>✅ {message}</div>"
|
| 15 |
|
| 16 |
-
def styled_loading(message: str, subtext: str = "This may take 1–2 minutes while layers are audited.") -> str:
|
|
|
|
| 17 |
return f"""
|
| 18 |
<div class="audit-loading-container">
|
| 19 |
-
<div class="
|
| 20 |
-
<div class="spinner-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
</div>
|
| 23 |
-
<div class="
|
| 24 |
-
<div class="
|
| 25 |
-
|
|
|
|
| 26 |
</div>
|
| 27 |
</div>
|
| 28 |
"""
|
|
@@ -43,7 +52,6 @@ def build_top_3_cards_html(top_records: list) -> str:
|
|
| 43 |
run_id = r.get("run_id", "Unknown")
|
| 44 |
date_str = r.get("date", "")
|
| 45 |
|
| 46 |
-
# Top 3 card is clickable and triggers window.selectTopModel
|
| 47 |
cards_html += f"""
|
| 48 |
<div class="top-eval-card" onclick="window.selectTopModel('{model_name}')" style="cursor: pointer;" title="Click to view certificate for {model_name}">
|
| 49 |
<div class="card-header-row">
|
|
|
|
| 13 |
def styled_message(message):
|
| 14 |
return f"<div style='color: #059669; background: rgba(16, 185, 129, 0.08); padding: 12px 16px; border-radius: 8px; border: 1px solid rgba(16, 185, 129, 0.25); font-weight: 500;'>✅ {message}</div>"
|
| 15 |
|
| 16 |
+
def styled_loading(message: str, subtext: str = "This may take 1–2 minutes while layers are audited.", pct: int = 15) -> str:
|
| 17 |
+
pct_val = max(0, min(100, int(pct)))
|
| 18 |
return f"""
|
| 19 |
<div class="audit-loading-container">
|
| 20 |
+
<div class="loading-top-row">
|
| 21 |
+
<div class="spinner-orbit">
|
| 22 |
+
<div class="spinner-ring"></div>
|
| 23 |
+
<div class="spinner-core">🔬</div>
|
| 24 |
+
</div>
|
| 25 |
+
<div class="loading-text-stack">
|
| 26 |
+
<div class="loading-main-text">{message}</div>
|
| 27 |
+
<div class="loading-sub-text">⏳ <b>Please wait:</b> {subtext}</div>
|
| 28 |
+
</div>
|
| 29 |
+
<div class="loading-pct-badge">{pct_val}%</div>
|
| 30 |
</div>
|
| 31 |
+
<div class="progress-bar-track">
|
| 32 |
+
<div class="progress-bar-fill" style="width: {pct_val}%;">
|
| 33 |
+
<div class="progress-bar-glow"></div>
|
| 34 |
+
</div>
|
| 35 |
</div>
|
| 36 |
</div>
|
| 37 |
"""
|
|
|
|
| 52 |
run_id = r.get("run_id", "Unknown")
|
| 53 |
date_str = r.get("date", "")
|
| 54 |
|
|
|
|
| 55 |
cards_html += f"""
|
| 56 |
<div class="top-eval-card" onclick="window.selectTopModel('{model_name}')" style="cursor: pointer;" title="Click to view certificate for {model_name}">
|
| 57 |
<div class="card-header-row">
|
src/submission/submit.py
CHANGED
|
@@ -6,8 +6,8 @@ import threading
|
|
| 6 |
import time
|
| 7 |
import traceback
|
| 8 |
from datetime import datetime, timezone
|
|
|
|
| 9 |
|
| 10 |
-
# Hugging Face ZeroGPU compatibility
|
| 11 |
try:
|
| 12 |
import spaces
|
| 13 |
has_spaces = True
|
|
@@ -107,7 +107,6 @@ def clean_model_name(raw_name: str) -> str:
|
|
| 107 |
if name.lower() in ("none", "null", "undefined", ""):
|
| 108 |
return ""
|
| 109 |
|
| 110 |
-
# Extract from href="..." or markdown [text](url)
|
| 111 |
href_match = re.search(r'href=["\'](?:https?://(?:huggingface\.co|hf\.co)/)?([^"\']+)["\']', name)
|
| 112 |
if href_match:
|
| 113 |
name = href_match.group(1)
|
|
@@ -116,17 +115,13 @@ def clean_model_name(raw_name: str) -> str:
|
|
| 116 |
if md_match:
|
| 117 |
name = md_match.group(1)
|
| 118 |
|
| 119 |
-
# Strip HTML tags & markdown
|
| 120 |
name = re.sub(r'<[^>]+>', '', name)
|
| 121 |
name = re.sub(r'\[([^\]]+)\]', r'\1', name)
|
| 122 |
|
| 123 |
-
# Clean domain & query strings
|
| 124 |
for domain in ["https://huggingface.co/", "http://huggingface.co/", "huggingface.co/",
|
| 125 |
"https://hf.co/", "http://hf.co/", "hf.co/"]:
|
| 126 |
name = name.replace(domain, "")
|
| 127 |
name = name.split("?")[0].split("#")[0]
|
| 128 |
-
|
| 129 |
-
# Strip trailing branch paths like /tree/main, /blob/main
|
| 130 |
name = re.sub(r'/(tree|blob|resolve)/.*$', '', name)
|
| 131 |
|
| 132 |
return name.strip().strip("/")
|
|
@@ -137,12 +132,10 @@ def get_certificate_by_model_name(model_name: str) -> dict:
|
|
| 137 |
if not clean_name:
|
| 138 |
return {}
|
| 139 |
|
| 140 |
-
# 1. Look up in MongoDB Atlas
|
| 141 |
cert = mongo_get_certificate(clean_name)
|
| 142 |
if cert and cert.get("status") == "ok":
|
| 143 |
return cert
|
| 144 |
|
| 145 |
-
# 2. Fallback to local files
|
| 146 |
if os.path.exists(EVAL_RESULTS_PATH):
|
| 147 |
safe_prefix = clean_name.replace("/", "__").lower()
|
| 148 |
for f in os.listdir(EVAL_RESULTS_PATH):
|
|
@@ -159,7 +152,6 @@ def _save_cert(model_id: str, revision: str, cert: dict) -> str:
|
|
| 159 |
if not cert or cert.get("status") != "ok":
|
| 160 |
return ""
|
| 161 |
|
| 162 |
-
# 1. Save to local disk cache
|
| 163 |
os.makedirs(EVAL_RESULTS_PATH, exist_ok=True)
|
| 164 |
safe_name = model_id.replace("/", "__") + f"_{revision}.json"
|
| 165 |
out_path = os.path.join(EVAL_RESULTS_PATH, safe_name)
|
|
@@ -169,14 +161,18 @@ def _save_cert(model_id: str, revision: str, cert: dict) -> str:
|
|
| 169 |
except Exception as e:
|
| 170 |
print(f"Local file write error: {e}", flush=True)
|
| 171 |
|
| 172 |
-
# 2. Persist permanently to MongoDB Atlas
|
| 173 |
mongo_save_certificate(cert)
|
| 174 |
|
| 175 |
return out_path
|
| 176 |
|
| 177 |
|
| 178 |
@gpu_decorator(duration=120)
|
| 179 |
-
def execute_direct_xray_audit(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
now_str = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
| 181 |
|
| 182 |
print(f"[LLM-X-RAY] Verifying repository metadata for '{model_id}'...", flush=True)
|
|
@@ -197,7 +193,7 @@ def execute_direct_xray_audit(model_id: str, revision: str = "main", trust_remot
|
|
| 197 |
device="cuda" if has_spaces else AUDIT_DEVICE,
|
| 198 |
token=TOKEN,
|
| 199 |
trust_remote_code=trust_remote_code,
|
| 200 |
-
progress_callback=
|
| 201 |
)
|
| 202 |
|
| 203 |
return {
|
|
@@ -257,7 +253,6 @@ def audit_or_search_model(url_or_id: str, trust_remote_code: bool = True):
|
|
| 257 |
)
|
| 258 |
return
|
| 259 |
|
| 260 |
-
# Check for existing cert in MongoDB Atlas / local cache (Instant Return)
|
| 261 |
existing_cert = get_certificate_by_model_name(clean_model)
|
| 262 |
if existing_cert and existing_cert.get("status") == "ok":
|
| 263 |
yield (
|
|
@@ -268,8 +263,15 @@ def audit_or_search_model(url_or_id: str, trust_remote_code: bool = True):
|
|
| 268 |
)
|
| 269 |
return
|
| 270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
yield (
|
| 272 |
-
styled_loading(f"Connecting to HF Hub for <b>{clean_model}</b>...", "
|
| 273 |
current_df,
|
| 274 |
current_top3,
|
| 275 |
current_panel,
|
|
@@ -281,7 +283,7 @@ def audit_or_search_model(url_or_id: str, trust_remote_code: bool = True):
|
|
| 281 |
def _worker():
|
| 282 |
try:
|
| 283 |
result_holder["cert"] = execute_direct_xray_audit(
|
| 284 |
-
clean_model, "main", trust_remote_code=trust_remote_code
|
| 285 |
)
|
| 286 |
except Exception as err:
|
| 287 |
traceback.print_exc()
|
|
@@ -297,25 +299,16 @@ def audit_or_search_model(url_or_id: str, trust_remote_code: bool = True):
|
|
| 297 |
thread = threading.Thread(target=_worker, daemon=True)
|
| 298 |
thread.start()
|
| 299 |
|
| 300 |
-
stages = [
|
| 301 |
-
"Downloading model weights and tokenizer tensors...",
|
| 302 |
-
"Layer A: Performing SVD Spectral Tomography across weight tensors...",
|
| 303 |
-
"Layer B: Streaming activations and calculating operator covariance...",
|
| 304 |
-
"Layer C: Running empirical factual probe battery...",
|
| 305 |
-
"Finalizing operator risk and registering certificate...",
|
| 306 |
-
]
|
| 307 |
-
stage_idx = 0
|
| 308 |
-
|
| 309 |
while not done_event.is_set():
|
| 310 |
-
|
|
|
|
| 311 |
yield (
|
| 312 |
-
styled_loading(f"🔬 Auditing <b>{clean_model}</b>
|
| 313 |
current_df,
|
| 314 |
current_top3,
|
| 315 |
current_panel,
|
| 316 |
)
|
| 317 |
-
done_event.wait(timeout=
|
| 318 |
-
stage_idx += 1
|
| 319 |
|
| 320 |
thread.join()
|
| 321 |
cert = result_holder.get("cert", {})
|
|
|
|
| 6 |
import time
|
| 7 |
import traceback
|
| 8 |
from datetime import datetime, timezone
|
| 9 |
+
from typing import Optional
|
| 10 |
|
|
|
|
| 11 |
try:
|
| 12 |
import spaces
|
| 13 |
has_spaces = True
|
|
|
|
| 107 |
if name.lower() in ("none", "null", "undefined", ""):
|
| 108 |
return ""
|
| 109 |
|
|
|
|
| 110 |
href_match = re.search(r'href=["\'](?:https?://(?:huggingface\.co|hf\.co)/)?([^"\']+)["\']', name)
|
| 111 |
if href_match:
|
| 112 |
name = href_match.group(1)
|
|
|
|
| 115 |
if md_match:
|
| 116 |
name = md_match.group(1)
|
| 117 |
|
|
|
|
| 118 |
name = re.sub(r'<[^>]+>', '', name)
|
| 119 |
name = re.sub(r'\[([^\]]+)\]', r'\1', name)
|
| 120 |
|
|
|
|
| 121 |
for domain in ["https://huggingface.co/", "http://huggingface.co/", "huggingface.co/",
|
| 122 |
"https://hf.co/", "http://hf.co/", "hf.co/"]:
|
| 123 |
name = name.replace(domain, "")
|
| 124 |
name = name.split("?")[0].split("#")[0]
|
|
|
|
|
|
|
| 125 |
name = re.sub(r'/(tree|blob|resolve)/.*$', '', name)
|
| 126 |
|
| 127 |
return name.strip().strip("/")
|
|
|
|
| 132 |
if not clean_name:
|
| 133 |
return {}
|
| 134 |
|
|
|
|
| 135 |
cert = mongo_get_certificate(clean_name)
|
| 136 |
if cert and cert.get("status") == "ok":
|
| 137 |
return cert
|
| 138 |
|
|
|
|
| 139 |
if os.path.exists(EVAL_RESULTS_PATH):
|
| 140 |
safe_prefix = clean_name.replace("/", "__").lower()
|
| 141 |
for f in os.listdir(EVAL_RESULTS_PATH):
|
|
|
|
| 152 |
if not cert or cert.get("status") != "ok":
|
| 153 |
return ""
|
| 154 |
|
|
|
|
| 155 |
os.makedirs(EVAL_RESULTS_PATH, exist_ok=True)
|
| 156 |
safe_name = model_id.replace("/", "__") + f"_{revision}.json"
|
| 157 |
out_path = os.path.join(EVAL_RESULTS_PATH, safe_name)
|
|
|
|
| 161 |
except Exception as e:
|
| 162 |
print(f"Local file write error: {e}", flush=True)
|
| 163 |
|
|
|
|
| 164 |
mongo_save_certificate(cert)
|
| 165 |
|
| 166 |
return out_path
|
| 167 |
|
| 168 |
|
| 169 |
@gpu_decorator(duration=120)
|
| 170 |
+
def execute_direct_xray_audit(
|
| 171 |
+
model_id: str,
|
| 172 |
+
revision: str = "main",
|
| 173 |
+
trust_remote_code: bool = True,
|
| 174 |
+
progress_callback=None,
|
| 175 |
+
) -> dict:
|
| 176 |
now_str = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
| 177 |
|
| 178 |
print(f"[LLM-X-RAY] Verifying repository metadata for '{model_id}'...", flush=True)
|
|
|
|
| 193 |
device="cuda" if has_spaces else AUDIT_DEVICE,
|
| 194 |
token=TOKEN,
|
| 195 |
trust_remote_code=trust_remote_code,
|
| 196 |
+
progress_callback=progress_callback,
|
| 197 |
)
|
| 198 |
|
| 199 |
return {
|
|
|
|
| 253 |
)
|
| 254 |
return
|
| 255 |
|
|
|
|
| 256 |
existing_cert = get_certificate_by_model_name(clean_model)
|
| 257 |
if existing_cert and existing_cert.get("status") == "ok":
|
| 258 |
yield (
|
|
|
|
| 263 |
)
|
| 264 |
return
|
| 265 |
|
| 266 |
+
progress_holder = {"pct": 5, "msg": f"Connecting to HF Hub for {clean_model}..."}
|
| 267 |
+
|
| 268 |
+
def _progress_cb(msg: str, pct: Optional[int] = None):
|
| 269 |
+
if pct is not None:
|
| 270 |
+
progress_holder["pct"] = pct
|
| 271 |
+
progress_holder["msg"] = msg
|
| 272 |
+
|
| 273 |
yield (
|
| 274 |
+
styled_loading(f"Connecting to HF Hub for <b>{clean_model}</b>...", progress_holder["msg"], progress_holder["pct"]),
|
| 275 |
current_df,
|
| 276 |
current_top3,
|
| 277 |
current_panel,
|
|
|
|
| 283 |
def _worker():
|
| 284 |
try:
|
| 285 |
result_holder["cert"] = execute_direct_xray_audit(
|
| 286 |
+
clean_model, "main", trust_remote_code=trust_remote_code, progress_callback=_progress_cb
|
| 287 |
)
|
| 288 |
except Exception as err:
|
| 289 |
traceback.print_exc()
|
|
|
|
| 299 |
thread = threading.Thread(target=_worker, daemon=True)
|
| 300 |
thread.start()
|
| 301 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
while not done_event.is_set():
|
| 303 |
+
current_pct = progress_holder.get("pct", 15)
|
| 304 |
+
current_msg = progress_holder.get("msg", "Auditing model...")
|
| 305 |
yield (
|
| 306 |
+
styled_loading(f"🔬 Auditing <b>{clean_model}</b>...", current_msg, current_pct),
|
| 307 |
current_df,
|
| 308 |
current_top3,
|
| 309 |
current_panel,
|
| 310 |
)
|
| 311 |
+
done_event.wait(timeout=0.8)
|
|
|
|
| 312 |
|
| 313 |
thread.join()
|
| 314 |
cert = result_holder.get("cert", {})
|