beyondnn 0.1.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.
Files changed (80) hide show
  1. beyondnn/__init__.py +82 -0
  2. beyondnn/_testing/__init__.py +7 -0
  3. beyondnn/_testing/attribution_models.py +84 -0
  4. beyondnn/_testing/audit_scenarios.py +679 -0
  5. beyondnn/_testing/causal_models.py +77 -0
  6. beyondnn/_testing/concept_models.py +84 -0
  7. beyondnn/_testing/faithfulness_models.py +97 -0
  8. beyondnn/_testing/models.py +236 -0
  9. beyondnn/attribution/__init__.py +70 -0
  10. beyondnn/attribution/captum.py +203 -0
  11. beyondnn/attribution/claims.py +171 -0
  12. beyondnn/attribution/native.py +299 -0
  13. beyondnn/attribution/runner.py +567 -0
  14. beyondnn/attribution/spec.py +246 -0
  15. beyondnn/audits/__init__.py +184 -0
  16. beyondnn/audits/engine.py +1860 -0
  17. beyondnn/audits/evidence.py +761 -0
  18. beyondnn/audits/plan.py +212 -0
  19. beyondnn/audits/render.py +183 -0
  20. beyondnn/audits/report.py +538 -0
  21. beyondnn/audits/uncertainty.py +175 -0
  22. beyondnn/concepts/__init__.py +108 -0
  23. beyondnn/concepts/_core.py +270 -0
  24. beyondnn/concepts/data.py +209 -0
  25. beyondnn/concepts/encoding.py +519 -0
  26. beyondnn/concepts/features.py +442 -0
  27. beyondnn/concepts/use.py +537 -0
  28. beyondnn/concepts/validate.py +430 -0
  29. beyondnn/concepts/verify.py +588 -0
  30. beyondnn/core/__init__.py +6 -0
  31. beyondnn/core/hooks.py +403 -0
  32. beyondnn/core/persistence.py +255 -0
  33. beyondnn/core/samples.py +61 -0
  34. beyondnn/core/sites.py +208 -0
  35. beyondnn/core/tensors.py +125 -0
  36. beyondnn/core/trace.py +896 -0
  37. beyondnn/core/units.py +101 -0
  38. beyondnn/explain/__init__.py +42 -0
  39. beyondnn/explain/bundle.py +644 -0
  40. beyondnn/explain/handle.py +125 -0
  41. beyondnn/explain/response.py +1157 -0
  42. beyondnn/explain/views.py +244 -0
  43. beyondnn/faithfulness/__init__.py +96 -0
  44. beyondnn/faithfulness/claims.py +167 -0
  45. beyondnn/faithfulness/runner.py +978 -0
  46. beyondnn/faithfulness/spec.py +494 -0
  47. beyondnn/faithfulness/stability.py +574 -0
  48. beyondnn/faithfulness/stats.py +180 -0
  49. beyondnn/faithfulness/verify.py +313 -0
  50. beyondnn/interventions/__init__.py +62 -0
  51. beyondnn/interventions/claims.py +123 -0
  52. beyondnn/interventions/metrics.py +211 -0
  53. beyondnn/interventions/runner.py +850 -0
  54. beyondnn/interventions/spec.py +282 -0
  55. beyondnn/protocols.py +98 -0
  56. beyondnn/provenance/__init__.py +18 -0
  57. beyondnn/provenance/collect.py +106 -0
  58. beyondnn/provenance/fingerprint.py +234 -0
  59. beyondnn/py.typed +0 -0
  60. beyondnn/schema/__init__.py +231 -0
  61. beyondnn/schema/_canonical.py +121 -0
  62. beyondnn/schema/_types.py +298 -0
  63. beyondnn/schema/attribution.py +272 -0
  64. beyondnn/schema/audit.py +410 -0
  65. beyondnn/schema/base.py +276 -0
  66. beyondnn/schema/claims.py +439 -0
  67. beyondnn/schema/codec.py +187 -0
  68. beyondnn/schema/concepts.py +491 -0
  69. beyondnn/schema/errors.py +55 -0
  70. beyondnn/schema/faithfulness.py +253 -0
  71. beyondnn/schema/interventions.py +347 -0
  72. beyondnn/schema/limitations.py +304 -0
  73. beyondnn/schema/provenance.py +302 -0
  74. beyondnn/schema/records.py +114 -0
  75. beyondnn/schema/status.py +205 -0
  76. beyondnn/schema/values.py +304 -0
  77. beyondnn-0.1.0.dist-info/METADATA +560 -0
  78. beyondnn-0.1.0.dist-info/RECORD +80 -0
  79. beyondnn-0.1.0.dist-info/WHEEL +4 -0
  80. beyondnn-0.1.0.dist-info/licenses/LICENSE +202 -0
