interp-engine 0.0.24__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.
- interp_engine-0.0.24.dist-info/METADATA +21 -0
- interp_engine-0.0.24.dist-info/RECORD +28 -0
- interp_engine-0.0.24.dist-info/WHEEL +4 -0
- interp_engine-0.0.24.dist-info/licenses/LICENSE +19 -0
- neuron_explainer/__init__.py +0 -0
- neuron_explainer/activations/__init__.py +0 -0
- neuron_explainer/activations/activation_records.py +130 -0
- neuron_explainer/activations/activations.py +311 -0
- neuron_explainer/activations/attention_utils.py +121 -0
- neuron_explainer/activations/token_connections.py +59 -0
- neuron_explainer/api_client.py +190 -0
- neuron_explainer/azure.py +5 -0
- neuron_explainer/explanations/__init__.py +0 -0
- neuron_explainer/explanations/calibrated_simulator.py +194 -0
- neuron_explainer/explanations/explainer.py +2585 -0
- neuron_explainer/explanations/explanations.py +230 -0
- neuron_explainer/explanations/few_shot_examples.py +3125 -0
- neuron_explainer/explanations/prompt_builder.py +118 -0
- neuron_explainer/explanations/puzzles.json +399 -0
- neuron_explainer/explanations/puzzles.py +50 -0
- neuron_explainer/explanations/scoring.py +155 -0
- neuron_explainer/explanations/simulator.py +1121 -0
- neuron_explainer/explanations/test_explainer.py +227 -0
- neuron_explainer/explanations/test_simulator.py +269 -0
- neuron_explainer/explanations/token_space_few_shot_examples.py +212 -0
- neuron_explainer/fast_dataclasses/__init__.py +3 -0
- neuron_explainer/fast_dataclasses/fast_dataclasses.py +85 -0
- neuron_explainer/fast_dataclasses/test_fast_dataclasses.py +83 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Utilities for dataclasses that are very fast to serialize and deserialize, with limited data
|
|
2
|
+
# validation. Fields must not be tuples, since they get serialized and then deserialized as lists.
|
|
3
|
+
#
|
|
4
|
+
# The unit tests for this library show how to use it.
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from dataclasses import dataclass, field, fields, is_dataclass
|
|
8
|
+
from functools import partial
|
|
9
|
+
from typing import Any, Union
|
|
10
|
+
|
|
11
|
+
import orjson
|
|
12
|
+
|
|
13
|
+
dataclasses_by_name = {}
|
|
14
|
+
dataclasses_by_fieldnames = {}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class FastDataclass:
|
|
19
|
+
dataclass_name: str = field(init=False)
|
|
20
|
+
|
|
21
|
+
def __post_init__(self) -> None:
|
|
22
|
+
self.dataclass_name = self.__class__.__name__
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def register_dataclass(cls): # type: ignore
|
|
26
|
+
assert is_dataclass(cls), "Only dataclasses can be registered."
|
|
27
|
+
dataclasses_by_name[cls.__name__] = cls
|
|
28
|
+
name_set = frozenset(f.name for f in fields(cls) if f.name != "dataclass_name")
|
|
29
|
+
dataclasses_by_fieldnames[name_set] = cls
|
|
30
|
+
return cls
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def dumps(obj: Any) -> bytes:
|
|
34
|
+
return orjson.dumps(obj, option=orjson.OPT_SERIALIZE_NUMPY)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _object_hook(d: Any, backwards_compatible: bool = True) -> Any:
|
|
38
|
+
# If d is a list, recurse.
|
|
39
|
+
if isinstance(d, list):
|
|
40
|
+
return [_object_hook(x, backwards_compatible=backwards_compatible) for x in d]
|
|
41
|
+
# If d is not a dict, return it as is.
|
|
42
|
+
if not isinstance(d, dict):
|
|
43
|
+
return d
|
|
44
|
+
cls = None
|
|
45
|
+
if "dataclass_name" in d:
|
|
46
|
+
if d["dataclass_name"] in dataclasses_by_name:
|
|
47
|
+
cls = dataclasses_by_name[d["dataclass_name"]]
|
|
48
|
+
else:
|
|
49
|
+
assert backwards_compatible, (
|
|
50
|
+
f"Dataclass {d['dataclass_name']} not found, set backwards_compatible=True if you "
|
|
51
|
+
f"are okay with that."
|
|
52
|
+
)
|
|
53
|
+
# Load objects created without dataclass_name set.
|
|
54
|
+
else:
|
|
55
|
+
# Try our best to find a dataclass if backwards_compatible is True.
|
|
56
|
+
if backwards_compatible:
|
|
57
|
+
d_fields = frozenset(d.keys())
|
|
58
|
+
if d_fields in dataclasses_by_fieldnames:
|
|
59
|
+
cls = dataclasses_by_fieldnames[d_fields]
|
|
60
|
+
elif len(d_fields) > 0:
|
|
61
|
+
# Check if the fields are a subset of a dataclass (if the dataclass had extra fields
|
|
62
|
+
# added since the data was created). Note that this will fail if fields were removed
|
|
63
|
+
# from the dataclass.
|
|
64
|
+
for key, possible_cls in dataclasses_by_fieldnames.items():
|
|
65
|
+
if d_fields.issubset(key):
|
|
66
|
+
cls = possible_cls
|
|
67
|
+
break
|
|
68
|
+
else:
|
|
69
|
+
print(f"Could not find dataclass for {d_fields} {cls}")
|
|
70
|
+
new_d = {
|
|
71
|
+
k: _object_hook(v, backwards_compatible=backwards_compatible)
|
|
72
|
+
for k, v in d.items()
|
|
73
|
+
if k != "dataclass_name"
|
|
74
|
+
}
|
|
75
|
+
if cls is not None:
|
|
76
|
+
return cls(**new_d)
|
|
77
|
+
else:
|
|
78
|
+
return new_d
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def loads(s: Union[str, bytes], backwards_compatible: bool = True) -> Any:
|
|
82
|
+
return json.loads(
|
|
83
|
+
s,
|
|
84
|
+
object_hook=partial(_object_hook, backwards_compatible=backwards_compatible),
|
|
85
|
+
)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from .fast_dataclasses import FastDataclass, dumps, loads, register_dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Inheritance is a bit tricky with our setup. dataclass_name must be set for instances of these
|
|
9
|
+
# classes to serialize and deserialize correctly, but if it's given a default value, then subclasses
|
|
10
|
+
# can't have any fields that don't have default values, because of how constructors are generated
|
|
11
|
+
# for dataclasses (fields with no default value can't follow those with default values). To work
|
|
12
|
+
# around this, we set dataclass_name in __post_init__ on the base class, which is called after the
|
|
13
|
+
# constructor. The implementation does the right thing for both the base class and the subclass.
|
|
14
|
+
@register_dataclass
|
|
15
|
+
@dataclass
|
|
16
|
+
class DataclassC(FastDataclass):
|
|
17
|
+
ints: list[int]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@register_dataclass
|
|
21
|
+
@dataclass
|
|
22
|
+
class DataclassC_ext(DataclassC):
|
|
23
|
+
s: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@register_dataclass
|
|
27
|
+
@dataclass
|
|
28
|
+
class DataclassB(FastDataclass):
|
|
29
|
+
str_to_c: dict[str, DataclassC]
|
|
30
|
+
cs: list[DataclassC]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@register_dataclass
|
|
34
|
+
@dataclass
|
|
35
|
+
class DataclassA(FastDataclass):
|
|
36
|
+
floats: list[float]
|
|
37
|
+
strings: list[str]
|
|
38
|
+
bs: list[DataclassB]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@register_dataclass
|
|
42
|
+
@dataclass
|
|
43
|
+
class DataclassD(FastDataclass):
|
|
44
|
+
s1: str
|
|
45
|
+
s2: str = "default"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_dataclasses() -> None:
|
|
49
|
+
a = DataclassA(
|
|
50
|
+
floats=[1.0, 2.0],
|
|
51
|
+
strings=["a", "b"],
|
|
52
|
+
bs=[
|
|
53
|
+
DataclassB(
|
|
54
|
+
str_to_c={"a": DataclassC(ints=[1, 2]), "b": DataclassC(ints=[3, 4])},
|
|
55
|
+
cs=[DataclassC(ints=[5, 6]), DataclassC_ext(ints=[7, 8], s="s")],
|
|
56
|
+
),
|
|
57
|
+
DataclassB(
|
|
58
|
+
str_to_c={"c": DataclassC_ext(ints=[9, 10], s="t"), "d": DataclassC(ints=[11, 12])},
|
|
59
|
+
cs=[DataclassC(ints=[13, 14]), DataclassC(ints=[15, 16])],
|
|
60
|
+
),
|
|
61
|
+
],
|
|
62
|
+
)
|
|
63
|
+
assert loads(dumps(a)) == a
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_c_and_c_ext() -> None:
|
|
67
|
+
c_ext = DataclassC_ext(ints=[3, 4], s="s")
|
|
68
|
+
assert loads(dumps(c_ext)) == c_ext
|
|
69
|
+
|
|
70
|
+
c = DataclassC(ints=[1, 2])
|
|
71
|
+
assert loads(dumps(c)) == c
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_bad_serialized_data() -> None:
|
|
75
|
+
assert type(loads(dumps(DataclassC(ints=[3, 4])))) == DataclassC
|
|
76
|
+
assert type(loads('{"ints": [3, 4]}', backwards_compatible=False)) == dict
|
|
77
|
+
assert type(loads('{"ints": [3, 4], "dataclass_name": "DataclassC"}')) == DataclassC
|
|
78
|
+
with pytest.raises(TypeError):
|
|
79
|
+
loads('{"ints": [3, 4], "bogus_extra_field": "foo", "dataclass_name": "DataclassC"}')
|
|
80
|
+
with pytest.raises(TypeError):
|
|
81
|
+
loads('{"ints_field_is_missing": [3, 4], "dataclass_name": "DataclassC"}')
|
|
82
|
+
assert type(loads('{"s1": "test"}', backwards_compatible=False)) == dict
|
|
83
|
+
assert type(loads('{"s1": "test"}', backwards_compatible=True)) == DataclassD
|