invarlock 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- invarlock/__init__.py +33 -0
- invarlock/__main__.py +10 -0
- invarlock/_data/runtime/profiles/ci_cpu.yaml +15 -0
- invarlock/_data/runtime/profiles/release.yaml +23 -0
- invarlock/_data/runtime/tiers.yaml +76 -0
- invarlock/adapters/__init__.py +102 -0
- invarlock/adapters/_capabilities.py +45 -0
- invarlock/adapters/auto.py +99 -0
- invarlock/adapters/base.py +530 -0
- invarlock/adapters/base_types.py +85 -0
- invarlock/adapters/hf_bert.py +852 -0
- invarlock/adapters/hf_gpt2.py +403 -0
- invarlock/adapters/hf_llama.py +485 -0
- invarlock/adapters/hf_mixin.py +383 -0
- invarlock/adapters/hf_onnx.py +112 -0
- invarlock/adapters/hf_t5.py +137 -0
- invarlock/adapters/py.typed +1 -0
- invarlock/assurance/__init__.py +43 -0
- invarlock/cli/__init__.py +8 -0
- invarlock/cli/__main__.py +8 -0
- invarlock/cli/_evidence.py +25 -0
- invarlock/cli/_json.py +75 -0
- invarlock/cli/adapter_auto.py +162 -0
- invarlock/cli/app.py +287 -0
- invarlock/cli/commands/__init__.py +26 -0
- invarlock/cli/commands/certify.py +403 -0
- invarlock/cli/commands/doctor.py +1358 -0
- invarlock/cli/commands/explain_gates.py +151 -0
- invarlock/cli/commands/export_html.py +100 -0
- invarlock/cli/commands/plugins.py +1331 -0
- invarlock/cli/commands/report.py +354 -0
- invarlock/cli/commands/run.py +4146 -0
- invarlock/cli/commands/verify.py +1040 -0
- invarlock/cli/config.py +396 -0
- invarlock/cli/constants.py +68 -0
- invarlock/cli/device.py +92 -0
- invarlock/cli/doctor_helpers.py +74 -0
- invarlock/cli/errors.py +6 -0
- invarlock/cli/overhead_utils.py +60 -0
- invarlock/cli/provenance.py +66 -0
- invarlock/cli/utils.py +41 -0
- invarlock/config.py +56 -0
- invarlock/core/__init__.py +62 -0
- invarlock/core/abi.py +15 -0
- invarlock/core/api.py +274 -0
- invarlock/core/auto_tuning.py +317 -0
- invarlock/core/bootstrap.py +226 -0
- invarlock/core/checkpoint.py +221 -0
- invarlock/core/contracts.py +73 -0
- invarlock/core/error_utils.py +64 -0
- invarlock/core/events.py +298 -0
- invarlock/core/exceptions.py +95 -0
- invarlock/core/registry.py +481 -0
- invarlock/core/retry.py +146 -0
- invarlock/core/runner.py +2041 -0
- invarlock/core/types.py +154 -0
- invarlock/edits/__init__.py +12 -0
- invarlock/edits/_edit_utils.py +249 -0
- invarlock/edits/_external_utils.py +268 -0
- invarlock/edits/noop.py +47 -0
- invarlock/edits/py.typed +1 -0
- invarlock/edits/quant_rtn.py +801 -0
- invarlock/edits/registry.py +166 -0
- invarlock/eval/__init__.py +23 -0
- invarlock/eval/bench.py +1207 -0
- invarlock/eval/bootstrap.py +50 -0
- invarlock/eval/data.py +2052 -0
- invarlock/eval/metrics.py +2167 -0
- invarlock/eval/primary_metric.py +767 -0
- invarlock/eval/probes/__init__.py +24 -0
- invarlock/eval/probes/fft.py +139 -0
- invarlock/eval/probes/mi.py +213 -0
- invarlock/eval/probes/post_attention.py +323 -0
- invarlock/eval/providers/base.py +67 -0
- invarlock/eval/providers/seq2seq.py +111 -0
- invarlock/eval/providers/text_lm.py +113 -0
- invarlock/eval/providers/vision_text.py +93 -0
- invarlock/eval/py.typed +1 -0
- invarlock/guards/__init__.py +18 -0
- invarlock/guards/_contracts.py +9 -0
- invarlock/guards/invariants.py +640 -0
- invarlock/guards/policies.py +805 -0
- invarlock/guards/py.typed +1 -0
- invarlock/guards/rmt.py +2097 -0
- invarlock/guards/spectral.py +1419 -0
- invarlock/guards/tier_config.py +354 -0
- invarlock/guards/variance.py +3298 -0
- invarlock/guards_ref/__init__.py +15 -0
- invarlock/guards_ref/rmt_ref.py +40 -0
- invarlock/guards_ref/spectral_ref.py +135 -0
- invarlock/guards_ref/variance_ref.py +60 -0
- invarlock/model_profile.py +353 -0
- invarlock/model_utils.py +221 -0
- invarlock/observability/__init__.py +10 -0
- invarlock/observability/alerting.py +535 -0
- invarlock/observability/core.py +546 -0
- invarlock/observability/exporters.py +565 -0
- invarlock/observability/health.py +588 -0
- invarlock/observability/metrics.py +457 -0
- invarlock/observability/py.typed +1 -0
- invarlock/observability/utils.py +553 -0
- invarlock/plugins/__init__.py +12 -0
- invarlock/plugins/hello_guard.py +33 -0
- invarlock/plugins/hf_awq_adapter.py +82 -0
- invarlock/plugins/hf_bnb_adapter.py +79 -0
- invarlock/plugins/hf_gptq_adapter.py +78 -0
- invarlock/plugins/py.typed +1 -0
- invarlock/py.typed +1 -0
- invarlock/reporting/__init__.py +7 -0
- invarlock/reporting/certificate.py +3221 -0
- invarlock/reporting/certificate_schema.py +244 -0
- invarlock/reporting/dataset_hashing.py +215 -0
- invarlock/reporting/guards_analysis.py +948 -0
- invarlock/reporting/html.py +32 -0
- invarlock/reporting/normalizer.py +235 -0
- invarlock/reporting/policy_utils.py +517 -0
- invarlock/reporting/primary_metric_utils.py +265 -0
- invarlock/reporting/render.py +1442 -0
- invarlock/reporting/report.py +903 -0
- invarlock/reporting/report_types.py +278 -0
- invarlock/reporting/utils.py +175 -0
- invarlock/reporting/validate.py +631 -0
- invarlock/security.py +176 -0
- invarlock/sparsity_utils.py +323 -0
- invarlock/utils/__init__.py +150 -0
- invarlock/utils/digest.py +45 -0
- invarlock-0.2.0.dist-info/METADATA +586 -0
- invarlock-0.2.0.dist-info/RECORD +132 -0
- invarlock-0.2.0.dist-info/WHEEL +5 -0
- invarlock-0.2.0.dist-info/entry_points.txt +20 -0
- invarlock-0.2.0.dist-info/licenses/LICENSE +201 -0
- invarlock-0.2.0.dist-info/top_level.txt +1 -0
invarlock/__init__.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
InvarLock: Edit‑agnostic robustness certificates for weight edits
|
|
3
|
+
=============================================================
|
|
4
|
+
|
|
5
|
+
Core runtime package — torch-independent utilities, configuration, and interfaces.
|
|
6
|
+
|
|
7
|
+
This package provides the foundation for the InvarLock GuardChain without heavy dependencies.
|
|
8
|
+
For torch-dependent functionality, see subpackages under `invarlock.*`:
|
|
9
|
+
- `invarlock.adapters`: Model adapters (HF GPT-2/BERT/LLaMA, auto)
|
|
10
|
+
- `invarlock.guards`: Safety mechanisms (invariants, spectral, RMT, variance)
|
|
11
|
+
- `invarlock.edits`: Built-in quantization and edit interfaces
|
|
12
|
+
- `invarlock.eval`: Metrics, guard-overhead checks, and certification
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__version__ = "0.2.0"
|
|
16
|
+
|
|
17
|
+
# Core exports - torch-independent
|
|
18
|
+
from .config import CFG, Defaults, get_default_config
|
|
19
|
+
|
|
20
|
+
__all__ = ["__version__", "get_default_config", "Defaults", "CFG"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def __getattr__(name: str): # pragma: no cover - thin lazy loader
|
|
24
|
+
"""Lazily expose selected subpackages without importing heavy deps at init.
|
|
25
|
+
|
|
26
|
+
This keeps `import invarlock` torch-free while allowing patterns like
|
|
27
|
+
monkeypatching `invarlock.eval.*` in tests.
|
|
28
|
+
"""
|
|
29
|
+
if name == "eval":
|
|
30
|
+
import importlib
|
|
31
|
+
|
|
32
|
+
return importlib.import_module(".eval", __name__)
|
|
33
|
+
raise AttributeError(name)
|
invarlock/__main__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# CPU-only CI profile for telemetry/edge validation runs.
|
|
2
|
+
#
|
|
3
|
+
# Forces CPU execution and trims window counts slightly so telemetry runs
|
|
4
|
+
# finish quickly on developer machines while still exercising guards.
|
|
5
|
+
|
|
6
|
+
model:
|
|
7
|
+
device: "cpu"
|
|
8
|
+
|
|
9
|
+
dataset:
|
|
10
|
+
preview_n: 120
|
|
11
|
+
final_n: 120
|
|
12
|
+
stride: 512
|
|
13
|
+
|
|
14
|
+
context:
|
|
15
|
+
telemetry_profile: "ci_cpu"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Release profile overrides for certification workflows.
|
|
2
|
+
#
|
|
3
|
+
# Applies denser evaluation coverage, longer bootstrap runs, and embeds
|
|
4
|
+
# policy snapshot metadata so artifacts can be audited after publication.
|
|
5
|
+
|
|
6
|
+
dataset:
|
|
7
|
+
preview_n: 400
|
|
8
|
+
final_n: 400
|
|
9
|
+
|
|
10
|
+
guards:
|
|
11
|
+
variance:
|
|
12
|
+
max_calib: 320
|
|
13
|
+
|
|
14
|
+
eval:
|
|
15
|
+
bootstrap:
|
|
16
|
+
replicates: 3200
|
|
17
|
+
alpha: 0.05
|
|
18
|
+
method: bca_paired_delta_log
|
|
19
|
+
|
|
20
|
+
context:
|
|
21
|
+
policy_snapshot:
|
|
22
|
+
tiers_file: src/invarlock/_data/runtime/tiers.yaml
|
|
23
|
+
profile: release
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Tier guard policy knobs for variance correction (balanced vs conservative)
|
|
2
|
+
#
|
|
3
|
+
# These values mirror the settings validated during the December 2025
|
|
4
|
+
# calibration runs. They should be kept in sync with the policy digest
|
|
5
|
+
# embedded in certificates and referenced by automation documentation.
|
|
6
|
+
|
|
7
|
+
balanced:
|
|
8
|
+
variance_guard:
|
|
9
|
+
deadband: 0.02
|
|
10
|
+
min_abs_adjust: 0.012
|
|
11
|
+
max_scale_step: 0.03
|
|
12
|
+
min_effect_lognll: 0.0009
|
|
13
|
+
predictive_one_sided: true
|
|
14
|
+
topk_backstop: 1
|
|
15
|
+
max_adjusted_modules: 1
|
|
16
|
+
tap: "transformer.h.*.mlp.c_proj"
|
|
17
|
+
predictive_gate: true
|
|
18
|
+
spectral_guard:
|
|
19
|
+
sigma_quantile: 0.95
|
|
20
|
+
deadband: 0.10
|
|
21
|
+
scope: all
|
|
22
|
+
max_caps: 5
|
|
23
|
+
max_spectral_norm: null
|
|
24
|
+
family_caps:
|
|
25
|
+
ffn: 3.834
|
|
26
|
+
attn: 3.423
|
|
27
|
+
embed: 3.1
|
|
28
|
+
other: 3.1
|
|
29
|
+
multiple_testing:
|
|
30
|
+
method: bh
|
|
31
|
+
alpha: 0.05
|
|
32
|
+
m: 4
|
|
33
|
+
rmt_guard:
|
|
34
|
+
deadband: 0.10
|
|
35
|
+
margin: 1.5
|
|
36
|
+
epsilon_default: 0.10
|
|
37
|
+
epsilon_by_family:
|
|
38
|
+
ffn: 0.10
|
|
39
|
+
attn: 0.08
|
|
40
|
+
embed: 0.12
|
|
41
|
+
other: 0.12
|
|
42
|
+
|
|
43
|
+
conservative:
|
|
44
|
+
variance_guard:
|
|
45
|
+
deadband: 0.03
|
|
46
|
+
min_abs_adjust: 0.02
|
|
47
|
+
max_scale_step: 0.015
|
|
48
|
+
min_effect_lognll: 0.0018
|
|
49
|
+
predictive_one_sided: false
|
|
50
|
+
topk_backstop: 0
|
|
51
|
+
max_adjusted_modules: 0
|
|
52
|
+
tap: "transformer.h.*.mlp.c_proj"
|
|
53
|
+
predictive_gate: true
|
|
54
|
+
spectral_guard:
|
|
55
|
+
sigma_quantile: 0.90
|
|
56
|
+
deadband: 0.05
|
|
57
|
+
scope: ffn
|
|
58
|
+
max_caps: 3
|
|
59
|
+
family_caps:
|
|
60
|
+
ffn: 2.3
|
|
61
|
+
attn: 2.6
|
|
62
|
+
embed: 2.8
|
|
63
|
+
other: 2.8
|
|
64
|
+
multiple_testing:
|
|
65
|
+
method: bonferroni
|
|
66
|
+
alpha: 0.02
|
|
67
|
+
m: 4
|
|
68
|
+
rmt_guard:
|
|
69
|
+
deadband: 0.05
|
|
70
|
+
margin: 1.3
|
|
71
|
+
epsilon_default: 0.06
|
|
72
|
+
epsilon_by_family:
|
|
73
|
+
ffn: 0.06
|
|
74
|
+
attn: 0.05
|
|
75
|
+
embed: 0.07
|
|
76
|
+
other: 0.07
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Adapter namespace (`invarlock.adapters`) exposing built-in adapters.
|
|
2
|
+
|
|
3
|
+
Provides lazy import of heavy submodules to avoid importing Transformers
|
|
4
|
+
stacks unless needed. Accessing adapter classes triggers on-demand import.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import importlib as _importlib
|
|
10
|
+
from typing import Any as _Any
|
|
11
|
+
|
|
12
|
+
from invarlock.core.abi import INVARLOCK_CORE_ABI as INVARLOCK_CORE_ABI
|
|
13
|
+
|
|
14
|
+
from .base import (
|
|
15
|
+
AdapterConfig,
|
|
16
|
+
AdapterInterface,
|
|
17
|
+
BaseAdapter,
|
|
18
|
+
DeviceManager,
|
|
19
|
+
)
|
|
20
|
+
from .base import (
|
|
21
|
+
PerformanceMetrics as BasePerformanceMetrics,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
_LAZY_MAP = {
|
|
25
|
+
"HF_BERT_Adapter": ".hf_bert",
|
|
26
|
+
"HF_GPT2_Adapter": ".hf_gpt2",
|
|
27
|
+
"HF_LLaMA_Adapter": ".hf_llama",
|
|
28
|
+
"HF_T5_Adapter": ".hf_t5",
|
|
29
|
+
"HF_ORT_CausalLM_Adapter": ".hf_onnx",
|
|
30
|
+
"HF_Causal_Auto_Adapter": ".auto",
|
|
31
|
+
"HF_MLM_Auto_Adapter": ".auto",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def __getattr__(name: str) -> _Any: # pragma: no cover - simple lazy import
|
|
36
|
+
mod_name = _LAZY_MAP.get(name)
|
|
37
|
+
if not mod_name:
|
|
38
|
+
raise AttributeError(name)
|
|
39
|
+
module = _importlib.import_module(mod_name, __name__)
|
|
40
|
+
try:
|
|
41
|
+
return getattr(module, name)
|
|
42
|
+
except AttributeError as exc: # re-raise with module context
|
|
43
|
+
raise AttributeError(f"{name} not found in {mod_name}") from exc
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Simple quality label helper used by tests
|
|
47
|
+
def quality_label(ratio: float) -> str:
|
|
48
|
+
if ratio <= 1.10:
|
|
49
|
+
return "Excellent"
|
|
50
|
+
if ratio <= 1.25:
|
|
51
|
+
return "Good"
|
|
52
|
+
if ratio <= 1.40:
|
|
53
|
+
return "Fair"
|
|
54
|
+
return "Degraded"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class _RemovedComponent:
|
|
58
|
+
def __init__(self, name: str, replacement: str | None = None):
|
|
59
|
+
self._name = name
|
|
60
|
+
self._replacement = replacement
|
|
61
|
+
|
|
62
|
+
def __call__(self, *args, **kwargs):
|
|
63
|
+
raise NotImplementedError(
|
|
64
|
+
f"{self._name} is not available in InvarLock 1.0."
|
|
65
|
+
+ (f" Use: {self._replacement}" if self._replacement else "")
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def __getattr__(self, _): # pragma: no cover - simple passthrough
|
|
69
|
+
return _RemovedComponent(self._name, self._replacement)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Placeholders for removed/legacy utilities referenced in tests
|
|
73
|
+
HF_Pythia_Adapter = _RemovedComponent("HF_Pythia_Adapter")
|
|
74
|
+
auto_tune_pruning_budget = _RemovedComponent("auto_tune_pruning_budget")
|
|
75
|
+
run_auto_invarlock = _RemovedComponent("run_auto_invarlock")
|
|
76
|
+
InvarLockPipeline = _RemovedComponent("InvarLockPipeline", "invarlock.cli.app:main")
|
|
77
|
+
InvarLockConfig = _RemovedComponent(
|
|
78
|
+
"InvarLockConfig", "invarlock.cli.config:InvarLockConfig"
|
|
79
|
+
)
|
|
80
|
+
run_invarlock_pipeline = _RemovedComponent(
|
|
81
|
+
"run_invarlock_pipeline", "invarlock.cli.run"
|
|
82
|
+
)
|
|
83
|
+
run_invarlock = _RemovedComponent("run_invarlock", "invarlock.cli.run")
|
|
84
|
+
quick_prune_gpt2 = _RemovedComponent("quick_prune_gpt2")
|
|
85
|
+
|
|
86
|
+
__all__ = [
|
|
87
|
+
"HF_GPT2_Adapter",
|
|
88
|
+
"HF_BERT_Adapter",
|
|
89
|
+
"HF_LLaMA_Adapter",
|
|
90
|
+
"HF_T5_Adapter",
|
|
91
|
+
"HF_ORT_CausalLM_Adapter",
|
|
92
|
+
"HF_Causal_Auto_Adapter",
|
|
93
|
+
"HF_MLM_Auto_Adapter",
|
|
94
|
+
"BaseAdapter",
|
|
95
|
+
"AdapterConfig",
|
|
96
|
+
"AdapterInterface",
|
|
97
|
+
"DeviceManager",
|
|
98
|
+
"BasePerformanceMetrics",
|
|
99
|
+
"quality_label",
|
|
100
|
+
"_RemovedComponent",
|
|
101
|
+
"INVARLOCK_CORE_ABI",
|
|
102
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model capability probes (lightweight, no heavy imports).
|
|
3
|
+
|
|
4
|
+
Currently supports a simple MoE probe that scans module names to infer whether
|
|
5
|
+
the model likely contains mixture-of-experts structures (router/gating and
|
|
6
|
+
expert FFNs).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def probe_moe_capabilities(model: Any) -> dict[str, Any]:
|
|
15
|
+
"""Detect MoE-related modules in a model by name heuristics.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
{
|
|
19
|
+
'moe': bool,
|
|
20
|
+
'families': set[str], # e.g., {'router','expert_ffn'}
|
|
21
|
+
'counts': dict[str,int], # occurrences per family
|
|
22
|
+
}
|
|
23
|
+
"""
|
|
24
|
+
families: set[str] = set()
|
|
25
|
+
counts: dict[str, int] = {}
|
|
26
|
+
try:
|
|
27
|
+
for name, _module in model.named_modules():
|
|
28
|
+
lname = str(name).lower()
|
|
29
|
+
# Router/gating indicators
|
|
30
|
+
if any(
|
|
31
|
+
tok in lname
|
|
32
|
+
for tok in ("router", "routing", "gate", "gating", "dispatch", "switch")
|
|
33
|
+
):
|
|
34
|
+
families.add("router")
|
|
35
|
+
counts["router"] = counts.get("router", 0) + 1
|
|
36
|
+
# Expert FFN indicators
|
|
37
|
+
if any(
|
|
38
|
+
tok in lname
|
|
39
|
+
for tok in ("experts", "expert", "moe", "mixture_of_experts")
|
|
40
|
+
):
|
|
41
|
+
families.add("expert_ffn")
|
|
42
|
+
counts["expert_ffn"] = counts.get("expert_ffn", 0) + 1
|
|
43
|
+
except Exception:
|
|
44
|
+
pass
|
|
45
|
+
return {"moe": bool(families), "families": families, "counts": counts}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib as _importlib
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from invarlock.core.api import ModelAdapter
|
|
7
|
+
|
|
8
|
+
from ..cli.adapter_auto import resolve_auto_adapter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _DelegatingAdapter(ModelAdapter):
|
|
12
|
+
name = "auto_adapter"
|
|
13
|
+
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
self._delegate: ModelAdapter | None = None
|
|
16
|
+
|
|
17
|
+
def _ensure_delegate_from_id(self, model_id: str) -> ModelAdapter:
|
|
18
|
+
if self._delegate is not None:
|
|
19
|
+
return self._delegate
|
|
20
|
+
resolved = resolve_auto_adapter(model_id)
|
|
21
|
+
if resolved == "hf_llama":
|
|
22
|
+
HF_LLaMA_Adapter = _importlib.import_module(
|
|
23
|
+
".hf_llama", __package__
|
|
24
|
+
).HF_LLaMA_Adapter
|
|
25
|
+
self._delegate = HF_LLaMA_Adapter()
|
|
26
|
+
elif resolved == "hf_bert":
|
|
27
|
+
HF_BERT_Adapter = _importlib.import_module(
|
|
28
|
+
".hf_bert", __package__
|
|
29
|
+
).HF_BERT_Adapter
|
|
30
|
+
self._delegate = HF_BERT_Adapter()
|
|
31
|
+
else:
|
|
32
|
+
HF_GPT2_Adapter = _importlib.import_module(
|
|
33
|
+
".hf_gpt2", __package__
|
|
34
|
+
).HF_GPT2_Adapter
|
|
35
|
+
self._delegate = HF_GPT2_Adapter()
|
|
36
|
+
return self._delegate
|
|
37
|
+
|
|
38
|
+
def _ensure_delegate_from_model(self, model: Any) -> ModelAdapter:
|
|
39
|
+
# Best-effort: inspect class name
|
|
40
|
+
cls_name = getattr(model, "__class__", type(model)).__name__.lower()
|
|
41
|
+
if any(k in cls_name for k in ["llama", "mistral", "qwen", "yi"]):
|
|
42
|
+
HF_LLaMA_Adapter = _importlib.import_module(
|
|
43
|
+
".hf_llama", __package__
|
|
44
|
+
).HF_LLaMA_Adapter
|
|
45
|
+
self._delegate = HF_LLaMA_Adapter()
|
|
46
|
+
elif any(k in cls_name for k in ["bert", "roberta", "albert", "deberta"]):
|
|
47
|
+
HF_BERT_Adapter = _importlib.import_module(
|
|
48
|
+
".hf_bert", __package__
|
|
49
|
+
).HF_BERT_Adapter
|
|
50
|
+
self._delegate = HF_BERT_Adapter()
|
|
51
|
+
else:
|
|
52
|
+
HF_GPT2_Adapter = _importlib.import_module(
|
|
53
|
+
".hf_gpt2", __package__
|
|
54
|
+
).HF_GPT2_Adapter
|
|
55
|
+
self._delegate = HF_GPT2_Adapter()
|
|
56
|
+
return self._delegate
|
|
57
|
+
|
|
58
|
+
def can_handle(self, model: Any) -> bool: # pragma: no cover - trivial
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
def describe(self, model: Any) -> dict[str, Any]:
|
|
62
|
+
delegate = self._delegate or self._ensure_delegate_from_model(model)
|
|
63
|
+
return delegate.describe(model)
|
|
64
|
+
|
|
65
|
+
def snapshot(self, model: Any) -> bytes:
|
|
66
|
+
delegate = self._delegate or self._ensure_delegate_from_model(model)
|
|
67
|
+
return delegate.snapshot(model)
|
|
68
|
+
|
|
69
|
+
def restore(self, model: Any, blob: bytes) -> None:
|
|
70
|
+
delegate = self._delegate or self._ensure_delegate_from_model(model)
|
|
71
|
+
return delegate.restore(model, blob)
|
|
72
|
+
|
|
73
|
+
def __getattr__(self, item: str): # pragma: no cover - passthrough
|
|
74
|
+
if item == "_delegate":
|
|
75
|
+
raise AttributeError(item)
|
|
76
|
+
delegate = self._delegate
|
|
77
|
+
if delegate is not None and hasattr(delegate, item):
|
|
78
|
+
return getattr(delegate, item)
|
|
79
|
+
raise AttributeError(item)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class HF_Causal_Auto_Adapter(_DelegatingAdapter):
|
|
83
|
+
name = "hf_causal_auto"
|
|
84
|
+
|
|
85
|
+
def load_model(self, model_id: str, device: str = "auto") -> Any:
|
|
86
|
+
delegate = self._ensure_delegate_from_id(model_id)
|
|
87
|
+
return delegate.load_model(model_id, device=device)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class HF_MLM_Auto_Adapter(_DelegatingAdapter):
|
|
91
|
+
name = "hf_mlm_auto"
|
|
92
|
+
|
|
93
|
+
def load_model(self, model_id: str, device: str = "auto") -> Any:
|
|
94
|
+
# Force BERT-like adapter for MLM families
|
|
95
|
+
HF_BERT_Adapter = _importlib.import_module(
|
|
96
|
+
".hf_bert", __package__
|
|
97
|
+
).HF_BERT_Adapter
|
|
98
|
+
self._delegate = HF_BERT_Adapter()
|
|
99
|
+
return self._delegate.load_model(model_id, device=device)
|