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
openinterp/cli_build.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""``open-interpretability build``: compile the archived experiments into the static site."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from openinterp.cli import cli, wiki_dir_option
|
|
10
|
+
from openinterp.core.schemas import COMMITTED_SOURCES
|
|
11
|
+
from openinterp.sisters import DEFAULT_PATH as SISTERS_PATH
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@cli.command()
|
|
15
|
+
@wiki_dir_option("Experiment archive (wiki/experiments/**/<id>.json).", exists=True)
|
|
16
|
+
@click.option(
|
|
17
|
+
"--output-dir", default=Path("dist"), show_default=True, type=click.Path(path_type=Path)
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
"--wiring",
|
|
21
|
+
"wiring_path",
|
|
22
|
+
default=Path("docs/analyses/wiring.jsonl"),
|
|
23
|
+
show_default=True,
|
|
24
|
+
type=click.Path(dir_okay=False, path_type=Path),
|
|
25
|
+
help="Backfilled wiring (`open-interpretability wiring-backfill`) for records without "
|
|
26
|
+
"their own; skipped if missing.",
|
|
27
|
+
)
|
|
28
|
+
@click.option(
|
|
29
|
+
"--corpus-sources",
|
|
30
|
+
"source_paths",
|
|
31
|
+
multiple=True,
|
|
32
|
+
default=[Path(name) for name in COMMITTED_SOURCES],
|
|
33
|
+
show_default=True,
|
|
34
|
+
type=click.Path(dir_okay=False, path_type=Path),
|
|
35
|
+
help="Corpus sidecars that give the source of records which scanned their corpus "
|
|
36
|
+
"(matched by SHA-256) without recording one, shown as inferred; skipped if missing.",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--alignment",
|
|
40
|
+
"alignment_path",
|
|
41
|
+
default=Path("docs/analyses/dictionary-alignment.jsonl"),
|
|
42
|
+
show_default=True,
|
|
43
|
+
type=click.Path(dir_okay=False, path_type=Path),
|
|
44
|
+
help="Dictionary latents aligned with each neuron pole (`open-interpretability crossref`); "
|
|
45
|
+
"skipped if missing.",
|
|
46
|
+
)
|
|
47
|
+
@click.option(
|
|
48
|
+
"--sisters",
|
|
49
|
+
"sisters_path",
|
|
50
|
+
default=SISTERS_PATH,
|
|
51
|
+
show_default=True,
|
|
52
|
+
type=click.Path(dir_okay=False, path_type=Path),
|
|
53
|
+
help="Each VERIFIED pole's matches in other models (`open-interpretability sisters`); "
|
|
54
|
+
"skipped if missing.",
|
|
55
|
+
)
|
|
56
|
+
@click.option(
|
|
57
|
+
"--coverage",
|
|
58
|
+
"coverage_path",
|
|
59
|
+
default=Path("docs/analyses/registry-coverage.jsonl"),
|
|
60
|
+
show_default=True,
|
|
61
|
+
type=click.Path(dir_okay=False, path_type=Path),
|
|
62
|
+
help="Registry coverage rows (`open-interpretability coverage`) for the home page; "
|
|
63
|
+
"skipped if missing.",
|
|
64
|
+
)
|
|
65
|
+
@click.option(
|
|
66
|
+
"--papers",
|
|
67
|
+
"papers_dir",
|
|
68
|
+
default=Path("papers"),
|
|
69
|
+
show_default=True,
|
|
70
|
+
type=click.Path(file_okay=False, path_type=Path),
|
|
71
|
+
help="The papers of the Research section; the section is empty if missing.",
|
|
72
|
+
)
|
|
73
|
+
@click.option(
|
|
74
|
+
"--jobs",
|
|
75
|
+
type=click.IntRange(min=1),
|
|
76
|
+
default=None,
|
|
77
|
+
help="Worker processes that render the unit pages. Default: one per CPU. 1 renders in "
|
|
78
|
+
"this process.",
|
|
79
|
+
)
|
|
80
|
+
def build( # noqa: PLR0913 (one option per input file)
|
|
81
|
+
wiki_dir,
|
|
82
|
+
output_dir,
|
|
83
|
+
wiring_path,
|
|
84
|
+
source_paths,
|
|
85
|
+
alignment_path,
|
|
86
|
+
sisters_path,
|
|
87
|
+
coverage_path,
|
|
88
|
+
papers_dir,
|
|
89
|
+
jobs,
|
|
90
|
+
):
|
|
91
|
+
"""Compile every archived experiment into static pages and data/registry.parquet."""
|
|
92
|
+
from openinterp.builder.compiler import compile_site
|
|
93
|
+
from openinterp.builder.coverage import load_rows as load_coverage
|
|
94
|
+
from openinterp.builder.model_facts import load_model_facts
|
|
95
|
+
from openinterp.builder.parallel import default_jobs
|
|
96
|
+
from openinterp.builder.users import load_users
|
|
97
|
+
from openinterp.builder.wiki import load_archive
|
|
98
|
+
from openinterp.core.draws import load_draws, load_stops
|
|
99
|
+
from openinterp.core.errata import load_errata
|
|
100
|
+
from openinterp.core.project import project_links
|
|
101
|
+
from openinterp.core.takedowns import activate, load_takedowns
|
|
102
|
+
from openinterp.corpus import load_sources
|
|
103
|
+
from openinterp.crossref import load_rows as load_alignment
|
|
104
|
+
from openinterp.planner import configured_models
|
|
105
|
+
from openinterp.sisters import load_rows as load_sisters
|
|
106
|
+
from openinterp.wiring_backfill import load_rows
|
|
107
|
+
|
|
108
|
+
activate(load_takedowns(wiki_dir)) # before any text is scrubbed; workers fork after this
|
|
109
|
+
report = compile_site(
|
|
110
|
+
load_archive(wiki_dir),
|
|
111
|
+
output_dir,
|
|
112
|
+
wiring_rows=load_rows(wiring_path),
|
|
113
|
+
draws=load_draws(wiki_dir),
|
|
114
|
+
corpus_sources=load_sources(source_paths),
|
|
115
|
+
alignment_rows=load_alignment(alignment_path),
|
|
116
|
+
sister_rows=load_sisters(sisters_path),
|
|
117
|
+
papers_dir=papers_dir,
|
|
118
|
+
stops=load_stops(wiki_dir),
|
|
119
|
+
model_facts=load_model_facts(configured_models()), # config.json only, no weights
|
|
120
|
+
jobs=jobs or default_jobs(),
|
|
121
|
+
errata=load_errata(wiki_dir),
|
|
122
|
+
users=load_users(project_links()["repo_url"], wiki_dir),
|
|
123
|
+
coverage_rows=load_coverage(coverage_path),
|
|
124
|
+
)
|
|
125
|
+
click.echo(
|
|
126
|
+
f"Published {report.experiments_published} experiments: {len(report.pages)} pages, "
|
|
127
|
+
f"{report.parquet} → {output_dir}"
|
|
128
|
+
)
|
openinterp/cli_check.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""The ``check`` command: registry consistency, for CI and before a push."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from openinterp.cli import cli, wiki_dir_option
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@cli.command()
|
|
11
|
+
@wiki_dir_option()
|
|
12
|
+
@click.option(
|
|
13
|
+
"--base-ref",
|
|
14
|
+
help="Git ref to diff against (e.g. origin/main). Enforces write-once pages, and checks "
|
|
15
|
+
"only the branch's changes unless it also changes files outside the wiki.",
|
|
16
|
+
)
|
|
17
|
+
def check(wiki_dir, base_ref):
|
|
18
|
+
"""Check that every posted experiment has a valid record and wiki page (CI gate)."""
|
|
19
|
+
import os
|
|
20
|
+
import subprocess
|
|
21
|
+
|
|
22
|
+
from openinterp.checks import check_registry
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
report = check_registry(wiki_dir, base_ref=base_ref)
|
|
26
|
+
except subprocess.CalledProcessError as error:
|
|
27
|
+
raise click.ClickException(
|
|
28
|
+
f"can't diff against {base_ref} ({error.stderr.strip()}). "
|
|
29
|
+
"Fetch the ref, or run `open-interpretability check` to check every record."
|
|
30
|
+
) from error
|
|
31
|
+
in_actions = os.environ.get("GITHUB_ACTIONS") == "true"
|
|
32
|
+
for problem in report.problems:
|
|
33
|
+
if in_actions:
|
|
34
|
+
click.echo(f"::error file={problem.path}::{problem.message}")
|
|
35
|
+
else:
|
|
36
|
+
click.echo(f"error: {problem}", err=True)
|
|
37
|
+
|
|
38
|
+
summary = (
|
|
39
|
+
f"Checked {report.records} experiment records and {report.pages} experiment pages"
|
|
40
|
+
+ "".join(f" and {n} {kind} records" for kind, n in report.extra_counts.items() if n)
|
|
41
|
+
+ (f" changed since {base_ref}" if report.changed_only else "")
|
|
42
|
+
+ ": "
|
|
43
|
+
+ ("all consistent." if report.ok else f"{len(report.problems)} problem(s).")
|
|
44
|
+
)
|
|
45
|
+
click.echo(summary)
|
|
46
|
+
if in_actions and os.environ.get("GITHUB_STEP_SUMMARY"):
|
|
47
|
+
with open(os.environ["GITHUB_STEP_SUMMARY"], "a", encoding="utf-8") as fh:
|
|
48
|
+
fh.write(f"### Experiment check\n\n{summary}\n\n")
|
|
49
|
+
fh.writelines(f"- `{p.path}`: {p.message}\n" for p in report.problems)
|
|
50
|
+
if not report.ok:
|
|
51
|
+
raise SystemExit(1)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""``open-interpretability concepts``: a labelled concept set from an annotated dataset.
|
|
2
|
+
|
|
3
|
+
See :mod:`openinterp.concepts` for the presets and how labels become spans.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from openinterp.cli import cli
|
|
13
|
+
from openinterp.concepts import CONCEPT_PRESETS
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@cli.command()
|
|
17
|
+
@click.option("--dataset", "preset", required=True, type=click.Choice(list(CONCEPT_PRESETS)))
|
|
18
|
+
@click.option(
|
|
19
|
+
"--label",
|
|
20
|
+
help="The label to mark (PER, NOUN, nsubj, fr, Sports). Omit it to list the split's "
|
|
21
|
+
"labels and how many words or documents carry each.",
|
|
22
|
+
)
|
|
23
|
+
@click.option("--split", help="Dataset split. Default: the preset's held-out one.")
|
|
24
|
+
@click.option("--subset", help="Universal Dependencies treebank (default en_ewt).")
|
|
25
|
+
@click.option("--column", help="Read labels from this column instead (e.g. UD's xpos).")
|
|
26
|
+
@click.option("--docs", "documents", default=1000, show_default=True, type=click.IntRange(1))
|
|
27
|
+
@click.option("--seed", default=0, show_default=True, type=int)
|
|
28
|
+
@click.option(
|
|
29
|
+
"--max-chars",
|
|
30
|
+
default=3000,
|
|
31
|
+
show_default=True,
|
|
32
|
+
type=click.IntRange(1),
|
|
33
|
+
help="Join sentences into documents of at most this many characters.",
|
|
34
|
+
)
|
|
35
|
+
@click.option("--out", type=click.Path(path_type=Path), help="Concept set JSONL.")
|
|
36
|
+
def concepts(preset, label, split, subset, column, documents, seed, max_chars, out):
|
|
37
|
+
"""Write a concept set from human-annotated labels.
|
|
38
|
+
|
|
39
|
+
The set is JSON lines of {"text": ..., "spans": [[start, end], ...]}. Use it for
|
|
40
|
+
`open-interpretability probe-compare --train/--test`, sparse-probing searches and reviewers'
|
|
41
|
+
positive holdouts.
|
|
42
|
+
|
|
43
|
+
Word tags (conll2003-*, ud-*) mark each tagged word; document classes
|
|
44
|
+
(language-identification, ag_news) mark whole documents, half of them of the class.
|
|
45
|
+
Also writes <name>.source.json, which pins the dataset commit, split and licence.
|
|
46
|
+
"""
|
|
47
|
+
from openinterp.concepts import build_concept, load_split
|
|
48
|
+
|
|
49
|
+
if label is None:
|
|
50
|
+
loaded = load_split(preset, split=split, subset=subset, column=column, max_chars=max_chars)
|
|
51
|
+
click.echo(
|
|
52
|
+
f"{loaded.dataset}@{loaded.revision[:8]} {loaded.files}: {len(loaded.docs)} docs"
|
|
53
|
+
)
|
|
54
|
+
for tag, n in loaded.counts().most_common():
|
|
55
|
+
click.echo(f"{n:>8,} {tag}")
|
|
56
|
+
return
|
|
57
|
+
if out is None:
|
|
58
|
+
raise click.UsageError("--out is required with --label.")
|
|
59
|
+
try:
|
|
60
|
+
source = build_concept(
|
|
61
|
+
preset,
|
|
62
|
+
label,
|
|
63
|
+
out,
|
|
64
|
+
split=split,
|
|
65
|
+
subset=subset,
|
|
66
|
+
column=column,
|
|
67
|
+
documents=documents,
|
|
68
|
+
seed=seed,
|
|
69
|
+
max_chars=max_chars,
|
|
70
|
+
)
|
|
71
|
+
except ValueError as exc:
|
|
72
|
+
raise click.ClickException(str(exc)) from exc
|
|
73
|
+
click.echo(f"Wrote {out}: {source}")
|
|
74
|
+
if source.skipped_sentences:
|
|
75
|
+
click.echo(f"warning: {source.skipped_sentences} sentences' words not found", err=True)
|
|
76
|
+
click.echo(f"Licence: {source.license or 'not stated on the dataset card'}")
|
openinterp/cli_corpus.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""``open-interpretability corpus``: build a scan corpus from a Hugging Face dataset."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
from click.core import ParameterSource
|
|
9
|
+
|
|
10
|
+
from openinterp.blends import BLEND_ALIASES, BLENDS, DEFAULT_DATASET
|
|
11
|
+
from openinterp.cli import cli
|
|
12
|
+
from openinterp.corpus import LAYOUTS, PRESETS
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@cli.command()
|
|
16
|
+
@click.option(
|
|
17
|
+
"--dataset",
|
|
18
|
+
default=DEFAULT_DATASET,
|
|
19
|
+
show_default=True,
|
|
20
|
+
help=f"A blend of presets ({', '.join([*BLEND_ALIASES, *BLENDS])}; '{DEFAULT_DATASET}' is "
|
|
21
|
+
f"the latest), a preset ({', '.join(PRESETS)}) or a Hugging Face dataset ID (then pass "
|
|
22
|
+
"--files).",
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
"--files",
|
|
26
|
+
help="Glob of Parquet files within the dataset; comma-separate several to take an equal "
|
|
27
|
+
"share of documents from each. Default: the preset's.",
|
|
28
|
+
)
|
|
29
|
+
@click.option(
|
|
30
|
+
"--text-column",
|
|
31
|
+
help="Column holding the text; comma-separate several to join them into one document. "
|
|
32
|
+
"Default: the preset's, or 'text'.",
|
|
33
|
+
)
|
|
34
|
+
@click.option(
|
|
35
|
+
"--revision",
|
|
36
|
+
help="Dataset branch, tag or commit. Default: the preset's, or main; pinned on use.",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--layout",
|
|
40
|
+
type=click.Choice(list(LAYOUTS)),
|
|
41
|
+
help="Join rows into documents this way, e.g. one WikiText row per paragraph. Default: "
|
|
42
|
+
"the preset's, or one document per row.",
|
|
43
|
+
)
|
|
44
|
+
@click.option("--docs", "documents", default=500, show_default=True, type=click.IntRange(1))
|
|
45
|
+
@click.option("--seed", default=0, show_default=True, type=int)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--max-chars",
|
|
48
|
+
default=3000,
|
|
49
|
+
show_default=True,
|
|
50
|
+
type=click.IntRange(1),
|
|
51
|
+
help="Cut each document to this many characters.",
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"--docs-per-row-group",
|
|
55
|
+
type=click.IntRange(1),
|
|
56
|
+
help="Documents taken from each Parquet row group read; lower spreads the sample wider. "
|
|
57
|
+
"Default: the preset's, or 20.",
|
|
58
|
+
)
|
|
59
|
+
@click.option(
|
|
60
|
+
"--first",
|
|
61
|
+
is_flag=True,
|
|
62
|
+
help="Take the dataset's first --docs documents in file order, cut but not stripped, "
|
|
63
|
+
"instead of a seeded sample.",
|
|
64
|
+
)
|
|
65
|
+
@click.option(
|
|
66
|
+
"--ascii",
|
|
67
|
+
"ascii_",
|
|
68
|
+
is_flag=True,
|
|
69
|
+
help="Escape non-ASCII characters in the JSONL. With --first, rebuilds the registry's "
|
|
70
|
+
"corpus from pile-10k (README).",
|
|
71
|
+
)
|
|
72
|
+
@click.option(
|
|
73
|
+
"--lang-pattern",
|
|
74
|
+
help="Regular expression whose group, matched in each --files glob, is the language its "
|
|
75
|
+
"documents record as 'lang' (e.g. '^\\d+\\.(\\w+)/' for Wikipedia). Default: the preset's.",
|
|
76
|
+
)
|
|
77
|
+
@click.option(
|
|
78
|
+
"--detect-lang",
|
|
79
|
+
is_flag=True,
|
|
80
|
+
help="Detect each document's language (fastText lid.176, downloaded once) and record "
|
|
81
|
+
"it as 'lang' where the detector is sure, for datasets that don't say. The source "
|
|
82
|
+
"sidecar records the detector. Replaces a preset's exact languages; not with --lang-pattern.",
|
|
83
|
+
)
|
|
84
|
+
@click.option(
|
|
85
|
+
"--detect-code",
|
|
86
|
+
is_flag=True,
|
|
87
|
+
help="Detect each document's programming language (Magika) and record it as "
|
|
88
|
+
"'code_language' where the detector is sure, for datasets that don't say (e.g. the "
|
|
89
|
+
"Pile's GitHub files). Prose stays unlabelled. The source sidecar records the "
|
|
90
|
+
"detector. Not with a preset that gives exact programming languages.",
|
|
91
|
+
)
|
|
92
|
+
@click.option(
|
|
93
|
+
"--chat-template",
|
|
94
|
+
metavar="MODEL",
|
|
95
|
+
help="Write each conversation in --text-column (a list of role/content messages) with "
|
|
96
|
+
"this model's chat template, pinned to its commit. Default: the preset's ("
|
|
97
|
+
+ ", ".join(f"{name}: {p.chat_template}" for name, p in PRESETS.items() if p.chat_template)
|
|
98
|
+
+ "), or none.",
|
|
99
|
+
)
|
|
100
|
+
@click.option(
|
|
101
|
+
"--same-as",
|
|
102
|
+
type=click.Path(exists=True, dir_okay=False, path_type=Path),
|
|
103
|
+
help="Rebuild the corpus this record scanned, at its pinned dataset commits, and check "
|
|
104
|
+
"its SHA-256. It sets the source, so only --out goes with it.",
|
|
105
|
+
)
|
|
106
|
+
@click.option(
|
|
107
|
+
"--out", default=Path("corpus.jsonl"), show_default=True, type=click.Path(path_type=Path)
|
|
108
|
+
)
|
|
109
|
+
@click.pass_context
|
|
110
|
+
def corpus(
|
|
111
|
+
ctx,
|
|
112
|
+
dataset,
|
|
113
|
+
files,
|
|
114
|
+
text_column,
|
|
115
|
+
revision,
|
|
116
|
+
layout,
|
|
117
|
+
documents,
|
|
118
|
+
seed,
|
|
119
|
+
max_chars,
|
|
120
|
+
docs_per_row_group,
|
|
121
|
+
first,
|
|
122
|
+
ascii_,
|
|
123
|
+
lang_pattern,
|
|
124
|
+
detect_lang,
|
|
125
|
+
detect_code,
|
|
126
|
+
chat_template,
|
|
127
|
+
same_as,
|
|
128
|
+
out,
|
|
129
|
+
):
|
|
130
|
+
"""Sample a scan corpus from a Hugging Face dataset, without downloading all of it.
|
|
131
|
+
|
|
132
|
+
Writes <out> (one {"text": ...} per line) and <name>.source.json next to it, which
|
|
133
|
+
pins the dataset commit, files, seed and licence. `open-interpretability audit --corpus <out>`
|
|
134
|
+
records that source in the submission's provenance.
|
|
135
|
+
"""
|
|
136
|
+
from openinterp.corpus import build_from_hub
|
|
137
|
+
|
|
138
|
+
if same_as:
|
|
139
|
+
return _same_as(ctx, same_as, out)
|
|
140
|
+
if dataset in BLENDS or dataset in BLEND_ALIASES:
|
|
141
|
+
per_dataset = {
|
|
142
|
+
"--files": files, "--text-column": text_column, "--revision": revision,
|
|
143
|
+
"--layout": layout, "--docs-per-row-group": docs_per_row_group, "--first": first,
|
|
144
|
+
"--lang-pattern": lang_pattern, "--detect-lang": detect_lang,
|
|
145
|
+
"--detect-code": detect_code, "--chat-template": chat_template,
|
|
146
|
+
} # fmt: skip
|
|
147
|
+
return _blend(dataset, per_dataset, out, documents, seed, max_chars, ascii_)
|
|
148
|
+
preset = PRESETS.get(dataset)
|
|
149
|
+
_check_dataset(dataset, preset, files, lang_pattern, detect_lang, detect_code)
|
|
150
|
+
try:
|
|
151
|
+
source = build_from_hub(
|
|
152
|
+
preset.dataset if preset else dataset,
|
|
153
|
+
out,
|
|
154
|
+
files=files or preset.files,
|
|
155
|
+
text_column=text_column or (preset.text_column if preset else "text"),
|
|
156
|
+
revision=revision or (preset.revision if preset else None),
|
|
157
|
+
layout=layout or (preset.layout if preset else None),
|
|
158
|
+
documents=documents,
|
|
159
|
+
seed=seed,
|
|
160
|
+
max_chars=max_chars,
|
|
161
|
+
docs_per_row_group=docs_per_row_group or (preset.docs_per_row_group if preset else 20),
|
|
162
|
+
first=first,
|
|
163
|
+
ascii=ascii_,
|
|
164
|
+
lang_pattern=None if detect_lang else lang_pattern or (preset and preset.lang_pattern),
|
|
165
|
+
detect_lang=detect_lang,
|
|
166
|
+
code_language_column=preset.code_language_column if preset else None,
|
|
167
|
+
detect_code=detect_code,
|
|
168
|
+
chat_template=chat_template or (preset.chat_template if preset else None),
|
|
169
|
+
)
|
|
170
|
+
except ValueError as error: # e.g. a model without a chat template
|
|
171
|
+
raise click.ClickException(str(error)) from error
|
|
172
|
+
_report(source, out, documents)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _check_dataset(dataset, preset, files, lang_pattern, detect_lang, detect_code) -> None:
|
|
176
|
+
"""Raise ``click.UsageError`` if the options can't sample ``dataset``."""
|
|
177
|
+
if detect_lang and lang_pattern:
|
|
178
|
+
raise click.UsageError("--detect-lang and --lang-pattern both set the languages.")
|
|
179
|
+
if detect_code and preset and preset.code_language_column:
|
|
180
|
+
raise click.UsageError(f"{dataset!r} has exact programming languages: no --detect-code.")
|
|
181
|
+
if preset is None and not files:
|
|
182
|
+
raise click.UsageError(f"--files is required for {dataset!r}, which is not a preset.")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@cli.command("corpus-cache")
|
|
186
|
+
@click.option("--clear", is_flag=True, help="Delete everything cached.")
|
|
187
|
+
def corpus_cache(clear):
|
|
188
|
+
"""Show the size of (or clear) the cache of Parquet data that `corpus` reads.
|
|
189
|
+
|
|
190
|
+
\b
|
|
191
|
+
Location: $OPENINTERP_CORPUS_CACHE (\"off\" disables it), else
|
|
192
|
+
$XDG_CACHE_HOME/openinterp/corpora or ~/.cache/openinterp/corpora.
|
|
193
|
+
Size cap: $OPENINTERP_CORPUS_CACHE_GB (default 5); least recently used go first.
|
|
194
|
+
"""
|
|
195
|
+
from openinterp.corpus_cache import ParquetCache
|
|
196
|
+
|
|
197
|
+
cache = ParquetCache.default()
|
|
198
|
+
if cache is None:
|
|
199
|
+
click.echo("The corpus cache is off ($OPENINTERP_CORPUS_CACHE).")
|
|
200
|
+
return
|
|
201
|
+
if clear:
|
|
202
|
+
click.echo(f"Deleted {cache.clear()} entries from {cache.root}")
|
|
203
|
+
return
|
|
204
|
+
click.echo(
|
|
205
|
+
f"{cache.root}: {len(cache.entries())} entries, "
|
|
206
|
+
f"{cache.size() / 1e9:.2f} of {cache.max_bytes / 1e9:.0f} GB"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _same_as(ctx, record: Path, out: Path) -> None:
|
|
211
|
+
from openinterp.cli_review import load_submission
|
|
212
|
+
from openinterp.corpus_rebuild import rebuild, scanned_source
|
|
213
|
+
|
|
214
|
+
given = [
|
|
215
|
+
name
|
|
216
|
+
for name in ctx.params
|
|
217
|
+
if name not in ("same_as", "out")
|
|
218
|
+
and ctx.get_parameter_source(name) != ParameterSource.DEFAULT
|
|
219
|
+
]
|
|
220
|
+
if given:
|
|
221
|
+
raise click.UsageError(f"--same-as sets the source, so not with: {', '.join(given)}.")
|
|
222
|
+
try:
|
|
223
|
+
source = rebuild(scanned_source(load_submission(record)), out)
|
|
224
|
+
except ValueError as error:
|
|
225
|
+
raise click.ClickException(f"{record}: {error}") from error
|
|
226
|
+
_report(source, out, source.documents)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _blend(dataset, per_dataset: dict, out: Path, documents, seed, max_chars, ascii_) -> None:
|
|
230
|
+
from openinterp.blends import build_blend
|
|
231
|
+
|
|
232
|
+
if given := [name for name, value in per_dataset.items() if value]:
|
|
233
|
+
raise click.UsageError(
|
|
234
|
+
f"{', '.join(given)}: set per preset, so not with the blend {dataset!r}."
|
|
235
|
+
)
|
|
236
|
+
source = build_blend(
|
|
237
|
+
dataset, out, documents=documents, seed=seed, max_chars=max_chars, ascii=ascii_
|
|
238
|
+
)
|
|
239
|
+
_report(source, out, documents)
|
|
240
|
+
for part in source.components:
|
|
241
|
+
click.echo(f" {part.documents} from {part}")
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _report(source, out: Path, documents: int) -> None:
|
|
245
|
+
click.echo(f"Wrote {source.documents} documents to {out}: {source}")
|
|
246
|
+
if source.lang_detector:
|
|
247
|
+
click.echo(f"Languages detected by {source.lang_detector}", err=True)
|
|
248
|
+
if source.code_detector:
|
|
249
|
+
click.echo(f"Programming languages detected by {source.code_detector}", err=True)
|
|
250
|
+
if source.documents < documents:
|
|
251
|
+
click.echo(f"warning: only {source.documents} of {documents} documents found", err=True)
|
|
252
|
+
click.echo(f"Licence: {source.license or 'not stated on the dataset card'}")
|