beyondnn/__init__.py ADDED
@@ -0,0 +1,82 @@
1
+ """BeyondNN: an interpretability evidence framework for PyTorch.
2
+
3
+ Implemented: the trace schema (:mod:`beyondnn.schema`), provenance
4
+ (:mod:`beyondnn.provenance`), trace recording (:func:`trace`,
5
+ :func:`recording`, :class:`TraceResult`), persistence (``TraceResult.save``,
6
+ :func:`load_trace`), and :func:`instrument` (``handle.explain`` returns
7
+ INPUT -> WHY -> OUTPUT, where Phase-1 WHY is measured internal evidence, not a
8
+ causal or attributed explanation).
9
+
10
+ ``import beyondnn`` does not import torch; the tracing names are loaded lazily on
11
+ first use, so :mod:`beyondnn.schema` stays usable without torch.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import TYPE_CHECKING, Any
17
+
18
+ from . import schema
19
+ from .schema import EstimandScope, EvidenceStatus, Outcome, Relation, Verdict
20
+
21
+ if TYPE_CHECKING:
22
+ from .attribution import attribute
23
+ from .audits import audit
24
+ from .core.persistence import load_trace
25
+ from .core.trace import TraceResult, recording, trace
26
+ from .explain import compose, instrument
27
+ from .interventions import intervene
28
+
29
+ __version__ = "0.1.0"
30
+
31
+ __all__ = [
32
+ "EstimandScope",
33
+ "EvidenceStatus",
34
+ "Outcome",
35
+ "Relation",
36
+ "TraceResult",
37
+ "Verdict",
38
+ "__version__",
39
+ "attribute",
40
+ "attribution",
41
+ "audit",
42
+ "audits",
43
+ "compose",
44
+ "concepts",
45
+ "faithfulness",
46
+ "instrument",
47
+ "intervene",
48
+ "interventions",
49
+ "load_trace",
50
+ "recording",
51
+ "schema",
52
+ "trace",
53
+ ]
54
+
55
+ _LAZY = {
56
+ "trace": "beyondnn.core.trace",
57
+ "recording": "beyondnn.core.trace",
58
+ "TraceResult": "beyondnn.core.trace",
59
+ "load_trace": "beyondnn.core.persistence",
60
+ "instrument": "beyondnn.explain",
61
+ "compose": "beyondnn.explain",
62
+ "intervene": "beyondnn.interventions",
63
+ "attribute": "beyondnn.attribution",
64
+ "audit": "beyondnn.audits",
65
+ }
66
+
67
+
68
+ def __getattr__(name: str) -> Any:
69
+ if name in ("interventions", "attribution", "faithfulness", "concepts", "audits"):
70
+ import importlib
71
+
72
+ module = importlib.import_module(f"beyondnn.{name}")
73
+ globals()[name] = module
74
+ return module
75
+ module_name = _LAZY.get(name)
76
+ if module_name is None:
77
+ raise AttributeError(f"module 'beyondnn' has no attribute {name!r}")
78
+ import importlib
79
+
80
+ value = getattr(importlib.import_module(module_name), name)
81
+ globals()[name] = value
82
+ return value
@@ -0,0 +1,7 @@
1
+ """Internal, unstable testing utilities. NOT public BeyondNN API.
2
+
3
+ Contents may change or disappear without notice. Nothing here is exported from
4
+ ``beyondnn``. The reference models in :mod:`beyondnn._testing.models` are
5
+ deliberately ordinary networks for testing BeyondNN's evidence machinery; they
6
+ are not BeyondNN model architectures.
7
+ """
@@ -0,0 +1,84 @@
1
+ """Fixed-weight ground-truth models for Phase-3 attribution tests (internal, unstable).
2
+
3
+ Input ``x = (x0, x1)`` of shape (1, 2); target ``y[0, 0]``. Expected attributions are
4
+ derived analytically in docs/PHASE_3_PLAN.md (before any experiment ran).
5
+
6
+ ========== =================== ============== ============== =====================
7
+ Model F gradient input x grad IG, zero baseline
8
+ ========== =================== ============== ============== =====================
9
+ Linear 2 x0 + 3 x1 [2, 3] [2 x0, 3 x1] [2 x0, 3 x1]
10
+ Irrelevant 4 x0 [4, 0] [4 x0, 0] [4 x0, 0]
11
+ Product x0 x1 [x1, x0] [x0 x1, x0 x1] [x0 x1 / 2, x0 x1 / 2]
12
+ Saturating tanh(x0) + x1 [sech^2 x0, 1] [x0 sech^2 x0, [tanh x0, x1]
13
+ x1]
14
+ ========== =================== ============== ============== =====================
15
+
16
+ ``Twice`` applies one scalar linear map (weight 2) twice: ``y = lin(lin(x))``; the
17
+ gradient at call 0's output is 2 and at call 1's output is 1. ``Aliased`` registers
18
+ one module under two paths.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import torch
24
+ from torch import nn
25
+
26
+ __all__ = ["Aliased", "Irrelevant", "Linear", "Product", "Saturating", "Twice"]
27
+
28
+
29
+ def _linear(weights: list[float]) -> nn.Linear:
30
+ layer = nn.Linear(len(weights), 1, bias=False)
31
+ with torch.no_grad():
32
+ layer.weight.copy_(torch.tensor([weights]))
33
+ return layer
34
+
35
+
36
+ class Linear(nn.Module):
37
+ def __init__(self) -> None:
38
+ super().__init__()
39
+ self.lin = _linear([2.0, 3.0])
40
+
41
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
42
+ out: torch.Tensor = self.lin(x)
43
+ return out
44
+
45
+
46
+ class Irrelevant(nn.Module):
47
+ def __init__(self) -> None:
48
+ super().__init__()
49
+ self.lin = _linear([4.0, 0.0])
50
+
51
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
52
+ out: torch.Tensor = self.lin(x)
53
+ return out
54
+
55
+
56
+ class Product(nn.Module):
57
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
58
+ return (x[:, 0] * x[:, 1]).unsqueeze(1)
59
+
60
+
61
+ class Saturating(nn.Module):
62
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
63
+ return (torch.tanh(x[:, 0]) + x[:, 1]).unsqueeze(1)
64
+
65
+
66
+ class Twice(nn.Module):
67
+ def __init__(self) -> None:
68
+ super().__init__()
69
+ self.lin = _linear([2.0])
70
+
71
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
72
+ out: torch.Tensor = self.lin(self.lin(x))
73
+ return out
74
+
75
+
76
+ class Aliased(nn.Module):
77
+ def __init__(self) -> None:
78
+ super().__init__()
79
+ self.first = _linear([1.0, 1.0])
80
+ self.alias = self.first
81
+
82
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
83
+ out: torch.Tensor = self.first(x)
84
+ return out