vlmprobe 0.9.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 (78) hide show
  1. vlm_probing/__init__.py +17 -0
  2. vlm_probing/_vendor/__init__.py +1 -0
  3. vlm_probing/_vendor/chefer2021/LICENSE +21 -0
  4. vlm_probing/_vendor/chefer2021/README.md +22 -0
  5. vlm_probing/_vendor/chefer2021/__init__.py +1 -0
  6. vlm_probing/_vendor/chefer2021/layer_helpers.py +21 -0
  7. vlm_probing/_vendor/chefer2021/layers.py +280 -0
  8. vlm_probing/_vendor/chefer2021/vit.py +372 -0
  9. vlm_probing/_vendor/chefer2021/weight_init.py +60 -0
  10. vlm_probing/adapters/__init__.py +7 -0
  11. vlm_probing/adapters/auto.py +35 -0
  12. vlm_probing/adapters/base.py +15 -0
  13. vlm_probing/adapters/hf_attention.py +70 -0
  14. vlm_probing/adapters/huggingface.py +184 -0
  15. vlm_probing/adapters/spec.py +198 -0
  16. vlm_probing/adapters/torch.py +201 -0
  17. vlm_probing/adapters/vit.py +103 -0
  18. vlm_probing/api/__init__.py +1 -0
  19. vlm_probing/api/attention.py +214 -0
  20. vlm_probing/api/attention_maps.py +146 -0
  21. vlm_probing/api/causal.py +371 -0
  22. vlm_probing/api/common.py +145 -0
  23. vlm_probing/api/lenses.py +248 -0
  24. vlm_probing/attention/__init__.py +22 -0
  25. vlm_probing/attention/_attribution_utils.py +45 -0
  26. vlm_probing/attention/attribution.py +46 -0
  27. vlm_probing/attention/base.py +68 -0
  28. vlm_probing/attention/beyond_intuition.py +103 -0
  29. vlm_probing/attention/chefer.py +53 -0
  30. vlm_probing/attention/grad_cam.py +55 -0
  31. vlm_probing/attention/head_logit_attribution.py +54 -0
  32. vlm_probing/attention/lrp.py +195 -0
  33. vlm_probing/attention/profile.py +51 -0
  34. vlm_probing/attention/relevance.py +47 -0
  35. vlm_probing/attention/reweight.py +49 -0
  36. vlm_probing/attention/rollout.py +54 -0
  37. vlm_probing/attention/tam.py +58 -0
  38. vlm_probing/attention/temperature.py +46 -0
  39. vlm_probing/causal/__init__.py +15 -0
  40. vlm_probing/causal/activation_patching.py +29 -0
  41. vlm_probing/causal/attention_knockout.py +47 -0
  42. vlm_probing/causal/attribution_patching.py +47 -0
  43. vlm_probing/causal/base.py +94 -0
  44. vlm_probing/causal/eap_ig.py +81 -0
  45. vlm_probing/causal/path_patching.py +185 -0
  46. vlm_probing/causal/steering.py +63 -0
  47. vlm_probing/causal/transformer_eap_ig.py +397 -0
  48. vlm_probing/causal/visual_steering.py +99 -0
  49. vlm_probing/core/__init__.py +4 -0
  50. vlm_probing/core/base.py +16 -0
  51. vlm_probing/core/types.py +41 -0
  52. vlm_probing/lenses/__init__.py +10 -0
  53. vlm_probing/lenses/attention.py +116 -0
  54. vlm_probing/lenses/base.py +144 -0
  55. vlm_probing/lenses/embed.py +74 -0
  56. vlm_probing/lenses/jacobian.py +127 -0
  57. vlm_probing/lenses/logit.py +28 -0
  58. vlm_probing/lenses/patchscope.py +65 -0
  59. vlm_probing/lenses/tuned.py +76 -0
  60. vlm_probing/metrics.py +91 -0
  61. vlm_probing/prober.py +129 -0
  62. vlm_probing/training/__init__.py +8 -0
  63. vlm_probing/training/cache.py +49 -0
  64. vlm_probing/training/distribution.py +187 -0
  65. vlm_probing/training/jacobian.py +139 -0
  66. vlm_probing/training/model_bound.py +83 -0
  67. vlm_probing/training/tuned_import.py +98 -0
  68. vlm_probing/visualization/__init__.py +22 -0
  69. vlm_probing/visualization/_common.py +112 -0
  70. vlm_probing/visualization/attention.py +238 -0
  71. vlm_probing/visualization/causal.py +222 -0
  72. vlm_probing/visualization/lenses.py +84 -0
  73. vlm_probing/visualization/path_graphs.py +254 -0
  74. vlmprobe/__init__.py +38 -0
  75. vlmprobe-0.9.0.dist-info/METADATA +257 -0
  76. vlmprobe-0.9.0.dist-info/RECORD +78 -0
  77. vlmprobe-0.9.0.dist-info/WHEEL +5 -0
  78. vlmprobe-0.9.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,17 @@
