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,155 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Any, Callable, Coroutine, Sequence
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from neuron_explainer.activations.activations import ActivationRecord
|
|
9
|
+
from neuron_explainer.explanations.calibrated_simulator import (
|
|
10
|
+
CalibratedNeuronSimulator,
|
|
11
|
+
LinearCalibratedNeuronSimulator,
|
|
12
|
+
)
|
|
13
|
+
from neuron_explainer.explanations.explanations import (
|
|
14
|
+
ScoredSequenceSimulation,
|
|
15
|
+
ScoredSimulation,
|
|
16
|
+
SequenceSimulation,
|
|
17
|
+
)
|
|
18
|
+
from neuron_explainer.explanations.simulator import ExplanationNeuronSimulator, NeuronSimulator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def flatten_list(list_of_lists: Sequence[Sequence[Any]]) -> list[Any]:
|
|
22
|
+
return [item for sublist in list_of_lists for item in sublist]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def correlation_score(
|
|
26
|
+
real_activations: Sequence[float] | np.ndarray,
|
|
27
|
+
predicted_activations: Sequence[float] | np.ndarray,
|
|
28
|
+
) -> float:
|
|
29
|
+
return np.corrcoef(real_activations, predicted_activations)[0, 1]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def score_from_simulation(
|
|
33
|
+
real_activations: ActivationRecord,
|
|
34
|
+
simulation: SequenceSimulation,
|
|
35
|
+
score_function: Callable[[Sequence[float] | np.ndarray, Sequence[float] | np.ndarray], float],
|
|
36
|
+
) -> float:
|
|
37
|
+
return score_function(real_activations.activations, simulation.expected_activations)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def rsquared_score_from_sequences(
|
|
41
|
+
real_activations: Sequence[float] | np.ndarray,
|
|
42
|
+
predicted_activations: Sequence[float] | np.ndarray,
|
|
43
|
+
) -> float:
|
|
44
|
+
return float(
|
|
45
|
+
1
|
|
46
|
+
- np.mean(np.square(np.array(real_activations) - np.array(predicted_activations)))
|
|
47
|
+
/ np.mean(np.square(np.array(real_activations)))
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def absolute_dev_explained_score_from_sequences(
|
|
52
|
+
real_activations: Sequence[float] | np.ndarray,
|
|
53
|
+
predicted_activations: Sequence[float] | np.ndarray,
|
|
54
|
+
) -> float:
|
|
55
|
+
return float(
|
|
56
|
+
1
|
|
57
|
+
- np.mean(np.abs(np.array(real_activations) - np.array(predicted_activations)))
|
|
58
|
+
/ np.mean(np.abs(np.array(real_activations)))
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def make_explanation_simulator(
|
|
63
|
+
explanation: str,
|
|
64
|
+
calibration_activation_records: Sequence[ActivationRecord],
|
|
65
|
+
model_name: str,
|
|
66
|
+
calibrated_simulator_class: type[CalibratedNeuronSimulator] = LinearCalibratedNeuronSimulator,
|
|
67
|
+
) -> CalibratedNeuronSimulator:
|
|
68
|
+
"""
|
|
69
|
+
Make a simulator that uses an explanation to predict activations and calibrates it on the given
|
|
70
|
+
activation records.
|
|
71
|
+
"""
|
|
72
|
+
simulator = ExplanationNeuronSimulator(model_name, explanation)
|
|
73
|
+
calibrated_simulator = calibrated_simulator_class(simulator)
|
|
74
|
+
await calibrated_simulator.calibrate(calibration_activation_records)
|
|
75
|
+
return calibrated_simulator
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def _simulate_and_score_sequence(
|
|
79
|
+
simulator: NeuronSimulator, activations: ActivationRecord
|
|
80
|
+
) -> ScoredSequenceSimulation:
|
|
81
|
+
"""Score an explanation of a neuron by how well it predicts activations on a sentence."""
|
|
82
|
+
simulation = await simulator.simulate(activations.tokens)
|
|
83
|
+
logging.debug(simulation)
|
|
84
|
+
rsquared_score = score_from_simulation(activations, simulation, rsquared_score_from_sequences)
|
|
85
|
+
absolute_dev_explained_score = score_from_simulation(
|
|
86
|
+
activations, simulation, absolute_dev_explained_score_from_sequences
|
|
87
|
+
)
|
|
88
|
+
scored_sequence_simulation = ScoredSequenceSimulation(
|
|
89
|
+
simulation=simulation,
|
|
90
|
+
true_activations=activations.activations,
|
|
91
|
+
ev_correlation_score=score_from_simulation(activations, simulation, correlation_score),
|
|
92
|
+
rsquared_score=rsquared_score,
|
|
93
|
+
absolute_dev_explained_score=absolute_dev_explained_score,
|
|
94
|
+
)
|
|
95
|
+
return scored_sequence_simulation
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def aggregate_scored_sequence_simulations(
|
|
99
|
+
scored_sequence_simulations: list[ScoredSequenceSimulation],
|
|
100
|
+
) -> ScoredSimulation:
|
|
101
|
+
"""
|
|
102
|
+
Aggregate a list of scored sequence simulations. The logic for doing this is non-trivial for EV
|
|
103
|
+
scores, since we want to calculate the correlation over all activations from all sequences at
|
|
104
|
+
once rather than simply averaging per-sequence correlations.
|
|
105
|
+
"""
|
|
106
|
+
all_true_activations: list[float] = []
|
|
107
|
+
all_expected_values: list[float] = []
|
|
108
|
+
for scored_sequence_simulation in scored_sequence_simulations:
|
|
109
|
+
all_true_activations.extend(scored_sequence_simulation.true_activations or [])
|
|
110
|
+
all_expected_values.extend(scored_sequence_simulation.simulation.expected_activations)
|
|
111
|
+
ev_correlation_score = (
|
|
112
|
+
correlation_score(all_true_activations, all_expected_values)
|
|
113
|
+
if len(all_true_activations) > 0
|
|
114
|
+
else None
|
|
115
|
+
)
|
|
116
|
+
rsquared_score = rsquared_score_from_sequences(all_true_activations, all_expected_values)
|
|
117
|
+
absolute_dev_explained_score = absolute_dev_explained_score_from_sequences(
|
|
118
|
+
all_true_activations, all_expected_values
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return ScoredSimulation(
|
|
122
|
+
scored_sequence_simulations=scored_sequence_simulations,
|
|
123
|
+
ev_correlation_score=ev_correlation_score,
|
|
124
|
+
rsquared_score=rsquared_score,
|
|
125
|
+
absolute_dev_explained_score=absolute_dev_explained_score,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
async def simulate_and_score(
|
|
130
|
+
simulator: NeuronSimulator,
|
|
131
|
+
activation_records: Sequence[ActivationRecord],
|
|
132
|
+
) -> ScoredSimulation:
|
|
133
|
+
"""
|
|
134
|
+
Score an explanation of a neuron by how well it predicts activations on the given text
|
|
135
|
+
sequences.
|
|
136
|
+
"""
|
|
137
|
+
scored_sequence_simulations = await asyncio.gather(
|
|
138
|
+
*[
|
|
139
|
+
_simulate_and_score_sequence(
|
|
140
|
+
simulator,
|
|
141
|
+
activation_record,
|
|
142
|
+
)
|
|
143
|
+
for activation_record in activation_records
|
|
144
|
+
]
|
|
145
|
+
)
|
|
146
|
+
return aggregate_scored_sequence_simulations(scored_sequence_simulations)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
async def make_simulator_and_score(
|
|
150
|
+
make_simulator: Coroutine[None, None, NeuronSimulator],
|
|
151
|
+
activation_records: Sequence[ActivationRecord],
|
|
152
|
+
) -> ScoredSimulation:
|
|
153
|
+
"""Chain together creating the simulator and using it to score activation records."""
|
|
154
|
+
simulator = await make_simulator
|
|
155
|
+
return await simulate_and_score(simulator, activation_records)
|