open-interpretability 0.0.20__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.
- open_interpretability-0.0.20.dist-info/METADATA +157 -0
- open_interpretability-0.0.20.dist-info/RECORD +256 -0
- open_interpretability-0.0.20.dist-info/WHEEL +4 -0
- open_interpretability-0.0.20.dist-info/entry_points.txt +2 -0
- open_interpretability-0.0.20.dist-info/licenses/LICENSE +21 -0
- openinterp/__init__.py +6 -0
- openinterp/agents/__init__.py +25 -0
- openinterp/agents/base.py +229 -0
- openinterp/agents/judge.py +149 -0
- openinterp/agents/proposer.py +471 -0
- openinterp/agents/proposer_profiles.py +79 -0
- openinterp/agents/review_measurements.py +173 -0
- openinterp/agents/reviewer.py +498 -0
- openinterp/agreement.py +63 -0
- openinterp/audit_options.py +79 -0
- openinterp/baseline.py +254 -0
- openinterp/benchmark.py +450 -0
- openinterp/blends.py +239 -0
- openinterp/builder/__init__.py +6 -0
- openinterp/builder/agents.py +260 -0
- openinterp/builder/aligned.py +41 -0
- openinterp/builder/charts.py +411 -0
- openinterp/builder/circuit_pages.py +37 -0
- openinterp/builder/circuits.py +264 -0
- openinterp/builder/compiler.py +495 -0
- openinterp/builder/corpora.py +98 -0
- openinterp/builder/coverage.py +46 -0
- openinterp/builder/dashboard.py +255 -0
- openinterp/builder/disk_memo.py +65 -0
- openinterp/builder/experiment.py +105 -0
- openinterp/builder/heat.py +121 -0
- openinterp/builder/hrefs.py +71 -0
- openinterp/builder/learned_baseline.py +204 -0
- openinterp/builder/model_facts.py +138 -0
- openinterp/builder/neuronpedia_export.py +107 -0
- openinterp/builder/parallel.py +100 -0
- openinterp/builder/parquet_export.py +458 -0
- openinterp/builder/pieces.py +127 -0
- openinterp/builder/pii.py +211 -0
- openinterp/builder/registry_stats.py +144 -0
- openinterp/builder/research.py +109 -0
- openinterp/builder/sections.py +28 -0
- openinterp/builder/significance.py +103 -0
- openinterp/builder/sister_graph.py +180 -0
- openinterp/builder/standing.py +185 -0
- openinterp/builder/statuses.py +34 -0
- openinterp/builder/stopped.py +91 -0
- openinterp/builder/stops.py +30 -0
- openinterp/builder/superpositions.py +102 -0
- openinterp/builder/templates/_agent_role_cells.html +9 -0
- openinterp/builder/templates/_causal_chart.html +67 -0
- openinterp/builder/templates/_circuit.html +8 -0
- openinterp/builder/templates/_dashboard.html +133 -0
- openinterp/builder/templates/_experiment.html +500 -0
- openinterp/builder/templates/_macros.html +82 -0
- openinterp/builder/templates/_patchscope.html +33 -0
- openinterp/builder/templates/_prior_art.html +24 -0
- openinterp/builder/templates/_specificity.html +21 -0
- openinterp/builder/templates/_steering.html +34 -0
- openinterp/builder/templates/_superposition.html +62 -0
- openinterp/builder/templates/_vocab_chart.html +88 -0
- openinterp/builder/templates/_wiring.html +44 -0
- openinterp/builder/templates/about.html +95 -0
- openinterp/builder/templates/agent.html +69 -0
- openinterp/builder/templates/agents.html +80 -0
- openinterp/builder/templates/base.html +103 -0
- openinterp/builder/templates/circuit.html +64 -0
- openinterp/builder/templates/circuits.html +46 -0
- openinterp/builder/templates/experiment.html +21 -0
- openinterp/builder/templates/hub.html +16 -0
- openinterp/builder/templates/index.html +387 -0
- openinterp/builder/templates/layer.html +69 -0
- openinterp/builder/templates/learned-baseline.html +44 -0
- openinterp/builder/templates/model.html +151 -0
- openinterp/builder/templates/models.html +47 -0
- openinterp/builder/templates/neuron.html +234 -0
- openinterp/builder/templates/paper.html +39 -0
- openinterp/builder/templates/redirect.html +1 -0
- openinterp/builder/templates/research.html +31 -0
- openinterp/builder/templates/user.html +54 -0
- openinterp/builder/templates/users.html +39 -0
- openinterp/builder/templates/wiki/experiment.md +271 -0
- openinterp/builder/templates/wiki/index.md +32 -0
- openinterp/builder/templates/wiki/neuron.md +30 -0
- openinterp/builder/templates/wiki/stop.md +36 -0
- openinterp/builder/tree.py +470 -0
- openinterp/builder/users.py +142 -0
- openinterp/builder/wiki.py +427 -0
- openinterp/checks.py +429 -0
- openinterp/cli.py +494 -0
- openinterp/cli_baseline.py +332 -0
- openinterp/cli_benchmark.py +300 -0
- openinterp/cli_build.py +128 -0
- openinterp/cli_check.py +51 -0
- openinterp/cli_concepts.py +76 -0
- openinterp/cli_corpus.py +252 -0
- openinterp/cli_costs.py +257 -0
- openinterp/cli_coverage.py +76 -0
- openinterp/cli_crossref.py +86 -0
- openinterp/cli_errata.py +142 -0
- openinterp/cli_evidence.py +495 -0
- openinterp/cli_evidence_store.py +93 -0
- openinterp/cli_explain.py +101 -0
- openinterp/cli_loop.py +125 -0
- openinterp/cli_memory.py +28 -0
- openinterp/cli_neuronpedia.py +175 -0
- openinterp/cli_pause.py +45 -0
- openinterp/cli_pole_effects.py +133 -0
- openinterp/cli_probing.py +119 -0
- openinterp/cli_registry.py +348 -0
- openinterp/cli_reproduce.py +446 -0
- openinterp/cli_review.py +302 -0
- openinterp/cli_scan.py +223 -0
- openinterp/cli_score.py +446 -0
- openinterp/cli_sisters.py +86 -0
- openinterp/cli_submission.py +217 -0
- openinterp/cli_superpositions.py +118 -0
- openinterp/cli_wiring.py +54 -0
- openinterp/codeid.py +73 -0
- openinterp/concepts.py +400 -0
- openinterp/core/__init__.py +59 -0
- openinterp/core/agent_names.py +76 -0
- openinterp/core/attribution.py +101 -0
- openinterp/core/cache_dirs.py +15 -0
- openinterp/core/causal.py +82 -0
- openinterp/core/confounds.py +103 -0
- openinterp/core/contributors.py +26 -0
- openinterp/core/corpora.py +126 -0
- openinterp/core/costs.py +430 -0
- openinterp/core/draws.py +109 -0
- openinterp/core/errata.py +244 -0
- openinterp/core/evidence.py +160 -0
- openinterp/core/examples.py +93 -0
- openinterp/core/exceptions.py +29 -0
- openinterp/core/explanation.py +130 -0
- openinterp/core/fence.py +42 -0
- openinterp/core/heavy_lock.py +114 -0
- openinterp/core/identifiers.py +198 -0
- openinterp/core/isolation.py +149 -0
- openinterp/core/ledger.py +130 -0
- openinterp/core/licenses.py +28 -0
- openinterp/core/manifold.py +117 -0
- openinterp/core/partners.py +32 -0
- openinterp/core/patchscope.py +59 -0
- openinterp/core/paths.py +40 -0
- openinterp/core/pause.py +96 -0
- openinterp/core/pricing.py +178 -0
- openinterp/core/prior_art.py +44 -0
- openinterp/core/probing.py +146 -0
- openinterp/core/profiles.py +221 -0
- openinterp/core/project.py +28 -0
- openinterp/core/run_environment.py +38 -0
- openinterp/core/schemas.py +484 -0
- openinterp/core/specificity.py +49 -0
- openinterp/core/stats.py +172 -0
- openinterp/core/steering.py +49 -0
- openinterp/core/strict.py +19 -0
- openinterp/core/takedowns.py +136 -0
- openinterp/core/transcripts.py +130 -0
- openinterp/core/wiring.py +80 -0
- openinterp/corpus.py +476 -0
- openinterp/corpus_cache.py +145 -0
- openinterp/corpus_layouts.py +108 -0
- openinterp/corpus_presets.py +168 -0
- openinterp/corpus_rebuild.py +93 -0
- openinterp/coverage.py +155 -0
- openinterp/crossref.py +442 -0
- openinterp/data/__init__.py +9 -0
- openinterp/data/offensive_words.txt +58 -0
- openinterp/data/public_suffix_list.dat +15771 -0
- openinterp/data/sample_corpus.txt +40 -0
- openinterp/draw_steps.py +359 -0
- openinterp/errata_checks.py +129 -0
- openinterp/evidence.py +462 -0
- openinterp/evidence_branch.py +119 -0
- openinterp/evidence_lenses.py +75 -0
- openinterp/experiment_loop.py +357 -0
- openinterp/explain.py +252 -0
- openinterp/half_precision.py +79 -0
- openinterp/harness/__init__.py +37 -0
- openinterp/harness/ane/__init__.py +9 -0
- openinterp/harness/ane/backend.py +324 -0
- openinterp/harness/ane/cache.py +276 -0
- openinterp/harness/ane/chunks.py +163 -0
- openinterp/harness/ane/convert.py +116 -0
- openinterp/harness/ane/forward.py +258 -0
- openinterp/harness/ane/qualified.py +40 -0
- openinterp/harness/annotations.py +329 -0
- openinterp/harness/attribution.py +96 -0
- openinterp/harness/causal.py +264 -0
- openinterp/harness/confounds.py +184 -0
- openinterp/harness/covariance.py +301 -0
- openinterp/harness/crossref.py +195 -0
- openinterp/harness/cuda_devices.py +88 -0
- openinterp/harness/dead.py +124 -0
- openinterp/harness/devices.py +401 -0
- openinterp/harness/dictionaries.py +496 -0
- openinterp/harness/dreaming.py +116 -0
- openinterp/harness/environment.py +64 -0
- openinterp/harness/explanation_scores.py +371 -0
- openinterp/harness/features.py +276 -0
- openinterp/harness/first_position.py +137 -0
- openinterp/harness/heads.py +226 -0
- openinterp/harness/hooks.py +499 -0
- openinterp/harness/input_attribution.py +367 -0
- openinterp/harness/jlens.py +183 -0
- openinterp/harness/layer_cache.py +301 -0
- openinterp/harness/layer_major.py +274 -0
- openinterp/harness/lookahead.py +93 -0
- openinterp/harness/manifold.py +200 -0
- openinterp/harness/memory.py +471 -0
- openinterp/harness/moe.py +134 -0
- openinterp/harness/patcher.py +322 -0
- openinterp/harness/patchscope.py +177 -0
- openinterp/harness/probing.py +383 -0
- openinterp/harness/scan.py +462 -0
- openinterp/harness/scan_backend.py +201 -0
- openinterp/harness/sister_passes.py +463 -0
- openinterp/harness/sisters.py +363 -0
- openinterp/harness/sites.py +101 -0
- openinterp/harness/specificity.py +107 -0
- openinterp/harness/steering.py +159 -0
- openinterp/harness/superpositions.py +116 -0
- openinterp/harness/units.py +203 -0
- openinterp/harness/wiring.py +432 -0
- openinterp/harness/wiring_activations.py +285 -0
- openinterp/langid.py +73 -0
- openinterp/names.py +129 -0
- openinterp/neuronpedia_baseline.py +88 -0
- openinterp/neuronpedia_review.py +148 -0
- openinterp/planner.py +466 -0
- openinterp/planner_effects.py +89 -0
- openinterp/planner_heads.py +92 -0
- openinterp/planner_models.py +174 -0
- openinterp/planner_sisters.py +122 -0
- openinterp/planner_states.py +57 -0
- openinterp/planner_superpositions.py +114 -0
- openinterp/pole_effects.py +102 -0
- openinterp/prior_art.py +143 -0
- openinterp/reproduce.py +450 -0
- openinterp/revision.py +45 -0
- openinterp/runner_cache.py +35 -0
- openinterp/score_controls.py +169 -0
- openinterp/sensitive.py +243 -0
- openinterp/show.py +236 -0
- openinterp/signing.py +209 -0
- openinterp/sisters.py +476 -0
- openinterp/superposition_finders.py +225 -0
- openinterp/sync/__init__.py +5 -0
- openinterp/sync/r2.py +280 -0
- openinterp/syntax.py +399 -0
- openinterp/takedown_checks.py +76 -0
- openinterp/toxicity.py +158 -0
- openinterp/verdict_regression.py +79 -0
- openinterp/wiring_backfill.py +170 -0
- openinterp/wordnet.py +362 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Each MLP pole's effect on the loss, estimated by attribution patching (issue #3486).
|
|
2
|
+
|
|
3
|
+
Mean-ablating one pole replaces its part of the activation with that part's mean over the
|
|
4
|
+
fit windows. The part is the positive part or the negative part. This is the ablation that
|
|
5
|
+
``openinterp/coverage.py`` applies to every pole at once. Measuring it pole by pole costs
|
|
6
|
+
one forward pass per pole: 73,728 for GPT-2 small. To first order, the change in mean
|
|
7
|
+
loss is the sum over tokens of ``dL/dh × (mean − part)``. One backward pass per batch
|
|
8
|
+
gives it for every pole of every layer. :func:`exact_effect` measures single poles, to
|
|
9
|
+
check the estimate.
|
|
10
|
+
|
|
11
|
+
The planner draws some explore units in proportion to this effect (``planner_effects``).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from collections.abc import Sequence
|
|
17
|
+
|
|
18
|
+
import torch
|
|
19
|
+
|
|
20
|
+
from openinterp.coverage import mean_loss, pole_means
|
|
21
|
+
from openinterp.harness.attribution import _corrupted_grads
|
|
22
|
+
from openinterp.harness.hooks import NeuronHookRunner
|
|
23
|
+
|
|
24
|
+
POLES = ("positive", "negative")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _loss_sum(ids: torch.Tensor):
|
|
28
|
+
"""A metric for ``_corrupted_grads``: the summed next-token cross-entropy on ``ids``."""
|
|
29
|
+
|
|
30
|
+
def metric(logits: torch.Tensor) -> torch.Tensor:
|
|
31
|
+
target = ids[:, 1:].to(logits.device).flatten()
|
|
32
|
+
return torch.nn.functional.cross_entropy(
|
|
33
|
+
logits[:, :-1].flatten(0, 1).float(), target, reduction="sum"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return metric
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def estimate(
|
|
40
|
+
runner: NeuronHookRunner,
|
|
41
|
+
fit: torch.Tensor,
|
|
42
|
+
test: torch.Tensor,
|
|
43
|
+
layers: Sequence[int],
|
|
44
|
+
batch: int,
|
|
45
|
+
) -> dict[tuple[int, str], torch.Tensor]:
|
|
46
|
+
"""``{(layer, pole): tensor[width]}``: each pole's estimated rise in mean loss on ``test``."""
|
|
47
|
+
means = {layer: pole_means(runner, fit, layer, batch) for layer in layers}
|
|
48
|
+
totals: dict[tuple[int, str], torch.Tensor] = {}
|
|
49
|
+
for chunk in test.split(batch):
|
|
50
|
+
acts, grads = _corrupted_grads(runner, chunk, list(layers), _loss_sum(chunk))
|
|
51
|
+
for layer, act, grad in zip(layers, acts, grads, strict=True):
|
|
52
|
+
act, grad = act.detach().float(), grad.float()
|
|
53
|
+
m_pos, m_neg = (m.to(act.device) for m in means[layer])
|
|
54
|
+
parts = {"positive": (m_pos - act.clamp(min=0)), "negative": (m_neg - act.clamp(max=0))}
|
|
55
|
+
for pole, diff in parts.items():
|
|
56
|
+
value = (diff * grad).sum(dim=(0, 1)).cpu()
|
|
57
|
+
key = (layer, pole)
|
|
58
|
+
totals[key] = value if key not in totals else totals[key] + value
|
|
59
|
+
tokens = test[:, 1:].numel()
|
|
60
|
+
return {key: value / tokens for key, value in totals.items()}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def single_pole(means, idx: int, pole: str):
|
|
64
|
+
"""An intervention that mean-ablates only pole ``pole`` of neuron ``idx``."""
|
|
65
|
+
m_pos, m_neg = means
|
|
66
|
+
|
|
67
|
+
def intervene(act: torch.Tensor) -> torch.Tensor:
|
|
68
|
+
out = act.clone()
|
|
69
|
+
column = act[..., idx]
|
|
70
|
+
if pole == "positive":
|
|
71
|
+
out[..., idx] = m_pos[idx].to(act.device, act.dtype) + column.clamp(max=0)
|
|
72
|
+
else:
|
|
73
|
+
out[..., idx] = column.clamp(min=0) + m_neg[idx].to(act.device, act.dtype)
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
return intervene
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def exact_effect(
|
|
80
|
+
runner: NeuronHookRunner,
|
|
81
|
+
fit: torch.Tensor,
|
|
82
|
+
test: torch.Tensor,
|
|
83
|
+
layer: int,
|
|
84
|
+
idx: int,
|
|
85
|
+
pole: str,
|
|
86
|
+
clean: float,
|
|
87
|
+
batch: int,
|
|
88
|
+
) -> float:
|
|
89
|
+
"""The measured rise in mean loss on ``test`` when one pole is mean-ablated."""
|
|
90
|
+
means = pole_means(runner, fit, layer, batch)
|
|
91
|
+
return mean_loss(runner, test, batch, {layer: single_pole(means, idx, pole)}) - clean
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def top_poles(effects: dict[tuple[int, str], torch.Tensor], k: int) -> list[dict]:
|
|
95
|
+
"""The ``k`` poles with the largest estimated effect, largest first."""
|
|
96
|
+
rows = [
|
|
97
|
+
(float(v), layer, idx, pole)
|
|
98
|
+
for (layer, pole), values in effects.items()
|
|
99
|
+
for idx, v in enumerate(values.tolist())
|
|
100
|
+
]
|
|
101
|
+
rows.sort(reverse=True)
|
|
102
|
+
return [{"layer": la, "neuron": i, "pole": p, "effect": v} for v, la, i, p in rows[:k]]
|
openinterp/prior_art.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Find prior art for a unit after the proposer answers (`open-interpretability audit`).
|
|
2
|
+
|
|
3
|
+
A dictionary latent that Neuronpedia hosts is looked up directly. A neuron pole is
|
|
4
|
+
aligned with each dictionary preset that Neuronpedia hosts at its layer
|
|
5
|
+
(:func:`openinterp.harness.crossref.align_layer`). Rows from ``open-interpretability crossref`` are
|
|
6
|
+
used where they exist. The latents above chance on each side are then looked up, the best
|
|
7
|
+
``TOP`` first.
|
|
8
|
+
|
|
9
|
+
Lookups go through the cached, polite fetch of :mod:`openinterp.crossref`. A failed
|
|
10
|
+
lookup or alignment is left out, so prior art never stops an audit.
|
|
11
|
+
``$OPENINTERP_PRIOR_ART=0`` turns the readout off.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
|
|
19
|
+
from openinterp.core.fence import fence
|
|
20
|
+
from openinterp.core.prior_art import PriorArt
|
|
21
|
+
|
|
22
|
+
TOP = 3 # latents per side of a pole
|
|
23
|
+
ENV = "OPENINTERP_PRIOR_ART"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def enabled() -> bool:
|
|
27
|
+
"""False when ``$OPENINTERP_PRIOR_ART`` turns the readout off."""
|
|
28
|
+
return os.environ.get(ENV, "1").lower() not in ("", "0", "off", "false")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def find_prior_art(submission, runner, *, rows: dict | None = None, fetch: Callable | None = None):
|
|
32
|
+
"""Return the unit's prior art; ``None`` for a unit kind with none, or when turned off.
|
|
33
|
+
|
|
34
|
+
``rows`` are crossref rows by slug (:func:`openinterp.crossref.load_rows`). ``fetch``
|
|
35
|
+
returns a latent's explanations (default :func:`openinterp.crossref.latent_explanations`).
|
|
36
|
+
"""
|
|
37
|
+
from openinterp.crossref import latent_explanations
|
|
38
|
+
|
|
39
|
+
if not enabled():
|
|
40
|
+
return None
|
|
41
|
+
fetch = fetch or latent_explanations
|
|
42
|
+
ident = submission.identifier
|
|
43
|
+
if ident.kind == "dictionary_feature":
|
|
44
|
+
entry = _entry(fetch, ident.dictionary, ident.layer, ident.feature_idx, "self", None)
|
|
45
|
+
return [entry] if entry else []
|
|
46
|
+
if ident.kind != "mlp_neuron_pole":
|
|
47
|
+
return None
|
|
48
|
+
found = []
|
|
49
|
+
for name, side, matches in _aligned(ident, runner, rows):
|
|
50
|
+
for feature_idx, cosine in matches:
|
|
51
|
+
entry = _entry(fetch, name, ident.layer, feature_idx, side, cosine)
|
|
52
|
+
if entry:
|
|
53
|
+
found.append(entry)
|
|
54
|
+
return found
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _entry(fetch, dictionary: str, layer: int, feature_idx: int, relation: str, cosine):
|
|
58
|
+
"""The latent's first machine-written explanation, else its first; ``None`` if none."""
|
|
59
|
+
from openinterp.crossref import latent_url, machine_explanation
|
|
60
|
+
|
|
61
|
+
url = latent_url(dictionary, layer, feature_idx)
|
|
62
|
+
if url is None:
|
|
63
|
+
return None
|
|
64
|
+
explanations = fetch(dictionary, layer, feature_idx) or []
|
|
65
|
+
best = machine_explanation(explanations) or next(iter(explanations), None)
|
|
66
|
+
if best is None:
|
|
67
|
+
return None
|
|
68
|
+
return PriorArt(
|
|
69
|
+
dictionary=dictionary,
|
|
70
|
+
feature_idx=feature_idx,
|
|
71
|
+
relation=relation,
|
|
72
|
+
cosine=cosine,
|
|
73
|
+
description=best.description,
|
|
74
|
+
explainer=best.explainer,
|
|
75
|
+
url=url,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _aligned(ident, runner, rows: dict | None):
|
|
80
|
+
"""Yield ``(dictionary, side, [(feature_idx, cosine)])`` for each hosted dictionary."""
|
|
81
|
+
from openinterp.crossref import dictionaries_for, load_rows
|
|
82
|
+
from openinterp.harness.dictionaries import DICTIONARIES
|
|
83
|
+
|
|
84
|
+
rows = load_rows() if rows is None else rows
|
|
85
|
+
known = {r.dictionary: r for r in rows.get(ident.slug, [])}
|
|
86
|
+
for name in dictionaries_for(ident.model_name, ident.layer):
|
|
87
|
+
if not DICTIONARIES[name].neuronpedia_source(ident.layer):
|
|
88
|
+
continue
|
|
89
|
+
sides = _sides(known[name]) if name in known else _align(runner, name, ident)
|
|
90
|
+
for side, (matches, chance) in sides.items():
|
|
91
|
+
above = [m for m in matches if abs(m[1]) > chance]
|
|
92
|
+
yield name, side, sorted(above, key=lambda m: -abs(m[1]))[:TOP]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _sides(row) -> dict:
|
|
96
|
+
"""``{side: ([(feature_idx, cosine)], chance)}`` of a stored crossref row."""
|
|
97
|
+
out = {}
|
|
98
|
+
for side in ("writes", "reads"):
|
|
99
|
+
s = getattr(row, side)
|
|
100
|
+
if s is not None:
|
|
101
|
+
out[side] = ([(m.feature_idx, m.cosine) for m in s.matches], s.chance)
|
|
102
|
+
return out
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _align(runner, name: str, ident) -> dict:
|
|
106
|
+
"""Align the pole with dictionary ``name`` now; empty if that fails."""
|
|
107
|
+
from openinterp.core.exceptions import ArchitectureNotSupportedError
|
|
108
|
+
from openinterp.harness.crossref import align_layer
|
|
109
|
+
from openinterp.harness.dictionaries import dictionary_spec
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
found = align_layer(
|
|
113
|
+
runner, dictionary_spec(name), ident.layer, [(ident.neuron_idx, ident.pole)]
|
|
114
|
+
)
|
|
115
|
+
except (ArchitectureNotSupportedError, OSError, ValueError):
|
|
116
|
+
return {}
|
|
117
|
+
write, read = found[(ident.neuron_idx, ident.pole)]
|
|
118
|
+
out = {"writes": ([(m.feature_idx, m.cosine) for m in write.matches], write.chance)}
|
|
119
|
+
if read is not None:
|
|
120
|
+
out["reads"] = ([(m.feature_idx, m.cosine) for m in read.matches], read.chance)
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def format_for_reviewer(prior_art: list[PriorArt] | None) -> str:
|
|
125
|
+
"""The prior art as a block of the reviewer's prompt; empty if there is none."""
|
|
126
|
+
if not prior_art:
|
|
127
|
+
return ""
|
|
128
|
+
lines = []
|
|
129
|
+
for p in prior_art:
|
|
130
|
+
where = (
|
|
131
|
+
"this latent itself"
|
|
132
|
+
if p.relation == "self"
|
|
133
|
+
else f"{p.dictionary} latent {p.feature_idx}, which {p.relation} along this pole "
|
|
134
|
+
f"(cosine {p.cosine:+.2f})"
|
|
135
|
+
)
|
|
136
|
+
lines.append(f"- {where}: {p.description} [{p.source}, {p.explainer}]")
|
|
137
|
+
return (
|
|
138
|
+
"Prior art: published explanations of this unit or of latents aligned with it. They "
|
|
139
|
+
"are other people's claims, not measurements, and the proposer did not see them. "
|
|
140
|
+
"Where one disagrees with the hypothesis, write probes that tell them apart.\n"
|
|
141
|
+
+ fence("\n".join(lines))
|
|
142
|
+
+ "\n"
|
|
143
|
+
)
|