1
+ """Three method families: causal interventions, attention analysis, and lenses."""
2
+ from .core import BaseMethod, ForwardTrace, ProbeResult
3
+ from .adapters import BaseModelAdapter, HookPoint, ModelReadout, TorchModelAdapter
4
+ from .adapters import CapabilityError, HeadSite, ModelSpec, ProbeInputs, TokenLayout, register_adapter
5
+ from .prober import Prober
6
+ from .api.lenses import LensMethods
7
+ from .api.attention import AttentionMethods
8
+ from .api.causal import CausalMethods
9
+ from .metrics import TokenMargin, SequenceLogProb, ClassScore
10
+ from . import visualization
11
+
12
+ __version__ = "0.9.0"
13
+ __all__ = ["BaseMethod", "ProbeResult", "ForwardTrace", "BaseModelAdapter",
14
+ "HookPoint", "ModelReadout", "TorchModelAdapter", "Prober", "ModelSpec",
15
+ "ProbeInputs", "TokenLayout", "HeadSite", "CapabilityError", "register_adapter",
16
+ "LensMethods", "AttentionMethods", "CausalMethods", "TokenMargin", "SequenceLogProb", "ClassScore",
17
+ "visualization"]
@@ -0,0 +1 @@
1
+ """Pinned third-party research kernels, imported only by explicit backends."""
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Hila Chefer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,22 @@
1
+ # Pinned Chefer CVPR 2021 ViT relevance implementation
2
+
3
+ Source: [hila-chefer/Transformer-Explainability](https://github.com/hila-chefer/Transformer-Explainability),
4
+ commit [`c3e578f76b954e8528afeaaee26de3f07e3fe559`](https://github.com/hila-chefer/Transformer-Explainability/tree/c3e578f76b954e8528afeaaee26de3f07e3fe559).
5
+ The source is MIT licensed; the complete license is retained in [LICENSE](LICENSE).
6
+
7
+ | Local file | Upstream file | Changes |
8
+ | --- | --- | --- |
9
+ | `layers.py` | `modules/layers_ours.py` | Byte-identical. |
10
+ | `vit.py` | `baselines/ViT/ViT_LRP.py` | Relative imports; equivalent native PyTorch reshapes replace `einops.rearrange`; remove model URL tables, pretrained factories and conversion helpers. All forward and relevance rules remain intact. |
11
+ | `weight_init.py` | `baselines/ViT/weight_init.py` | Byte-identical. |
12
+ | `layer_helpers.py` | `baselines/ViT/layer_helpers.py` | Byte-identical. |
13
+
14
+ The public wrapper does not implicitly download weights. It can copy a native
15
+ Hugging Face ViT classifier into this architecture with strict state-dict loading.
16
+ The wrapper evaluates one image per relevance propagation, replaces hard-coded
17
+ CUDA class seeds with device-aware tensors, leaves parameter gradient buffers
18
+ unchanged, and restores the caller's training flags.
19
+
20
+ The separate upstream `ViT_orig_LRP.py` / `layers_lrp.py` implementation is not
21
+ included. Do not describe the optional `full` or `last_layer` modes of this
22
+ Chefer-rule model as that separate conventional LRP baseline.
@@ -0,0 +1 @@
1
+ """Chefer et al. CVPR 2021 source; see README.md and LICENSE."""
@@ -0,0 +1,21 @@
1
+ """ Layer/Module Helpers
2
+ Hacked together by / Copyright 2020 Ross Wightman
3
+ """
4
+ from itertools import repeat
5
+ import collections.abc
6
+
7
+
8
+ # From PyTorch internals
9
+ def _ntuple(n):
10
+ def parse(x):
11
+ if isinstance(x, collections.abc.Iterable):
12
+ return x
13
+ return tuple(repeat(x, n))
14
+ return parse
15
+
16
+
17
+ to_1tuple = _ntuple(1)
18
+ to_2tuple = _ntuple(2)
19
+ to_3tuple = _ntuple(3)
20
+ to_4tuple = _ntuple(4)
21
+ to_ntuple = _ntuple
@@ -0,0 +1,280 @@
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ __all__ = ['forward_hook', 'Clone', 'Add', 'Cat', 'ReLU', 'GELU', 'Dropout', 'BatchNorm2d', 'Linear', 'MaxPool2d',
6
+ 'AdaptiveAvgPool2d', 'AvgPool2d', 'Conv2d', 'Sequential', 'safe_divide', 'einsum', 'Softmax', 'IndexSelect',
7
+ 'LayerNorm', 'AddEye']
8
+
9
+
10
+ def safe_divide(a, b):
11
+ den = b.clamp(min=1e-9) + b.clamp(max=1e-9)
12
+ den = den + den.eq(0).type(den.type()) * 1e-9
13
+ return a / den * b.ne(0).type(b.type())
14
+
15
+
16
+ def forward_hook(self, input, output):
17
+ if type(input[0]) in (list, tuple):
18
+ self.X = []
19
+ for i in input[0]:
20
+ x = i.detach()
21
+ x.requires_grad = True
22
+ self.X.append(x)
23
+ else:
24
+ self.X = input[0].detach()
25
+ self.X.requires_grad = True
26
+
27
+ self.Y = output
28
+
29
+
30
+ def backward_hook(self, grad_input, grad_output):
31
+ self.grad_input = grad_input
32
+ self.grad_output = grad_output
33
+
34
+
35
+ class RelProp(nn.Module):
36
+ def __init__(self):
37
+ super(RelProp, self).__init__()
38
+ # if not self.training:
39
+ self.register_forward_hook(forward_hook)
40
+
41
+ def gradprop(self, Z, X, S):
42
+ C = torch.autograd.grad(Z, X, S, retain_graph=True)
43
+ return C
44
+
45
+ def relprop(self, R, alpha):
46
+ return R
47
+
48
+ class RelPropSimple(RelProp):
49
+ def relprop(self, R, alpha):
50
+ Z = self.forward(self.X)
51
+ S = safe_divide(R, Z)
52
+ C = self.gradprop(Z, self.X, S)
53
+
54
+ if torch.is_tensor(self.X) == False:
55
+ outputs = []
56
+ outputs.append(self.X[0] * C[0])
57
+ outputs.append(self.X[1] * C[1])
58
+ else:
59
+ outputs = self.X * (C[0])
60
+ return outputs
61
+
62
+ class AddEye(RelPropSimple):
63
+ # input of shape B, C, seq_len, seq_len
64
+ def forward(self, input):
65
+ return input + torch.eye(input.shape[2]).expand_as(input).to(input.device)
66
+
67
+ class ReLU(nn.ReLU, RelProp):
68
+ pass
69
+
70
+ class GELU(nn.GELU, RelProp):
71
+ pass
72
+
73
+ class Softmax(nn.Softmax, RelProp):
74
+ pass
75
+
76
+ class LayerNorm(nn.LayerNorm, RelProp):
77
+ pass
78
+
79
+ class Dropout(nn.Dropout, RelProp):
80
+ pass
81
+
82
+
83
+ class MaxPool2d(nn.MaxPool2d, RelPropSimple):
84
+ pass
85
+
86
+ class LayerNorm(nn.LayerNorm, RelProp):
87
+ pass
88
+
89
+ class AdaptiveAvgPool2d(nn.AdaptiveAvgPool2d, RelPropSimple):
90
+ pass
91
+
92
+
93
+ class AvgPool2d(nn.AvgPool2d, RelPropSimple):
94
+ pass
95
+
96
+
97
+ class Add(RelPropSimple):
98
+ def forward(self, inputs):
99
+ return torch.add(*inputs)
100
+
101
+ def relprop(self, R, alpha):
102
+ Z = self.forward(self.X)
103
+ S = safe_divide(R, Z)
104
+ C = self.gradprop(Z, self.X, S)
105
+
106
+ a = self.X[0] * C[0]
107
+ b = self.X[1] * C[1]
108
+
109
+ a_sum = a.sum()
110
+ b_sum = b.sum()
111
+
112
+ a_fact = safe_divide(a_sum.abs(), a_sum.abs() + b_sum.abs()) * R.sum()
113
+ b_fact = safe_divide(b_sum.abs(), a_sum.abs() + b_sum.abs()) * R.sum()
114
+
115
+ a = a * safe_divide(a_fact, a.sum())
116
+ b = b * safe_divide(b_fact, b.sum())
117
+
118
+ outputs = [a, b]
119
+
120
+ return outputs
121
+
122
+ class einsum(RelPropSimple):
123
+ def __init__(self, equation):
124
+ super().__init__()
125
+ self.equation = equation
126
+ def forward(self, *operands):
127
+ return torch.einsum(self.equation, *operands)
128
+
129
+ class IndexSelect(RelProp):
130
+ def forward(self, inputs, dim, indices):
131
+ self.__setattr__('dim', dim)
132
+ self.__setattr__('indices', indices)
133
+
134
+ return torch.index_select(inputs, dim, indices)
135
+
136
+ def relprop(self, R, alpha):
137
+ Z = self.forward(self.X, self.dim, self.indices)
138
+ S = safe_divide(R, Z)
139
+ C = self.gradprop(Z, self.X, S)
140
+
141
+ if torch.is_tensor(self.X) == False:
142
+ outputs = []
143
+ outputs.append(self.X[0] * C[0])
144
+ outputs.append(self.X[1] * C[1])
145
+ else:
146
+ outputs = self.X * (C[0])
147
+ return outputs
148
+
149
+
150
+
151
+ class Clone(RelProp):
152
+ def forward(self, input, num):
153
+ self.__setattr__('num', num)
154
+ outputs = []
155
+ for _ in range(num):
156
+ outputs.append(input)
157
+
158
+ return outputs
159
+
160
+ def relprop(self, R, alpha):
161
+ Z = []
162
+ for _ in range(self.num):
163
+ Z.append(self.X)
164
+ S = [safe_divide(r, z) for r, z in zip(R, Z)]
165
+ C = self.gradprop(Z, self.X, S)[0]
166
+
167
+ R = self.X * C
168
+
169
+ return R
170
+
171
+ class Cat(RelProp):
172
+ def forward(self, inputs, dim):
173
+ self.__setattr__('dim', dim)
174
+ return torch.cat(inputs, dim)
175
+
176
+ def relprop(self, R, alpha):
177
+ Z = self.forward(self.X, self.dim)
178
+ S = safe_divide(R, Z)
179
+ C = self.gradprop(Z, self.X, S)
180
+
181
+ outputs = []
182
+ for x, c in zip(self.X, C):
183
+ outputs.append(x * c)
184
+
185
+ return outputs
186
+
187
+
188
+ class Sequential(nn.Sequential):
189
+ def relprop(self, R, alpha):
190
+ for m in reversed(self._modules.values()):
191
+ R = m.relprop(R, alpha)
192
+ return R
193
+
194
+ class BatchNorm2d(nn.BatchNorm2d, RelProp):
195
+ def relprop(self, R, alpha):
196
+ X = self.X
197
+ beta = 1 - alpha
198
+ weight = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3) / (
199
+ (self.running_var.unsqueeze(0).unsqueeze(2).unsqueeze(3).pow(2) + self.eps).pow(0.5))
200
+ Z = X * weight + 1e-9
201
+ S = R / Z
202
+ Ca = S * weight
203
+ R = self.X * (Ca)
204
+ return R
205
+
206
+
207
+ class Linear(nn.Linear, RelProp):
208
+ def relprop(self, R, alpha):
209
+ beta = alpha - 1
210
+ pw = torch.clamp(self.weight, min=0)
211
+ nw = torch.clamp(self.weight, max=0)
212
+ px = torch.clamp(self.X, min=0)
213
+ nx = torch.clamp(self.X, max=0)
214
+
215
+ def f(w1, w2, x1, x2):
216
+ Z1 = F.linear(x1, w1)
217
+ Z2 = F.linear(x2, w2)
218
+ S1 = safe_divide(R, Z1 + Z2)
219
+ S2 = safe_divide(R, Z1 + Z2)
220
+ C1 = x1 * torch.autograd.grad(Z1, x1, S1)[0]
221
+ C2 = x2 * torch.autograd.grad(Z2, x2, S2)[0]
222
+
223
+ return C1 + C2
224
+
225
+ activator_relevances = f(pw, nw, px, nx)
226
+ inhibitor_relevances = f(nw, pw, px, nx)
227
+
228
+ R = alpha * activator_relevances - beta * inhibitor_relevances
229
+
230
+ return R
231
+
232
+
233
+ class Conv2d(nn.Conv2d, RelProp):
234
+ def gradprop2(self, DY, weight):
235
+ Z = self.forward(self.X)
236
+
237
+ output_padding = self.X.size()[2] - (
238
+ (Z.size()[2] - 1) * self.stride[0] - 2 * self.padding[0] + self.kernel_size[0])
239
+
240
+ return F.conv_transpose2d(DY, weight, stride=self.stride, padding=self.padding, output_padding=output_padding)
241
+
242
+ def relprop(self, R, alpha):
243
+ if self.X.shape[1] == 3:
244
+ pw = torch.clamp(self.weight, min=0)
245
+ nw = torch.clamp(self.weight, max=0)
246
+ X = self.X
247
+ L = self.X * 0 + \
248
+ torch.min(torch.min(torch.min(self.X, dim=1, keepdim=True)[0], dim=2, keepdim=True)[0], dim=3,
249
+ keepdim=True)[0]
250
+ H = self.X * 0 + \
251
+ torch.max(torch.max(torch.max(self.X, dim=1, keepdim=True)[0], dim=2, keepdim=True)[0], dim=3,
252
+ keepdim=True)[0]
253
+ Za = torch.conv2d(X, self.weight, bias=None, stride=self.stride, padding=self.padding) - \
254
+ torch.conv2d(L, pw, bias=None, stride=self.stride, padding=self.padding) - \
255
+ torch.conv2d(H, nw, bias=None, stride=self.stride, padding=self.padding) + 1e-9
256
+
257
+ S = R / Za
258
+ C = X * self.gradprop2(S, self.weight) - L * self.gradprop2(S, pw) - H * self.gradprop2(S, nw)
259
+ R = C
260
+ else:
261
+ beta = alpha - 1
262
+ pw = torch.clamp(self.weight, min=0)
263
+ nw = torch.clamp(self.weight, max=0)
264
+ px = torch.clamp(self.X, min=0)
265
+ nx = torch.clamp(self.X, max=0)
266
+
267
+ def f(w1, w2, x1, x2):
268
+ Z1 = F.conv2d(x1, w1, bias=None, stride=self.stride, padding=self.padding)
269
+ Z2 = F.conv2d(x2, w2, bias=None, stride=self.stride, padding=self.padding)
270
+ S1 = safe_divide(R, Z1)
271
+ S2 = safe_divide(R, Z2)
272
+ C1 = x1 * self.gradprop(Z1, x1, S1)[0]
273
+ C2 = x2 * self.gradprop(Z2, x2, S2)[0]
274
+ return C1 + C2
275
+
276
+ activator_relevances = f(pw, nw, px, nx)
277
+ inhibitor_relevances = f(nw, pw, px, nx)
278
+
279
+ R = alpha * activator_relevances - beta * inhibitor_relevances
280
+ return R