representation-geometry 0.1.0__tar.gz

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 (24) hide show
  1. representation_geometry-0.1.0/LICENSE +21 -0
  2. representation_geometry-0.1.0/PKG-INFO +417 -0
  3. representation_geometry-0.1.0/README.md +379 -0
  4. representation_geometry-0.1.0/pyproject.toml +88 -0
  5. representation_geometry-0.1.0/setup.cfg +4 -0
  6. representation_geometry-0.1.0/src/representation_geometry/__init__.py +12 -0
  7. representation_geometry-0.1.0/src/representation_geometry/api.py +366 -0
  8. representation_geometry-0.1.0/src/representation_geometry/diagnostics.py +76 -0
  9. representation_geometry-0.1.0/src/representation_geometry/hooks.py +215 -0
  10. representation_geometry-0.1.0/src/representation_geometry/metrics.py +216 -0
  11. representation_geometry-0.1.0/src/representation_geometry/moe.py +57 -0
  12. representation_geometry-0.1.0/src/representation_geometry/online.py +65 -0
  13. representation_geometry-0.1.0/src/representation_geometry/results.py +87 -0
  14. representation_geometry-0.1.0/src/representation_geometry/smoke.py +77 -0
  15. representation_geometry-0.1.0/src/representation_geometry.egg-info/PKG-INFO +417 -0
  16. representation_geometry-0.1.0/src/representation_geometry.egg-info/SOURCES.txt +22 -0
  17. representation_geometry-0.1.0/src/representation_geometry.egg-info/dependency_links.txt +1 -0
  18. representation_geometry-0.1.0/src/representation_geometry.egg-info/entry_points.txt +2 -0
  19. representation_geometry-0.1.0/src/representation_geometry.egg-info/requires.txt +17 -0
  20. representation_geometry-0.1.0/src/representation_geometry.egg-info/top_level.txt +1 -0
  21. representation_geometry-0.1.0/tests/test_api_smoke.py +90 -0
  22. representation_geometry-0.1.0/tests/test_diagnostics.py +26 -0
  23. representation_geometry-0.1.0/tests/test_metrics.py +19 -0
  24. representation_geometry-0.1.0/tests/test_online.py +32 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vidit Gupta
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,417 @@
1
+ Metadata-Version: 2.4
2
+ Name: representation-geometry
3
+ Version: 0.1.0
4
+ Summary: Reproducible representation-geometry analysis for transformer language models.
5
+ Author: Vidit Gupta
6
+ Maintainer: Vidit Gupta
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/Vidit-01/representation-geometry
9
+ Project-URL: Repository, https://github.com/Vidit-01/representation-geometry
10
+ Project-URL: Issues, https://github.com/Vidit-01/representation-geometry/issues
11
+ Project-URL: Documentation, https://github.com/Vidit-01/representation-geometry#readme
12
+ Keywords: transformers,residual-stream,representation-geometry,effective-dimension,mechanistic-interpretability
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.23
24
+ Requires-Dist: pandas>=1.5
25
+ Requires-Dist: torch>=2.0
26
+ Provides-Extra: hf
27
+ Requires-Dist: accelerate>=0.26; extra == "hf"
28
+ Requires-Dist: datasets>=2.14; extra == "hf"
29
+ Requires-Dist: safetensors>=0.4; extra == "hf"
30
+ Requires-Dist: transformers>=4.40; extra == "hf"
31
+ Provides-Extra: plot
32
+ Requires-Dist: matplotlib>=3.7; extra == "plot"
33
+ Provides-Extra: dev
34
+ Requires-Dist: build>=1.2; extra == "dev"
35
+ Requires-Dist: pytest>=8.0; extra == "dev"
36
+ Requires-Dist: ruff>=0.8; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # representation-geometry
40
+
41
+ `representation-geometry` is a Python toolkit for measuring representation geometry inside transformer models. It collects internal activations with PyTorch hooks, updates streaming covariance statistics, computes spectral and subspace measurements, and saves reproducible artifact bundles.
42
+
43
+ The package follows the project vision in `VISION.md`: it provides measurement infrastructure, not paper-specific interpretation. It is model-agnostic where possible, stores reusable quantitative outputs, and stays isolated from manuscript code, figures, tables, and LaTeX files.
44
+
45
+ ## Features (Current)
46
+
47
+ - Analyze loaded `torch.nn.Module` models or Hugging Face causal language model ids.
48
+ - Collect residual block inputs, residual block outputs, or named submodule inputs/outputs.
49
+ - Accumulate covariance statistics with a streaming Welford-style backend.
50
+ - Compute spectral geometry metrics, sample-SVD metrics, and between-layer novelty metrics.
51
+ - Optionally run a normalization ablation diagnostic.
52
+ - Optionally collect simple MoE router load statistics when model outputs expose router logits.
53
+ - Save JSON, CSV, or bundle artifacts with versioned metadata, metrics, diagnostics, router stats, and eigenvalues.
54
+
55
+ ## Architecture Overview
56
+
57
+ The package is organized into four layers that can evolve independently:
58
+
59
+ 1. Activation collection through PyTorch hooks.
60
+ 2. Streaming statistical backends for covariance and sampled activations.
61
+ 3. Geometry metrics and diagnostics that consume those statistical objects.
62
+ 4. Artifact generation for DataFrames, JSON, CSV, NumPy arrays, and reproducibility metadata.
63
+
64
+ This separation is intentional. New measurements should be implemented against the statistical backend rather than directly inside model-specific collection code.
65
+
66
+ ## Why Streaming?
67
+
68
+ Many activation-analysis scripts store all hidden states before computing metrics. `representation-geometry` instead updates statistics incrementally whenever possible. The current covariance backend keeps streaming means, covariance numerators, and a bounded activation sample, which allows larger token budgets without keeping every activation in memory.
69
+
70
+ Dense covariance is still `hidden_dim x hidden_dim`, so very wide models require care, but the package is designed around bounded-memory measurement rather than one-off activation dumps.
71
+
72
+ ## Reproducibility
73
+
74
+ Every saved artifact bundle records the measurement protocol, not just the final numbers. Metadata includes the artifact schema version, model information, hook targets, selected layers, token budget, observed tokens, metric and diagnostic configuration, tokenizer and dataset labels when supplied, software versions, runtime, and optional user metadata.
75
+
76
+ The goal is for downstream research projects to reproduce the measurement independently of the original paper scripts.
77
+
78
+ ## Install
79
+
80
+ From this directory:
81
+
82
+ ```bash
83
+ python -m pip install -e ".[dev]"
84
+ ```
85
+
86
+ For Hugging Face loading and examples:
87
+
88
+ ```bash
89
+ python -m pip install -e ".[dev,hf]"
90
+ ```
91
+
92
+ The core package depends on `numpy`, `pandas`, and `torch`. The `hf` extra installs `transformers`, `accelerate`, `datasets`, and `safetensors`.
93
+
94
+ Development tooling is included in the `dev` extra: `pytest`, `ruff`, and `build`.
95
+
96
+ ## Quick Start
97
+
98
+ ```python
99
+ from representation_geometry import analyze_model
100
+
101
+ results = analyze_model(
102
+ model_name=model,
103
+ dataloader=dataloader,
104
+ max_tokens=100_000,
105
+ layers="all",
106
+ hook_point="residual_input",
107
+ metrics="default",
108
+ save_mode="bundle",
109
+ save_dir="runs/my_model",
110
+ tokenizer_name="my-tokenizer",
111
+ dataset_name="my-dataset",
112
+ )
113
+
114
+ print(results.metrics.head())
115
+ print(results.novelty.head())
116
+ print(results.metadata)
117
+ ```
118
+
119
+ `model_name` may be:
120
+
121
+ - a loaded `torch.nn.Module`,
122
+ - a Hugging Face model id string, if `transformers` is installed,
123
+ - or omitted when using the explicit `model=` argument.
124
+
125
+ For large models, prefer passing a preloaded model so you control dtype, device placement, quantization, and `device_map`.
126
+
127
+ ## Dataloader Format
128
+
129
+ `dataloader` must be an iterable of model batches. Dictionary batches with `input_ids` are preferred:
130
+
131
+ ```python
132
+ yield {
133
+ "input_ids": input_ids,
134
+ "attention_mask": attention_mask,
135
+ }
136
+ ```
137
+
138
+ The package moves tensors to the selected input device recursively. It calls the model under `torch.no_grad()` and tries `use_cache=False` for transformer-style forward methods.
139
+
140
+ `max_tokens` is a stopping budget based on observed batch tokens. The current implementation processes whole batches, so `tokens_observed` can exceed `max_tokens` on the final batch.
141
+
142
+ ## Hook Points
143
+
144
+ The default hook is the input to each transformer block:
145
+
146
+ ```python
147
+ analyze_model(model_name=model, dataloader=dataloader, hook_point="residual_input")
148
+ ```
149
+
150
+ Supported hook points are:
151
+
152
+ - `residual_input`: forward pre-hook on transformer blocks.
153
+ - `residual_output`: forward hook on transformer blocks.
154
+ - `module_input:<module_path>`: forward pre-hook on a named submodule.
155
+ - `module_output:<module_path>`: forward hook on a named submodule.
156
+
157
+ Examples:
158
+
159
+ ```python
160
+ analyze_model(model_name=model, dataloader=dataloader, layers=[0, 3, 7])
161
+
162
+ analyze_model(
163
+ model_name=model,
164
+ dataloader=dataloader,
165
+ hook_point="module_output:blocks.0.proj",
166
+ )
167
+ ```
168
+
169
+ For residual hooks, transformer blocks are auto-detected from common containers such as `.transformer.h`, `.model.layers`, `.gpt_neox.layers`, `.decoder.layers`, `.layers`, `.blocks`, or `.h`.
170
+
171
+ For named module hooks, use paths from `dict(model.named_modules())`. Named module hooks currently collect a single target and should be called with the default `layers="all"`.
172
+
173
+ ## Metrics
174
+
175
+ `metrics="default"`, `metrics=None`, or `metrics=[]` computes all currently implemented metric families:
176
+
177
+ - `spectrum`
178
+ - `sample`
179
+ - `novelty`
180
+
181
+ You can request a narrower set:
182
+
183
+ ```python
184
+ analyze_model(model_name=model, dataloader=dataloader, metrics=["spectrum"])
185
+ ```
186
+
187
+ ### Spectrum Metrics
188
+
189
+ Computed from covariance eigenvalues:
190
+
191
+ - `d_pr`
192
+ - `d_pr_norm`
193
+ - `d_entropy`
194
+ - `d_entropy_norm`
195
+ - `stable_rank`
196
+ - `top1_share`
197
+ - `top10_share`
198
+ - `top32_share`
199
+ - `k90`
200
+ - `k95`
201
+ - `log_spectrum_slope_10_200`
202
+
203
+ The near-rank-1 criterion used by the original paper workflow can be computed downstream:
204
+
205
+ ```python
206
+ near_rank1 = (results.metrics["top1_share"] >= 0.99) & (results.metrics["k90"] <= 1)
207
+ ```
208
+
209
+ ### Activation Sample Metrics
210
+
211
+ Computed from a bounded activation sample stored by the streaming accumulator:
212
+
213
+ - `sv_effective_rank`
214
+ - `sv_stable_rank`
215
+ - `sv_participation_ratio`
216
+ - `cos_sim_mean`
217
+ - `cos_sim_std`
218
+ - `ve_4`
219
+ - `ve_8`
220
+ - `ve_16`
221
+ - `ve_32`
222
+
223
+ The sample size is controlled by `sample_limit`, default `512`.
224
+
225
+ ### Novelty Metrics
226
+
227
+ Computed between consecutive collected layers:
228
+
229
+ - `feature_subspace_novelty`
230
+ - `linear_cka`
231
+ - `layer_cosine_sim`
232
+
233
+ `novelty_k` controls the number of top covariance eigenvectors used for feature-subspace novelty.
234
+
235
+ ## Diagnostics
236
+
237
+ Currently supported diagnostics:
238
+
239
+ ```python
240
+ diagnostics=["normalization_ablation"]
241
+ ```
242
+
243
+ This diagnostic recomputes spectrum metrics on sampled activations under:
244
+
245
+ - `raw`
246
+ - `token_l2`
247
+ - `token_rms`
248
+ - `feature_standardized`
249
+
250
+ Diagnostics are stored in `results.diagnostics` and saved under `diagnostics/` when `save_mode` is enabled.
251
+
252
+ ## Extending The Package
253
+
254
+ The current public API does not yet accept arbitrary user-defined metrics at runtime. Internally, however, metrics are already separated from activation collection: `api.py` collects activations into streaming statistics, and `metrics.py` computes measurements from those statistics.
255
+
256
+ To add a new built-in metric today, implement it as a focused function in `metrics.py`, thread it through the metric-family selection in `api.py`, add tests, and document the new output columns. Diagnostics follow the same pattern through the small `DIAGNOSTIC_REGISTRY` in `diagnostics.py`.
257
+
258
+ This is a stepping stone toward the longer-term vision of a registry-style metric API.
259
+
260
+ ## Outputs
261
+
262
+ `analyze_model` returns an `AnalysisResults` object:
263
+
264
+ ```python
265
+ results.metrics # pandas.DataFrame
266
+ results.novelty # pandas.DataFrame
267
+ results.router # pandas.DataFrame, empty unless router stats are available
268
+ results.diagnostics # dict[str, pandas.DataFrame]
269
+ results.eigenvalues # dict[str, numpy.ndarray]
270
+ results.metadata # dict
271
+ results.artifact_dir # pathlib.Path after save()
272
+ ```
273
+
274
+ Supported save modes:
275
+
276
+ - `save_mode=None`: no files are written.
277
+ - `save_mode="json"`: writes JSON tables.
278
+ - `save_mode="csv"`: writes CSV tables.
279
+ - `save_mode="bundle"`: writes CSV tables plus bundle metadata and eigenvalues.
280
+
281
+ Saved bundle contents:
282
+
283
+ ```text
284
+ metrics.csv or metrics.json
285
+ novelty.csv or novelty.json
286
+ router.csv or router.json # only when router stats are available
287
+ diagnostics/* # only when diagnostics are requested
288
+ eigenvalues.npz
289
+ metadata.json
290
+ ```
291
+
292
+ Metadata includes `artifact_schema_version`, model id, model class, model config summary, token budget, observed tokens, batch count, hook point, hook targets, selected layers, metric names, diagnostic names, tokenizer label, dataset label, input device, software versions, runtime, save mode, and optional `run_metadata`.
293
+
294
+ ## Hugging Face Usage
295
+
296
+ Small runnable example:
297
+
298
+ ```python
299
+ from pathlib import Path
300
+
301
+ import torch
302
+ from transformers import AutoModelForCausalLM, AutoTokenizer
303
+
304
+ from representation_geometry import analyze_model
305
+
306
+ model_id = "hf-internal-testing/tiny-random-gpt2"
307
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
308
+ model = AutoModelForCausalLM.from_pretrained(model_id)
309
+ model.eval()
310
+
311
+ tokens = tokenizer(
312
+ "Residual geometry measures covariance structure inside transformer layers.",
313
+ return_tensors="pt",
314
+ )
315
+
316
+ results = analyze_model(
317
+ model_name=model,
318
+ dataloader=[tokens],
319
+ max_tokens=16,
320
+ layers=[0],
321
+ save_mode="json",
322
+ save_dir=Path(".tmp") / "hf_usage_example",
323
+ tokenizer_name=model_id,
324
+ dataset_name="inline example sentence",
325
+ )
326
+
327
+ print(results.metrics[["layer", "d_pr_norm", "top1_share", "k90"]])
328
+ ```
329
+
330
+ The same pattern is available as:
331
+
332
+ ```bash
333
+ python examples/hf_tiny_random_gpt2.py
334
+ ```
335
+
336
+ ## Examples
337
+
338
+ Tiny in-memory model with no Hugging Face dependency:
339
+
340
+ ```bash
341
+ python examples/tiny_in_memory.py
342
+ ```
343
+
344
+ GPT-2 Hugging Face example:
345
+
346
+ ```bash
347
+ python examples/minimal_hf_gpt2.py
348
+ ```
349
+
350
+ Tiny Hugging Face model example:
351
+
352
+ ```bash
353
+ python examples/hf_tiny_random_gpt2.py
354
+ ```
355
+
356
+ Package smoke test:
357
+
358
+ ```bash
359
+ python -m representation_geometry.smoke --out-dir .tmp/smoke
360
+ ```
361
+
362
+ After installation, the console script is:
363
+
364
+ ```bash
365
+ representation-geometry-smoke --out-dir .tmp/smoke
366
+ ```
367
+
368
+ ## Tests
369
+
370
+ Run the test suite:
371
+
372
+ ```bash
373
+ python -m pytest
374
+ ```
375
+
376
+ Run linting:
377
+
378
+ ```bash
379
+ python -m ruff check .
380
+ ```
381
+
382
+ Build a wheel and source distribution:
383
+
384
+ ```bash
385
+ python -m build
386
+ ```
387
+
388
+ The tests cover covariance streaming, metric formulas, diagnostics, JSON/bundle saving, named module hooks, residual output hooks, and metric subset selection.
389
+
390
+ ## Current Limitations
391
+
392
+ - `analyze_model` currently loads Hugging Face ids with `AutoModelForCausalLM`.
393
+ - Residual block discovery uses common transformer container names; uncommon architectures may need named module hooks.
394
+ - Named module hooks collect one target per call.
395
+ - Covariance matrices are stored on CPU as dense `hidden_dim x hidden_dim` tensors, so very large hidden dimensions still need care.
396
+ - Distributed collection, sketching, randomized eigensolvers, dashboards, multimodal-specific helpers, and causal intervention APIs are vision items, not implemented yet.
397
+
398
+ ## Design Boundary
399
+
400
+ This package owns reusable measurement infrastructure:
401
+
402
+ - activation collection,
403
+ - streaming statistics,
404
+ - geometry metrics,
405
+ - diagnostics,
406
+ - artifact serialization.
407
+
408
+ It deliberately does not own:
409
+
410
+ - paper prose,
411
+ - LaTeX generation,
412
+ - publication tables,
413
+ - manuscript figures,
414
+ - benchmark leaderboards,
415
+ - research conclusions.
416
+
417
+ Downstream projects should interpret the measurements; `representation-geometry` should make the measurements reproducible.