interp-engine 1.3.2__tar.gz → 1.3.4__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.
- {interp_engine-1.3.2 → interp_engine-1.3.4}/.gitignore +4 -1
- {interp_engine-1.3.2 → interp_engine-1.3.4}/PKG-INFO +7 -4
- {interp_engine-1.3.2 → interp_engine-1.3.4}/README.md +5 -2
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/INTERNALS.md +6 -0
- interp_engine-1.3.4/interp_engine/notebook_stdout.py +90 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_backend.py +4 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/pyproject.toml +2 -2
- interp_engine-1.3.4/tests/test_notebook_stdout.py +132 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/LICENSE +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/README.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/__init__.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/bench_spec.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/cells.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/probe.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/probe_lens_stream.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/publish.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/report_bench.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__eager.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__vllm-cudagraph.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__vllm-dspark-cudagraph.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__vllm-dspark.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__vllm-static.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__vllm.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/gemma-2-2b__eager.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/gemma-2-2b__vllm-cudagraph.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/gemma-2-2b__vllm-static.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/gemma-2-2b__vllm.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/llama-3.1-8b__eager.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/llama-3.1-8b__vllm-cudagraph.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/llama-3.1-8b__vllm-static.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/llama-3.1-8b__vllm.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3-4b__eager.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3-4b__vllm-cudagraph.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3-4b__vllm-static.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3-4b__vllm.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3.8-27b__eager.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3.8-27b__vllm-cudagraph.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3.8-27b__vllm-static.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3.8-27b__vllm.json +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results-latest.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/run_all.sh +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/run_bench.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/workloads.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/AGENT_INTEGRATION.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/ARCHITECTURE_QUIRKS.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/COMPATIBILITY.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/ENGINE_HOOK_MAPPINGS.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/GRADIENTS.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/PERFORMANCE.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/PORTING.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/README.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/SUPPORTED_POINTS.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/docs/USAGE.md +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/__init__.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/_loop.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/address.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/arch.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/attn_config.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/attn_scores.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/autograd_support.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/capture.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/chat_compose.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/chat_conventions.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/chat_formatters.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/cuda_preflight.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/dispatch.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/facts.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/hooks.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/lens.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/load.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/mappers.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/model.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/moe_routing.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/points.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/protocol.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/residual_basis.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/select.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/steer.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/steer_specs.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/sync.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/tokenize.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/__init__.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/_demux.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/_hooks.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/_payload.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/_tree.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/attn.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/capture.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/graphs.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/lens/__init__.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/lens/intervene.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/lens/readout.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/lens/unembed.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/mhc.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/native.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/requests.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/static.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_capture/steering.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/interp_engine/vllm_plugin.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/conftest.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/harness.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/model_expectations.yaml +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/synthetic_families.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_address.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_attn_config_tripwire.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_attn_probs_indexing.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_attn_scores.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_attn_z_gqa.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_autograd_support.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_bench_workloads.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_capability_refusals.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_capture_addressing.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_chat_compose.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_chat_formatters.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_chat_templates.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_core.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_cuda_preflight.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_doc_code_fences.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_eager_autograd.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_facts.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_family_points.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_gated_attn_out.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_head_contributions.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_hook_call_conventions.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_layer_kinds.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_load.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_logit_transform.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_mappers.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_mlp_internals.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_model_expectations.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_moe.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_multimodal_arch.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_new_models_gpu.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_no_chat_template.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_normalized_hook.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_packaging.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_parity_gpt2.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_per_layer_attn_dims.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_points_registry.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_protocol.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_published_benchmarks.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_qk_norm.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_qkv_layout.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_reasoning_spans.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_release.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_resid_mid.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_residual_basis.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_sandwich_norms.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_select.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_sliding_window_attn.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_small_models_gpu.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_static_dsv4_gpu.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_static_parity_gpu.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_static_set.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_static_warmup.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_steer_context.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_steer_math_parity.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_sync_loop.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_sync_parity.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_unified_free_functions.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_unresolved_families.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_capture_gpu.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_capture_scales.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_engine_loop.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_graph_path.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_graphs_on_gpu.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_hook_availability.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_hyper_connections.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_kv_isolation.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_new_points.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_only_families.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_plugin.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vllm_wire_grammar.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_vocabulary_boundary.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_worker_lens_capture_readout.py +0 -0
- {interp_engine-1.3.2 → interp_engine-1.3.4}/tests/test_worker_lens_readout.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: interp-engine
|
|
3
|
-
Version: 1.3.
|
|
4
|
-
Summary: A fast, standardized
|
|
3
|
+
Version: 1.3.4
|
|
4
|
+
Summary: A fast, standardized, and easy to use interpretability engine.
|
|
5
5
|
Project-URL: Homepage, https://github.com/decoderesearch/interp-engine
|
|
6
6
|
Project-URL: Repository, https://github.com/decoderesearch/interp-engine
|
|
7
7
|
Project-URL: Issues, https://github.com/decoderesearch/interp-engine/issues
|
|
@@ -44,10 +44,13 @@ Description-Content-Type: text/markdown
|
|
|
44
44
|
<a href="https://join.slack.com/t/opensourcemechanistic/shared_invite/zt-3z9o0hxjl-MDX9pbATO2qESOazNDLpdQ"><img src="https://img.shields.io/badge/Slack-Open%20Source%20Mechanistic%20Interpretability-4A154B?logo=slack&logoColor=white" alt="Join the Slack"></a>
|
|
45
45
|
</p>
|
|
46
46
|
|
|
47
|
-
`interp-engine` is an interpretability engine that is fast
|
|
47
|
+
`interp-engine` is an interpretability engine that is fast, standardized (34 'points'/addresses across architectures), and easy to use and debug. It powers all of [Neuronpedia](https://neuronpedia.org)'s inference and is checked for accuracy against HF Transformers and other engines.
|
|
48
48
|
|
|
49
49
|
<p align="center">
|
|
50
|
-
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/ie-
|
|
50
|
+
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/ie-benchmark.gif" alt="benchmark between ie and transformers" width="100%">
|
|
51
|
+
</p>
|
|
52
|
+
<p align="center">
|
|
53
|
+
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/toks.png" alt="Tokens per second while capturing and generating: eager against IE-vLLM and IE-vLLM-static on qwen3.8-27b and deepseek-v4-flash-0731, 8 requests in flight" width="100%">
|
|
51
54
|
</p>
|
|
52
55
|
<p align="center">
|
|
53
56
|
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/interp-engine-demo.gif" alt="interp-engine demo gif" width="100%">
|
|
@@ -13,10 +13,13 @@
|
|
|
13
13
|
<a href="https://join.slack.com/t/opensourcemechanistic/shared_invite/zt-3z9o0hxjl-MDX9pbATO2qESOazNDLpdQ"><img src="https://img.shields.io/badge/Slack-Open%20Source%20Mechanistic%20Interpretability-4A154B?logo=slack&logoColor=white" alt="Join the Slack"></a>
|
|
14
14
|
</p>
|
|
15
15
|
|
|
16
|
-
`interp-engine` is an interpretability engine that is fast
|
|
16
|
+
`interp-engine` is an interpretability engine that is fast, standardized (34 'points'/addresses across architectures), and easy to use and debug. It powers all of [Neuronpedia](https://neuronpedia.org)'s inference and is checked for accuracy against HF Transformers and other engines.
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/ie-
|
|
19
|
+
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/ie-benchmark.gif" alt="benchmark between ie and transformers" width="100%">
|
|
20
|
+
</p>
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/toks.png" alt="Tokens per second while capturing and generating: eager against IE-vLLM and IE-vLLM-static on qwen3.8-27b and deepseek-v4-flash-0731, 8 requests in flight" width="100%">
|
|
20
23
|
</p>
|
|
21
24
|
<p align="center">
|
|
22
25
|
<img src="https://neuronpedia.s3.amazonaws.com/site-assets/interp-engine-demo.gif" alt="interp-engine demo gif" width="100%">
|
|
@@ -66,6 +66,12 @@ files and why they are where they are.
|
|
|
66
66
|
- `LD_LIBRARY_PATH`) before the first CUDA call, instead of failing ten frames deep in
|
|
67
67
|
`torch.cuda._lazy_init`. Lives here because every app on the engine inherits the same CUDA
|
|
68
68
|
floor — the `[vllm]` wheels link `libcudart.so.13` directly.
|
|
69
|
+
- `notebook_stdout.py` — `ensure_stdout_descriptor`: gives a notebook kernel's `sys.stdout` the file
|
|
70
|
+
descriptor vLLM's engine start needs. vLLM silences C-level output by dup'ing over one and forks
|
|
71
|
+
its EngineCore child, so under ipykernel — whose stream writes to a socket and has none — the
|
|
72
|
+
child dies before it loads anything, and the caller is told to see a root cause that is in another
|
|
73
|
+
process. Called from `_ensure_engine`; a no-op in a script, a server, or a kernel that captured
|
|
74
|
+
the real descriptors itself.
|
|
69
75
|
|
|
70
76
|
## Correctness
|
|
71
77
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Give a notebook kernel's stdout the file descriptor vLLM's engine start needs.
|
|
2
|
+
|
|
3
|
+
vLLM silences C-level output around ``torch.distributed.new_group`` by dup'ing over a
|
|
4
|
+
descriptor (``suppress_stdout`` in ``vllm/utils/system_utils.py``), and its EngineCore
|
|
5
|
+
child is forked, so the child inherits whichever ``sys.stdout`` the parent had. Under
|
|
6
|
+
Jupyter that is ``ipykernel.iostream.OutStream``, which writes through a ZMQ socket and
|
|
7
|
+
raises ``io.UnsupportedOperation`` from ``fileno()``. The child then dies before it loads
|
|
8
|
+
anything, and what reaches the caller is vLLM's ``Engine core initialization failed. See
|
|
9
|
+
root cause above.`` -- above being a traceback in another process, about a descriptor.
|
|
10
|
+
|
|
11
|
+
A descriptor is what that stream is supposed to hand back: ipykernel answers ``fileno()``
|
|
12
|
+
with ``_original_stdstream_copy``, a dup of the real stdout it took over, whenever the
|
|
13
|
+
kernel was started capturing the low-level ones. This supplies the one a kernel that was
|
|
14
|
+
not started that way -- Colab's -- did not keep. Colab is the case that matters, because
|
|
15
|
+
this repo's own notebook templates run there.
|
|
16
|
+
|
|
17
|
+
The descriptor stays on the stream rather than being restored after the engine is built.
|
|
18
|
+
The fork is not the only caller: vLLM suppresses stdout the same way around its stateless
|
|
19
|
+
process groups, from whichever process reaches one.
|
|
20
|
+
|
|
21
|
+
Forcing ``spawn`` would also give the child a stdout of its own, and is what
|
|
22
|
+
``VLLM_WORKER_MULTIPROC_METHOD`` is for. It is not what this does, because a spawned
|
|
23
|
+
child writes to the kernel's real stdout rather than to the cell -- which takes the engine
|
|
24
|
+
logs, and the root cause behind that message, out of the notebook with it.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import logging
|
|
30
|
+
import os
|
|
31
|
+
import sys
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _answers_fileno(stream: object) -> bool:
|
|
37
|
+
"""Whether ``stream.fileno()`` returns rather than raises.
|
|
38
|
+
|
|
39
|
+
``io.UnsupportedOperation`` is both an ``OSError`` and a ``ValueError``, which is what
|
|
40
|
+
a kernel stream raises; a detached or closed one raises ``ValueError`` on its own.
|
|
41
|
+
"""
|
|
42
|
+
try:
|
|
43
|
+
stream.fileno() # type: ignore[attr-defined]
|
|
44
|
+
except (AttributeError, OSError, ValueError):
|
|
45
|
+
return False
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _process_stdout_fd() -> int | None:
|
|
50
|
+
"""The descriptor this process's stdout is, or None when it has none.
|
|
51
|
+
|
|
52
|
+
``sys.__stdout__`` is the stream Python opened at startup, which Jupyter leaves alone
|
|
53
|
+
when it replaces ``sys.stdout``, so it is the first place to ask. Fd 1 covers an
|
|
54
|
+
embedding that replaced both. Either is confirmed with ``fstat`` before being handed
|
|
55
|
+
out, since a daemonized process may have closed it.
|
|
56
|
+
"""
|
|
57
|
+
original = sys.__stdout__
|
|
58
|
+
fd = original.fileno() if original is not None and _answers_fileno(original) else 1
|
|
59
|
+
try:
|
|
60
|
+
os.fstat(fd)
|
|
61
|
+
except OSError:
|
|
62
|
+
return None
|
|
63
|
+
return fd
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ensure_stdout_descriptor() -> bool:
|
|
67
|
+
"""Give ``sys.stdout`` a ``fileno()`` if it has none, and say whether it needed one.
|
|
68
|
+
|
|
69
|
+
Idempotent, and a no-op outside a notebook. A stream that already answers is left
|
|
70
|
+
alone, and so is a process whose stdout is closed: there is no descriptor to offer
|
|
71
|
+
there, and vLLM's refusal is then the honest outcome rather than one to work around.
|
|
72
|
+
"""
|
|
73
|
+
stream = sys.stdout
|
|
74
|
+
if stream is None or _answers_fileno(stream):
|
|
75
|
+
return False
|
|
76
|
+
fd = _process_stdout_fd()
|
|
77
|
+
if fd is None:
|
|
78
|
+
return False
|
|
79
|
+
try:
|
|
80
|
+
stream.fileno = lambda: fd # type: ignore[method-assign]
|
|
81
|
+
except (AttributeError, TypeError):
|
|
82
|
+
# A stream that takes no new attribute, which a C-level or slotted one does not.
|
|
83
|
+
# Nothing is lost: this is the refusal vLLM was about to raise anyway.
|
|
84
|
+
return False
|
|
85
|
+
logger.info(
|
|
86
|
+
"%s has no file descriptor, which vLLM's engine start requires; answering fileno() with fd %d.",
|
|
87
|
+
type(stream).__name__,
|
|
88
|
+
fd,
|
|
89
|
+
)
|
|
90
|
+
return True
|
|
@@ -30,6 +30,7 @@ from interp_engine import facts
|
|
|
30
30
|
from interp_engine._loop import refuse_foreign_loop
|
|
31
31
|
from interp_engine.address import Address, format_address, to_address
|
|
32
32
|
from interp_engine.autograd_support import GradSupport, vllm_grad_support
|
|
33
|
+
from interp_engine.notebook_stdout import ensure_stdout_descriptor
|
|
33
34
|
from interp_engine.points import d_model_wide, hyper_connection_names, refusal_reasons
|
|
34
35
|
from interp_engine.points import steer_refusal_reason as points_steer_refusal
|
|
35
36
|
from interp_engine.residual_basis import ResidualBasis, vllm_residual_basis
|
|
@@ -1213,6 +1214,9 @@ class VLLMModel:
|
|
|
1213
1214
|
tuple(getattr(self, "_static_reads", ())),
|
|
1214
1215
|
tuple(getattr(self, "_static_writes", ())),
|
|
1215
1216
|
)
|
|
1217
|
+
# The line below forks a child that suppresses stdout by descriptor, which a
|
|
1218
|
+
# notebook kernel's stdout does not have. See `notebook_stdout`.
|
|
1219
|
+
ensure_stdout_descriptor()
|
|
1216
1220
|
self.engine = AsyncLLM.from_engine_args(AsyncEngineArgs(**self._engine_kwargs))
|
|
1217
1221
|
self._engine_loop = asyncio.get_running_loop()
|
|
1218
1222
|
return self.engine
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "interp-engine"
|
|
3
|
-
version = "1.3.
|
|
4
|
-
description = "A fast, standardized
|
|
3
|
+
version = "1.3.4"
|
|
4
|
+
description = "A fast, standardized, and easy to use interpretability engine."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
license-files = ["LICENSE"]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Unit tests for the stdout descriptor a notebook kernel does not provide.
|
|
2
|
+
|
|
3
|
+
No vLLM and no GPU: what is under test is a property of ``sys.stdout``, and the stream
|
|
4
|
+
that has that property in the field -- ipykernel's ``OutStream`` -- is stood in for by a
|
|
5
|
+
class which raises from ``fileno()`` the same way. The engine-shaped half is a vLLM engine
|
|
6
|
+
started under such a stream, which fails in the EngineCore child rather than here.
|
|
7
|
+
|
|
8
|
+
``sys.stdout`` is replaced **inside each test body** rather than by a fixture. pytest
|
|
9
|
+
captures at the descriptor level and reassigns ``sys.stdout`` every time it resumes
|
|
10
|
+
capture, including on the way from setup into the call phase -- so a patch applied in a
|
|
11
|
+
fixture is gone by the time the test runs, and the test passes or fails on the runner's
|
|
12
|
+
stream instead of the one it meant to use.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import io
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
from typing import IO, Any
|
|
21
|
+
|
|
22
|
+
import pytest
|
|
23
|
+
|
|
24
|
+
from interp_engine.notebook_stdout import ensure_stdout_descriptor
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class KernelStdout:
|
|
28
|
+
"""``ipykernel.iostream.OutStream``, as far as this matters.
|
|
29
|
+
|
|
30
|
+
Writes go somewhere that is not a file -- a ZMQ socket, in the real one -- so there is
|
|
31
|
+
no descriptor to answer with, which is the whole of the failure being reproduced.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
self.written: list[str] = []
|
|
36
|
+
|
|
37
|
+
def write(self, text: str) -> int:
|
|
38
|
+
self.written.append(text)
|
|
39
|
+
return len(text)
|
|
40
|
+
|
|
41
|
+
def flush(self) -> None:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def fileno(self) -> int:
|
|
45
|
+
raise io.UnsupportedOperation("fileno")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SlottedStdout:
|
|
49
|
+
"""A stream that takes no new attribute, as a C-level one does not."""
|
|
50
|
+
|
|
51
|
+
__slots__ = ()
|
|
52
|
+
|
|
53
|
+
def fileno(self) -> int:
|
|
54
|
+
raise io.UnsupportedOperation("fileno")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _as_stdout(monkeypatch: pytest.MonkeyPatch, stream: object) -> None:
|
|
58
|
+
"""Make ``stream`` this test's ``sys.stdout``. Call from the test body; see above."""
|
|
59
|
+
monkeypatch.setattr(sys, "stdout", stream)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_a_kernel_stream_gains_a_descriptor_the_os_accepts(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
63
|
+
"""The point of the exercise: ``fileno()`` answers, and with a live descriptor.
|
|
64
|
+
|
|
65
|
+
``fstat`` is the assertion rather than a particular number, because what vLLM does
|
|
66
|
+
with the answer is ``os.dup``, which fails on anything ``fstat`` would reject too.
|
|
67
|
+
"""
|
|
68
|
+
_as_stdout(monkeypatch, KernelStdout())
|
|
69
|
+
assert ensure_stdout_descriptor() is True
|
|
70
|
+
os.fstat(sys.stdout.fileno())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_writes_still_go_where_they_did(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
74
|
+
"""A descriptor is added; nothing is redirected. The cell keeps its output."""
|
|
75
|
+
stream = KernelStdout()
|
|
76
|
+
_as_stdout(monkeypatch, stream)
|
|
77
|
+
ensure_stdout_descriptor()
|
|
78
|
+
print("to the notebook")
|
|
79
|
+
assert "to the notebook" in "".join(stream.written)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_it_is_idempotent(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
83
|
+
"""Every engine build calls this, and only the first one has anything to do."""
|
|
84
|
+
_as_stdout(monkeypatch, KernelStdout())
|
|
85
|
+
assert ensure_stdout_descriptor() is True
|
|
86
|
+
assert ensure_stdout_descriptor() is False
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_a_real_stream_is_left_alone(monkeypatch: pytest.MonkeyPatch, tmp_path: Any) -> None:
|
|
90
|
+
"""A script's stdout already answers, so this must not touch it.
|
|
91
|
+
|
|
92
|
+
The second assertion is what says *untouched* rather than merely still working: a
|
|
93
|
+
descriptor of our own, put on the instance, would satisfy the first one too.
|
|
94
|
+
"""
|
|
95
|
+
with open(tmp_path / "out", "w") as real:
|
|
96
|
+
_as_stdout(monkeypatch, real)
|
|
97
|
+
assert ensure_stdout_descriptor() is False
|
|
98
|
+
assert "fileno" not in getattr(real, "__dict__", {})
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_a_stream_that_takes_no_attribute_is_refused(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
102
|
+
"""Refused rather than raised: vLLM's own error is a better one than ours here."""
|
|
103
|
+
_as_stdout(monkeypatch, SlottedStdout())
|
|
104
|
+
assert ensure_stdout_descriptor() is False
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_a_closed_process_stdout_offers_nothing(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
108
|
+
"""With none to lend, the answer is no rather than a number that fails later.
|
|
109
|
+
|
|
110
|
+
This is the daemonized process, whose stdout was closed before Python started. Both
|
|
111
|
+
sources are taken away: ``sys.__stdout__``, and the fd 1 fallback that stands in for
|
|
112
|
+
it, which is open in a test runner and would otherwise be handed out.
|
|
113
|
+
"""
|
|
114
|
+
_as_stdout(monkeypatch, KernelStdout())
|
|
115
|
+
monkeypatch.setattr(sys, "__stdout__", None)
|
|
116
|
+
monkeypatch.setattr("interp_engine.notebook_stdout.os.fstat", _raise_ebadf)
|
|
117
|
+
assert ensure_stdout_descriptor() is False
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _raise_ebadf(fd: int) -> os.stat_result:
|
|
121
|
+
raise OSError(9, "Bad file descriptor")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_the_stand_in_matches_ipykernel() -> None:
|
|
125
|
+
"""The premise, asserted where it can be: ``fileno()`` raises what is caught for.
|
|
126
|
+
|
|
127
|
+
``io.UnsupportedOperation`` is both an ``OSError`` and a ``ValueError``, which is why
|
|
128
|
+
the module catches those two rather than importing ipykernel to name the class.
|
|
129
|
+
"""
|
|
130
|
+
stream: IO[Any] = KernelStdout() # type: ignore[assignment]
|
|
131
|
+
with pytest.raises((OSError, ValueError)):
|
|
132
|
+
stream.fileno()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__eager.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/deepseek-v4-flash-0731__vllm.json
RENAMED
|
File without changes
|
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/gemma-2-2b__vllm-cudagraph.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/llama-3.1-8b__vllm-cudagraph.json
RENAMED
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/llama-3.1-8b__vllm-static.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3-4b__vllm-cudagraph.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3.8-27b__vllm-cudagraph.json
RENAMED
|
File without changes
|
{interp_engine-1.3.2 → interp_engine-1.3.4}/benchmarks/results/qwen3.8-27b__vllm-static.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|