logogram 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.
- logogram/__init__.py +6 -0
- logogram/__main__.py +5 -0
- logogram/analysis.py +419 -0
- logogram/atp.py +120 -0
- logogram/backends/__init__.py +5 -0
- logogram/backends/base.py +202 -0
- logogram/backends/hub.py +375 -0
- logogram/backends/saes.py +277 -0
- logogram/backends/transformer_lens.py +872 -0
- logogram/cli.py +496 -0
- logogram/compare.py +177 -0
- logogram/datasets.py +159 -0
- logogram/direct.py +193 -0
- logogram/engine.py +550 -0
- logogram/examples/ioi-gpt2/.gitignore +3 -0
- logogram/examples/ioi-gpt2/datasets/ioi.jsonl +32 -0
- logogram/examples/ioi-gpt2/experiments/ioi-head-patching/spec.json +42 -0
- logogram/examples/ioi-gpt2/project.json +6 -0
- logogram/exports.py +33 -0
- logogram/features.py +368 -0
- logogram/fileio.py +63 -0
- logogram/ioi.py +220 -0
- logogram/paths.py +204 -0
- logogram/project.py +444 -0
- logogram/prompts.py +204 -0
- logogram/research.py +84 -0
- logogram/results.py +240 -0
- logogram/runner.py +396 -0
- logogram/runs.py +98 -0
- logogram/sae.py +161 -0
- logogram/schema.py +302 -0
- logogram/server/__init__.py +1 -0
- logogram/server/app.py +1083 -0
- logogram/server/models.py +426 -0
- logogram/server/security.py +212 -0
- logogram/server/state.py +585 -0
- logogram/sites.py +249 -0
- logogram/spec.py +518 -0
- logogram/stats.py +171 -0
- logogram/steering.py +258 -0
- logogram/system.py +379 -0
- logogram/updates.py +194 -0
- logogram/verify.py +39 -0
- logogram/web_dist/assets/index-BvCU-2uy.js +54 -0
- logogram/web_dist/assets/index-DTr8_ucV.css +1 -0
- logogram/web_dist/assets/instrument-sans-latin-ext-standard-normal-C5E2Gvlv.woff2 +0 -0
- logogram/web_dist/assets/instrument-sans-latin-standard-normal-BVScPF0l.woff2 +0 -0
- logogram/web_dist/favicon.svg +1 -0
- logogram/web_dist/index.html +15 -0
- logogram-0.1.0.dist-info/METADATA +550 -0
- logogram-0.1.0.dist-info/RECORD +54 -0
- logogram-0.1.0.dist-info/WHEEL +4 -0
- logogram-0.1.0.dist-info/entry_points.txt +2 -0
- logogram-0.1.0.dist-info/licenses/LICENSE +21 -0
logogram/schema.py
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Schemas for what Logogram writes and sends: run files, listings and live events.
|
|
2
|
+
|
|
3
|
+
The experiment spec lives in :mod:`logogram.spec`; request bodies are defined next to their
|
|
4
|
+
endpoints. Everything here is validated when it is produced, so files on disk and messages to
|
|
5
|
+
the web app always have these shapes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Literal
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, ConfigDict
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _Model(BaseModel):
|
|
16
|
+
model_config = ConfigDict(extra="forbid")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# -- per-site statistics -----------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Stat(_Model):
|
|
23
|
+
mean: float | None
|
|
24
|
+
sd: float | None
|
|
25
|
+
lo: float | None
|
|
26
|
+
hi: float | None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SiteRef(_Model):
|
|
30
|
+
index: int
|
|
31
|
+
kind: Literal[
|
|
32
|
+
"resid_pre", "resid_mid", "resid_post", "attn_out", "mlp_out", "head", "sae_feature"
|
|
33
|
+
]
|
|
34
|
+
layer: int
|
|
35
|
+
head: int | None
|
|
36
|
+
feature: int | None = None
|
|
37
|
+
position: dict[str, Any]
|
|
38
|
+
position_key: str
|
|
39
|
+
row: int
|
|
40
|
+
col: int
|
|
41
|
+
label: str
|
|
42
|
+
# A variant of the site, such as a steering strength; None for one measurement per site.
|
|
43
|
+
variant: dict[str, Any] | None = None
|
|
44
|
+
variant_key: str | None = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SiteSummary(SiteRef):
|
|
48
|
+
n: int
|
|
49
|
+
effect: Stat
|
|
50
|
+
delta: Stat
|
|
51
|
+
patched_logit_diff: float | None
|
|
52
|
+
answer_prob: float | None
|
|
53
|
+
answer_prob_delta: float | None
|
|
54
|
+
sign_flips: int
|
|
55
|
+
opposite_sign: int
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LayoutAxis(BaseModel):
|
|
59
|
+
model_config = ConfigDict(extra="allow")
|
|
60
|
+
|
|
61
|
+
key: str
|
|
62
|
+
label: str
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class Layout(_Model):
|
|
66
|
+
kind: Literal["heads", "layer_position", "layer_components", "sites", "steering"]
|
|
67
|
+
site: str | None = None
|
|
68
|
+
row_title: str
|
|
69
|
+
col_title: str
|
|
70
|
+
rows: list[LayoutAxis]
|
|
71
|
+
cols: list[LayoutAxis]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# -- summary.json ------------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class GroupStats(_Model):
|
|
78
|
+
mean: float | None
|
|
79
|
+
sd: float | None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class PromptSetStats(_Model):
|
|
83
|
+
logit_diff: GroupStats
|
|
84
|
+
answer_prob: GroupStats
|
|
85
|
+
prefers_answer: int
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class BaselineSummary(_Model):
|
|
89
|
+
clean: PromptSetStats
|
|
90
|
+
corrupt: PromptSetStats
|
|
91
|
+
gap: GroupStats
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class MetricInfo(_Model):
|
|
95
|
+
kind: str
|
|
96
|
+
normalization: Literal["dataset_gap", "prompt_gap"]
|
|
97
|
+
denominator: float | None
|
|
98
|
+
description: str
|
|
99
|
+
normalized_effect: str
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class StatisticsInfo(_Model):
|
|
103
|
+
bootstrap: int
|
|
104
|
+
ci: float
|
|
105
|
+
seed: int
|
|
106
|
+
method: str
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class ModelShape(_Model):
|
|
110
|
+
id: str
|
|
111
|
+
n_layers: int
|
|
112
|
+
n_heads: int
|
|
113
|
+
d_model: int | None = None
|
|
114
|
+
d_head: int | None = None
|
|
115
|
+
d_mlp: int | None = None
|
|
116
|
+
site_kinds: list[str] | None = None
|
|
117
|
+
block_structure: str | None = None
|
|
118
|
+
normalization: str | None = None
|
|
119
|
+
activation: str | None = None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class DirectSplit(_Model):
|
|
123
|
+
"""Direct logit attribution: the mean logit difference and the parts it splits into."""
|
|
124
|
+
|
|
125
|
+
prompts: Literal["clean", "corrupt"]
|
|
126
|
+
logit_diff: float | None
|
|
127
|
+
embeddings: float | None
|
|
128
|
+
attention: float | None
|
|
129
|
+
mlp: float | None
|
|
130
|
+
biases: float | None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class SteeringInfo(_Model):
|
|
134
|
+
"""Which prompts trained the steering directions and which measured them, and how long each
|
|
135
|
+
site's direction is (one per row of the layout)."""
|
|
136
|
+
|
|
137
|
+
train: list[int]
|
|
138
|
+
test: list[int]
|
|
139
|
+
norms: list[float]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class FeatureRun(_Model):
|
|
143
|
+
"""Runs on SAE features: the SAE, how well it fits these prompts, and for attribution
|
|
144
|
+
patching how much of the site's estimated effect its features account for."""
|
|
145
|
+
|
|
146
|
+
sae: dict[str, Any]
|
|
147
|
+
fit: dict[str, Any]
|
|
148
|
+
site_estimate: float | None = None
|
|
149
|
+
features_estimate: float | None = None
|
|
150
|
+
evaluated: int | None = None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class Summary(_Model):
|
|
154
|
+
logogram_summary: Literal[1] = 1
|
|
155
|
+
run_id: str
|
|
156
|
+
name: str
|
|
157
|
+
description: str
|
|
158
|
+
model: ModelShape | None
|
|
159
|
+
n_prompts: int
|
|
160
|
+
n_sites: int
|
|
161
|
+
layout: Layout
|
|
162
|
+
receiver: Literal["clean", "corrupt"]
|
|
163
|
+
reference: Literal["clean", "corrupt"]
|
|
164
|
+
# What each per-prompt value is: a patched run, an estimate of one, or a term of a split.
|
|
165
|
+
measure: Literal["intervention", "estimate", "attribution"] = "intervention"
|
|
166
|
+
metric: MetricInfo
|
|
167
|
+
statistics: StatisticsInfo
|
|
168
|
+
baseline: BaselineSummary
|
|
169
|
+
sites: list[SiteSummary]
|
|
170
|
+
per_prompt: dict[str, list[float | None]]
|
|
171
|
+
donors: list[list[int]] | None
|
|
172
|
+
warnings: list[str]
|
|
173
|
+
direct: DirectSplit | None = None
|
|
174
|
+
steering: SteeringInfo | None = None
|
|
175
|
+
features: FeatureRun | None = None
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# -- manifest.json -----------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ModelProvenance(_Model):
|
|
182
|
+
id: str
|
|
183
|
+
revision: str | None
|
|
184
|
+
architecture: str
|
|
185
|
+
process_weights: bool
|
|
186
|
+
backend: str
|
|
187
|
+
backend_version: str
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class DeviceInfo(_Model):
|
|
191
|
+
type: str
|
|
192
|
+
name: str
|
|
193
|
+
cuda: str | None
|
|
194
|
+
threads: int
|
|
195
|
+
deterministic_algorithms: bool
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class DatasetProvenance(_Model):
|
|
199
|
+
path: str
|
|
200
|
+
sha256: str | None
|
|
201
|
+
n: int
|
|
202
|
+
source_path: str | None = None
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class DerivedFrom(_Model):
|
|
206
|
+
run: str
|
|
207
|
+
# robustness: one methodological choice changed; rerun: the same spec again; verification:
|
|
208
|
+
# the strongest estimated sites of an attribution patching run, patched for real.
|
|
209
|
+
kind: Literal["robustness", "rerun", "verification"]
|
|
210
|
+
change: str | None = None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class Manifest(_Model):
|
|
214
|
+
logogram_manifest: Literal[1] = 1
|
|
215
|
+
run_id: str
|
|
216
|
+
status: Literal["running", "finished", "failed", "cancelled"]
|
|
217
|
+
started_at: str
|
|
218
|
+
finished_at: str | None = None
|
|
219
|
+
wall_time_s: float | None = None
|
|
220
|
+
error: str | None = None
|
|
221
|
+
versions: dict[str, str | None]
|
|
222
|
+
derived_from: DerivedFrom | None = None
|
|
223
|
+
model: ModelProvenance | None = None
|
|
224
|
+
device: DeviceInfo | None = None
|
|
225
|
+
dtype: str | None = None
|
|
226
|
+
dataset: DatasetProvenance | None = None
|
|
227
|
+
sae: dict[str, Any] | None = None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# -- live events (WebSocket) -------------------------------------------------------------------
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class RunStarted(_Model):
|
|
234
|
+
run_id: str
|
|
235
|
+
n_prompts: int
|
|
236
|
+
model: ModelShape
|
|
237
|
+
layout: Layout
|
|
238
|
+
sites: list[SiteRef]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class RunLayer(_Model):
|
|
242
|
+
run_id: str
|
|
243
|
+
layer: int
|
|
244
|
+
sites: list[SiteSummary]
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class RunProgress(_Model):
|
|
248
|
+
run_id: str
|
|
249
|
+
done: int
|
|
250
|
+
total: int
|
|
251
|
+
layer: int
|
|
252
|
+
memory: int | None
|
|
253
|
+
elapsed_s: float
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class RunEnded(_Model):
|
|
257
|
+
run_id: str
|
|
258
|
+
error: str | None = None
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
EVENT_SCHEMAS: dict[str, type[BaseModel]] = {
|
|
262
|
+
"run.started": RunStarted,
|
|
263
|
+
"run.layer": RunLayer,
|
|
264
|
+
"run.progress": RunProgress,
|
|
265
|
+
"run.finished": RunEnded,
|
|
266
|
+
"run.failed": RunEnded,
|
|
267
|
+
"run.cancelled": RunEnded,
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def validate_event(kind: str, data: dict[str, Any]) -> dict[str, Any]:
|
|
272
|
+
"""Check a run event against its schema before it is sent."""
|
|
273
|
+
schema = EVENT_SCHEMAS.get(kind)
|
|
274
|
+
if schema is None:
|
|
275
|
+
return data
|
|
276
|
+
return schema.model_validate(data).model_dump(mode="json")
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
# -- history -----------------------------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class RunListing(_Model):
|
|
283
|
+
id: str
|
|
284
|
+
name: str
|
|
285
|
+
description: str
|
|
286
|
+
status: Literal["finished", "failed", "cancelled", "draft", "running"]
|
|
287
|
+
created: str | None
|
|
288
|
+
finished: str | None
|
|
289
|
+
wall_time_s: float | None
|
|
290
|
+
n_prompts: int | None
|
|
291
|
+
layout_kind: str | None
|
|
292
|
+
model_id: str
|
|
293
|
+
dataset: str
|
|
294
|
+
experiment: dict[str, Any]
|
|
295
|
+
scope: dict[str, Any]
|
|
296
|
+
derived_from: DerivedFrom | None
|
|
297
|
+
error: str | None
|
|
298
|
+
# Per layer, the largest normalized effect (signed): what writes the run's logogram in the app.
|
|
299
|
+
profile: list[float] | None = None
|
|
300
|
+
|
|
301
|
+
def to_dict(self) -> dict[str, Any]:
|
|
302
|
+
return self.model_dump(mode="json")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""The local web server."""
|