icalens 0.2.2__tar.gz → 0.3.0.dev1__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.
- {icalens-0.2.2 → icalens-0.3.0.dev1}/.gitignore +3 -1
- icalens-0.3.0.dev1/.readthedocs.yaml +13 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/PKG-INFO +36 -7
- {icalens-0.2.2 → icalens-0.3.0.dev1}/README.md +33 -5
- {icalens-0.2.2 → icalens-0.3.0.dev1}/demo/README.md +83 -11
- {icalens-0.2.2 → icalens-0.3.0.dev1}/demo/apply.py +19 -27
- icalens-0.3.0.dev1/demo/apply_chat.py +308 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/demo/fit.py +15 -1
- {icalens-0.2.2 → icalens-0.3.0.dev1}/demo/fit_chat.py +18 -4
- icalens-0.3.0.dev1/demo/get_started.py +41 -0
- icalens-0.3.0.dev1/demo/plot_objective.py +138 -0
- icalens-0.3.0.dev1/docs/api.md +87 -0
- icalens-0.3.0.dev1/docs/fit-and-publish.md +67 -0
- icalens-0.3.0.dev1/docs/getting-started.md +61 -0
- icalens-0.3.0.dev1/docs/index.md +44 -0
- icalens-0.3.0.dev1/docs/requirements.txt +1 -0
- icalens-0.3.0.dev1/docs/scores-and-energy.md +47 -0
- icalens-0.3.0.dev1/docs/text-and-chat.md +63 -0
- icalens-0.3.0.dev1/mkdocs.yml +56 -0
- {icalens-0.2.2/docs → icalens-0.3.0.dev1/notes}/api.md +15 -1
- {icalens-0.2.2/docs → icalens-0.3.0.dev1/notes}/artifact-format.md +12 -1
- {icalens-0.2.2 → icalens-0.3.0.dev1}/pyproject.toml +8 -1
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/__init__.py +1 -1
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/_capture.py +22 -5
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/_fastica.py +174 -35
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/analysis.py +62 -9
- icalens-0.3.0.dev1/src/icalens/html.py +299 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/lens.py +23 -3
- icalens-0.3.0.dev1/src/icalens/smoke_test.py +138 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/test_analysis.py +21 -0
- icalens-0.3.0.dev1/tests/test_capture.py +104 -0
- icalens-0.3.0.dev1/tests/test_html_explorer.py +108 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/test_lens.py +36 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/test_public_api.py +1 -1
- {icalens-0.2.2 → icalens-0.3.0.dev1}/uv.lock +201 -1
- icalens-0.2.2/demo/apply_chat.py +0 -184
- icalens-0.2.2/demo/html_explorer.py +0 -168
- icalens-0.2.2/tests/test_capture.py +0 -40
- icalens-0.2.2/tests/test_html_explorer.py +0 -29
- {icalens-0.2.2 → icalens-0.3.0.dev1}/.env.template +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/.github/workflows/release.yml +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/LICENSE +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/THIRD_PARTY_NOTICES.md +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/demo/__init__.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/demo/publish.py +0 -0
- {icalens-0.2.2/docs → icalens-0.3.0.dev1/notes}/naming.md +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/_arrays.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/_artifact.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/exceptions.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/src/icalens/py.typed +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/conftest.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/test_artifacts.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/test_demo_fit.py +0 -0
- {icalens-0.2.2 → icalens-0.3.0.dev1}/tests/test_demo_fit_chat.py +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: icalens
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0.dev1
|
|
4
4
|
Summary: Fit, share, and apply ICA lenses for language-model activations.
|
|
5
5
|
Project-URL: Homepage, https://liusida.github.io/ica-lens-paper/
|
|
6
|
+
Project-URL: Documentation, https://icalens.readthedocs.io/
|
|
6
7
|
Project-URL: Repository, https://github.com/liusida/icalens
|
|
7
8
|
Author: Sida Liu, Feijiang Han
|
|
8
9
|
License-Expression: MIT
|
|
@@ -43,6 +44,7 @@ result = lens.analyze("She deposited the check at the bank.", layer=6)
|
|
|
43
44
|
|
|
44
45
|
print(result.tokens)
|
|
45
46
|
print(result.scores)
|
|
47
|
+
result.to_html("analysis.html")
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
Fit and publish your own:
|
|
@@ -89,6 +91,8 @@ lens = ICALens(
|
|
|
89
91
|
The standard `icalens` installation can capture and analyze text or completed
|
|
90
92
|
chat conversations directly. `result = lens.analyze(text, layer=6)` returns aligned
|
|
91
93
|
tokens, activations, signed scores, and per-token component energy shares.
|
|
94
|
+
`result.to_html("analysis.html")` writes a self-contained interactive explorer;
|
|
95
|
+
pass `metric="energy"` to visualize component energy shares instead of scores.
|
|
92
96
|
|
|
93
97
|
Inputs may be NumPy arrays or PyTorch tensors. Leading dimensions are treated
|
|
94
98
|
as sample dimensions and the final dimension must be the model hidden size.
|
|
@@ -96,9 +100,8 @@ Fitting uses ICA Lens's built-in PyTorch FastICA implementation and can run on
|
|
|
96
100
|
the input tensor's device. NumPy inputs are fitted on CPU. ICA Lens does not
|
|
97
101
|
depend on scikit-learn or SciPy.
|
|
98
102
|
|
|
99
|
-
See [
|
|
100
|
-
|
|
101
|
-
portable artifact format.
|
|
103
|
+
See the [documentation](https://icalens.readthedocs.io/) for the complete text,
|
|
104
|
+
conversation, fitting, publishing, and HTML-export workflows.
|
|
102
105
|
|
|
103
106
|
For the 1,000-token GPT-2/Pile-10k fitting demo, run:
|
|
104
107
|
|
|
@@ -107,8 +110,8 @@ uv sync
|
|
|
107
110
|
uv run python demo/fit.py
|
|
108
111
|
```
|
|
109
112
|
|
|
110
|
-
For the corresponding instruct-model demo using
|
|
111
|
-
|
|
113
|
+
For the corresponding instruct-model demo using all formatted UltraChat
|
|
114
|
+
conversation tokens, including template markers, run:
|
|
112
115
|
|
|
113
116
|
```bash
|
|
114
117
|
uv run python demo/fit_chat.py --layers 12
|
|
@@ -122,3 +125,29 @@ uv run python demo/apply_chat.py
|
|
|
122
125
|
|
|
123
126
|
Both `apply.py` and `apply_chat.py` also write standalone interactive HTML
|
|
124
127
|
explorers under `demo/output/`; pass `--output-file` to choose another path.
|
|
128
|
+
|
|
129
|
+
## Installed-package smoke test
|
|
130
|
+
|
|
131
|
+
After installing a wheel or PyPI release in a clean project, run the bundled
|
|
132
|
+
end-to-end check:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
uv run icalens-smoke-test
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
By default, the suite checks both public input paths: raw text through the
|
|
139
|
+
published GPT-2 lens and a formatted conversation through the published
|
|
140
|
+
Qwen3.5-2B instruct lens. Each case lazily downloads one ICA layer, verifies
|
|
141
|
+
finite scores and normalized energy, checks reconstruction shape, and writes
|
|
142
|
+
`icalens-smoke-text.html` or `icalens-smoke-chat.html`.
|
|
143
|
+
|
|
144
|
+
Run only one path when iterating locally:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
uv run icalens-smoke-test text
|
|
148
|
+
uv run icalens-smoke-test chat
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Use `--text-lens`, `--text-layer`, `--text-input`, `--chat-lens`,
|
|
152
|
+
`--chat-layer`, `--chat-input`, `--chat-response`, `--device`, and
|
|
153
|
+
`--output-dir` to override the defaults.
|
|
@@ -18,6 +18,7 @@ result = lens.analyze("She deposited the check at the bank.", layer=6)
|
|
|
18
18
|
|
|
19
19
|
print(result.tokens)
|
|
20
20
|
print(result.scores)
|
|
21
|
+
result.to_html("analysis.html")
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
Fit and publish your own:
|
|
@@ -64,6 +65,8 @@ lens = ICALens(
|
|
|
64
65
|
The standard `icalens` installation can capture and analyze text or completed
|
|
65
66
|
chat conversations directly. `result = lens.analyze(text, layer=6)` returns aligned
|
|
66
67
|
tokens, activations, signed scores, and per-token component energy shares.
|
|
68
|
+
`result.to_html("analysis.html")` writes a self-contained interactive explorer;
|
|
69
|
+
pass `metric="energy"` to visualize component energy shares instead of scores.
|
|
67
70
|
|
|
68
71
|
Inputs may be NumPy arrays or PyTorch tensors. Leading dimensions are treated
|
|
69
72
|
as sample dimensions and the final dimension must be the model hidden size.
|
|
@@ -71,9 +74,8 @@ Fitting uses ICA Lens's built-in PyTorch FastICA implementation and can run on
|
|
|
71
74
|
the input tensor's device. NumPy inputs are fitted on CPU. ICA Lens does not
|
|
72
75
|
depend on scikit-learn or SciPy.
|
|
73
76
|
|
|
74
|
-
See [
|
|
75
|
-
|
|
76
|
-
portable artifact format.
|
|
77
|
+
See the [documentation](https://icalens.readthedocs.io/) for the complete text,
|
|
78
|
+
conversation, fitting, publishing, and HTML-export workflows.
|
|
77
79
|
|
|
78
80
|
For the 1,000-token GPT-2/Pile-10k fitting demo, run:
|
|
79
81
|
|
|
@@ -82,8 +84,8 @@ uv sync
|
|
|
82
84
|
uv run python demo/fit.py
|
|
83
85
|
```
|
|
84
86
|
|
|
85
|
-
For the corresponding instruct-model demo using
|
|
86
|
-
|
|
87
|
+
For the corresponding instruct-model demo using all formatted UltraChat
|
|
88
|
+
conversation tokens, including template markers, run:
|
|
87
89
|
|
|
88
90
|
```bash
|
|
89
91
|
uv run python demo/fit_chat.py --layers 12
|
|
@@ -97,3 +99,29 @@ uv run python demo/apply_chat.py
|
|
|
97
99
|
|
|
98
100
|
Both `apply.py` and `apply_chat.py` also write standalone interactive HTML
|
|
99
101
|
explorers under `demo/output/`; pass `--output-file` to choose another path.
|
|
102
|
+
|
|
103
|
+
## Installed-package smoke test
|
|
104
|
+
|
|
105
|
+
After installing a wheel or PyPI release in a clean project, run the bundled
|
|
106
|
+
end-to-end check:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run icalens-smoke-test
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
By default, the suite checks both public input paths: raw text through the
|
|
113
|
+
published GPT-2 lens and a formatted conversation through the published
|
|
114
|
+
Qwen3.5-2B instruct lens. Each case lazily downloads one ICA layer, verifies
|
|
115
|
+
finite scores and normalized energy, checks reconstruction shape, and writes
|
|
116
|
+
`icalens-smoke-text.html` or `icalens-smoke-chat.html`.
|
|
117
|
+
|
|
118
|
+
Run only one path when iterating locally:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv run icalens-smoke-test text
|
|
122
|
+
uv run icalens-smoke-test chat
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use `--text-lens`, `--text-layer`, `--text-input`, `--chat-lens`,
|
|
126
|
+
`--chat-layer`, `--chat-input`, `--chat-response`, `--device`, and
|
|
127
|
+
`--output-dir` to override the defaults.
|
|
@@ -38,6 +38,32 @@ as diagnostic-only because it is not an appropriate stopping rule in the LLM
|
|
|
38
38
|
activation regime. The displayed objective uses the selected FastICA contrast:
|
|
39
39
|
`log(cosh(x))`, `-exp(-x²/2)`, or `x⁴/4`.
|
|
40
40
|
|
|
41
|
+
For parallel FastICA, every saved layer also records an objective curve in
|
|
42
|
+
`icalens.json` under `layers.<layer>.fitting.objective_history`. At each
|
|
43
|
+
recorded iteration, the contrast is averaged over fitting tokens for each
|
|
44
|
+
component, then summarized across components at the minimum, 10th, 20th, ...,
|
|
45
|
+
90th percentile, and maximum. Its `iterations`, `percentiles`, and `values`
|
|
46
|
+
arrays can be plotted directly as percentile curves or nested colored bands.
|
|
47
|
+
Use `--objective-every N` to record every Nth iteration; the final iteration is
|
|
48
|
+
always included. The default is `1`.
|
|
49
|
+
|
|
50
|
+
After the fixed-point iterations, ICA Lens makes one final blockwise objective
|
|
51
|
+
pass and renumbers components by descending absolute contrast deviation from
|
|
52
|
+
the standard-Gaussian baseline. `C0` is therefore the strongest non-Gaussian
|
|
53
|
+
component within that layer. The manifest retains every component's raw
|
|
54
|
+
objective and baseline-relative strength.
|
|
55
|
+
|
|
56
|
+
Plot the first four available layers from a local, progressively written lens:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv run python demo/plot_objective.py \
|
|
60
|
+
demo/output/icalens-qwen3.5-2b-ultrachat-10m
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Use `--layers 0,1,2`, `--first 6`, or `--output path/to/curves.png` to customize
|
|
64
|
+
the selection and output. Nested colored bands show min–max, p10–p90, ...,
|
|
65
|
+
p40–p60, with the median drawn as a line.
|
|
66
|
+
|
|
41
67
|
The demo also displays token-rate progress bars while building the Pile-10k
|
|
42
68
|
candidate pool and capturing the sampled GPT-2 activations.
|
|
43
69
|
|
|
@@ -92,9 +118,16 @@ uv run python demo/fit.py \
|
|
|
92
118
|
|
|
93
119
|
This captures layers 0–1, fits them, releases their activations, and then
|
|
94
120
|
repeats for layers 2–3. Smaller groups use less memory but require more complete
|
|
95
|
-
passes over the tokenized dataset.
|
|
121
|
+
passes over the tokenized dataset. Each capture pass stops immediately after
|
|
122
|
+
its highest requested transformer block, so an early-layer group does not run
|
|
123
|
+
the unused remainder of the model. The default `0` captures all requested
|
|
96
124
|
layers in one pass.
|
|
97
125
|
|
|
126
|
+
After each layer finishes fitting, the demos atomically checkpoint the growing
|
|
127
|
+
lens to `--output`, including that layer's objective history. If a later layer
|
|
128
|
+
fails or the run is interrupted, every previously completed layer remains
|
|
129
|
+
loadable from the output directory.
|
|
130
|
+
|
|
98
131
|
The demo requires network access for Hugging Face downloads and a CUDA device.
|
|
99
132
|
|
|
100
133
|
Use every token available under the demo's per-document context limit without
|
|
@@ -112,19 +145,34 @@ reserved memory at the end.
|
|
|
112
145
|
|
|
113
146
|
## Fit an instruct-model lens from conversations
|
|
114
147
|
|
|
115
|
-
Fit a Qwen2.5-0.5B-Instruct lens on
|
|
148
|
+
Fit a Qwen2.5-0.5B-Instruct lens on all formatted tokens from streamed
|
|
116
149
|
UltraChat 200k conversations:
|
|
117
150
|
|
|
118
151
|
```bash
|
|
119
152
|
uv run python demo/fit_chat.py --layers 12
|
|
120
153
|
```
|
|
121
154
|
|
|
155
|
+
Qwen3.5 multimodal checkpoints can be fitted as text-only language models. The
|
|
156
|
+
loader selects the language backbone, while chat templating and assistant-token
|
|
157
|
+
selection use the same interface:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
uv run python demo/fit_chat.py \
|
|
161
|
+
--model Qwen/Qwen3.5-2B \
|
|
162
|
+
--layers 12 \
|
|
163
|
+
--token-budget 100000 \
|
|
164
|
+
--max-iter 20 \
|
|
165
|
+
--output demo/output/icalens-qwen3.5-2b-ultrachat-100k
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Qwen3.5-2B has 24 language layers indexed from 0 through 23 and hidden size
|
|
169
|
+
2048. Use at least 2049 fitting tokens for a full-component lens.
|
|
170
|
+
|
|
122
171
|
The script uses the tokenizer's chat template and offset mapping to distinguish
|
|
123
172
|
message content from role markers and other template control tokens. The
|
|
124
|
-
default `--token-scope
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
(including template tokens).
|
|
173
|
+
default `--token-scope all` fits every formatted position, including template
|
|
174
|
+
tokens. Other supported scopes are `assistant`, `user`, and `content` (all
|
|
175
|
+
message content but no template markers).
|
|
128
176
|
|
|
129
177
|
As in the plain-text demo, `--candidate-tokens` defaults to `--token-budget`.
|
|
130
178
|
For a larger deterministic candidate pool, run:
|
|
@@ -152,18 +200,18 @@ uv run python demo/fit_chat.py \
|
|
|
152
200
|
```
|
|
153
201
|
|
|
154
202
|
Ask the model to generate a response and apply the resulting instruct lens to
|
|
155
|
-
the
|
|
203
|
+
the complete formatted conversation:
|
|
156
204
|
|
|
157
205
|
```bash
|
|
158
206
|
uv run python demo/apply_chat.py
|
|
159
207
|
```
|
|
160
208
|
|
|
161
209
|
The script first generates a response, then performs a full forward pass over
|
|
162
|
-
the completed conversation so each
|
|
210
|
+
the completed conversation so each formatted token has an activation aligned
|
|
163
211
|
with the same chat formatting used during fitting. The default output shows
|
|
164
|
-
component scores
|
|
165
|
-
|
|
166
|
-
|
|
212
|
+
component scores for all formatted tokens. Pass `--user` and optionally
|
|
213
|
+
`--system` to supply a different prompt. `--token-scope` accepts the same
|
|
214
|
+
`assistant`, `user`, `content`, and `all` choices as the fitting demo:
|
|
167
215
|
|
|
168
216
|
```bash
|
|
169
217
|
uv run python demo/apply_chat.py \
|
|
@@ -178,6 +226,25 @@ The command also writes a self-contained v5-style explorer to
|
|
|
178
226
|
different location. The report works directly from disk and does not require
|
|
179
227
|
the v5 server.
|
|
180
228
|
|
|
229
|
+
For a predetermined multi-turn conversation, pass a quoted JSON list. The
|
|
230
|
+
model generates an assistant response after each entry; the next user entry is
|
|
231
|
+
then appended regardless of what the model said:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
uv run python demo/apply_chat.py \
|
|
235
|
+
--user '["Hi, how are you?", "Nothing."]' \
|
|
236
|
+
--layer 7
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Repeating the flag is equivalent and is often easier to type:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
uv run python demo/apply_chat.py \
|
|
243
|
+
--user "Hi, how are you?" \
|
|
244
|
+
--user "Nothing." \
|
|
245
|
+
--layer 7
|
|
246
|
+
```
|
|
247
|
+
|
|
181
248
|
## Apply the saved lens
|
|
182
249
|
|
|
183
250
|
After fitting layer 6, apply it to fresh text:
|
|
@@ -204,6 +271,11 @@ includes responsive token cards, signed component bars, component highlighting,
|
|
|
204
271
|
card-width control, and an opacity cutoff. Override the path with
|
|
205
272
|
`--output-file PATH`.
|
|
206
273
|
|
|
274
|
+
Pass `--metric score` (the default) for signed ICA coordinates or
|
|
275
|
+
`--metric energy` for nonnegative per-token squared-score fractions displayed
|
|
276
|
+
as percentages. The selected metric controls ranking, terminal output, and the
|
|
277
|
+
HTML explorer for both `apply.py` and `apply_chat.py`.
|
|
278
|
+
|
|
207
279
|
## Publish and verify a chat lens
|
|
208
280
|
|
|
209
281
|
The fitting demo records exact dataset and sampling provenance. Upload through
|
|
@@ -7,7 +7,6 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
import torch
|
|
9
9
|
from gb10_load_llm import load_model_to_cuda
|
|
10
|
-
from html_explorer import write_explorer_html
|
|
11
10
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
12
11
|
|
|
13
12
|
from icalens import ICALens
|
|
@@ -23,10 +22,20 @@ def parse_args() -> argparse.Namespace:
|
|
|
23
22
|
parser.add_argument("--text", default=DEFAULT_TEXT)
|
|
24
23
|
parser.add_argument("--layer", type=int, default=6)
|
|
25
24
|
parser.add_argument("--top-k", type=int, default=5)
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--metric",
|
|
27
|
+
choices=("score", "energy"),
|
|
28
|
+
default="score",
|
|
29
|
+
help="Rank and display signed ICA scores or per-token energy shares.",
|
|
30
|
+
)
|
|
26
31
|
parser.add_argument("--output-file", type=Path, default=DEFAULT_OUTPUT_FILE)
|
|
27
32
|
return parser.parse_args()
|
|
28
33
|
|
|
29
34
|
|
|
35
|
+
def format_value(value: float, metric: str) -> str:
|
|
36
|
+
return f"{value:+.3f}" if metric == "score" else f"{value:.2%}"
|
|
37
|
+
|
|
38
|
+
|
|
30
39
|
def main() -> None:
|
|
31
40
|
args = parse_args()
|
|
32
41
|
if not torch.cuda.is_available():
|
|
@@ -62,46 +71,29 @@ def main() -> None:
|
|
|
62
71
|
tokenizer=tokenizer,
|
|
63
72
|
context_length=tokenizer.model_max_length,
|
|
64
73
|
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
values = result.scores if args.metric == "score" else result.energy
|
|
75
|
+
ranking_values = values.abs() if args.metric == "score" else values
|
|
76
|
+
top_k = min(args.top_k, values.shape[-1])
|
|
77
|
+
top_indices = torch.topk(ranking_values, k=top_k, dim=-1).indices
|
|
69
78
|
tokens = result.tokens
|
|
70
79
|
|
|
71
80
|
print(f"Lens: {args.lens}")
|
|
72
81
|
print(f"Model: {lens.model_id}@{lens.model_revision} ({lens.model_type})")
|
|
73
82
|
print(f"Layer: {args.layer}")
|
|
83
|
+
print(f"Metric: {args.metric}")
|
|
74
84
|
print()
|
|
75
85
|
for position, token in enumerate(tokens):
|
|
76
86
|
entries = [
|
|
77
|
-
f"C{component.item()}={
|
|
87
|
+
f"C{component.item()}={format_value(values[position, component].item(), args.metric)}"
|
|
78
88
|
for component in top_indices[position]
|
|
79
89
|
]
|
|
80
90
|
print(f"{position:>3} {token!r:<18} {' '.join(entries)}")
|
|
81
91
|
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
"position": position,
|
|
85
|
-
"token": token,
|
|
86
|
-
"token_text": tokenizer.decode([token_ids[position]]),
|
|
87
|
-
"top": [
|
|
88
|
-
{
|
|
89
|
-
"component": int(component),
|
|
90
|
-
"score": float(scores[position, component]),
|
|
91
|
-
}
|
|
92
|
-
for component in top_indices[position]
|
|
93
|
-
],
|
|
94
|
-
}
|
|
95
|
-
for position, token in enumerate(tokens)
|
|
96
|
-
]
|
|
97
|
-
output_file = write_explorer_html(
|
|
92
|
+
output_file = result.to_html(
|
|
98
93
|
args.output_file,
|
|
99
94
|
title="ICA Lens Text Explorer",
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
input_text=args.text,
|
|
103
|
-
token_scope="all text tokens",
|
|
104
|
-
tokens=html_tokens,
|
|
95
|
+
metric=args.metric,
|
|
96
|
+
top_k=args.top_k,
|
|
105
97
|
)
|
|
106
98
|
print()
|
|
107
99
|
print(f"HTML explorer: {output_file}")
|