interp-engine 1.2.7__tar.gz → 1.2.9__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.2.7 → interp_engine-1.2.9}/PKG-INFO +12 -12
- {interp_engine-1.2.7 → interp_engine-1.2.9}/README.md +11 -11
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/README.md +24 -6
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/bench_spec.py +6 -4
- interp_engine-1.2.9/benchmarks/probe_lens_stream.py +622 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/AGENT_INTEGRATION.md +4 -1
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/PERFORMANCE.md +30 -9
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/USAGE.md +11 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/_loop.py +47 -4
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/protocol.py +6 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_backend.py +28 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/_hooks.py +25 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/freeze.py +22 -8
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/requests.py +1 -17
- {interp_engine-1.2.7 → interp_engine-1.2.9}/pyproject.toml +1 -1
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_sync_loop.py +46 -1
- interp_engine-1.2.9/tests/test_vllm_engine_loop.py +101 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_hyper_connections.py +276 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/.gitignore +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/LICENSE +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/__init__.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/cells.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/probe.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/publish.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/report_bench.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/deepseek-v4-flash-0731__eager.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/deepseek-v4-flash-0731__vllm-cudagraph.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/deepseek-v4-flash-0731__vllm-dspark-cudagraph.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/deepseek-v4-flash-0731__vllm-dspark.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/deepseek-v4-flash-0731__vllm-freeze.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/deepseek-v4-flash-0731__vllm.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/gemma-2-2b__eager.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/gemma-2-2b__vllm-cudagraph.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/gemma-2-2b__vllm-freeze.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/gemma-2-2b__vllm.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/llama-3.1-8b__eager.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/llama-3.1-8b__vllm-cudagraph.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/llama-3.1-8b__vllm-freeze.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/llama-3.1-8b__vllm.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3-4b__eager.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3-4b__vllm-cudagraph.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3-4b__vllm-freeze.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3-4b__vllm.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3.8-27b__eager.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3.8-27b__vllm-cudagraph.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3.8-27b__vllm-freeze.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results/qwen3.8-27b__vllm.json +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/results-latest.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/run_all.sh +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/run_bench.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/benchmarks/workloads.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/ARCHITECTURE_QUIRKS.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/COMPATIBILITY.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/ENGINE_HOOK_MAPPINGS.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/GRADIENTS.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/INTERNALS.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/PORTING.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/README.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/docs/SUPPORTED_POINTS.md +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/__init__.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/address.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/arch.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/attn_config.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/attn_scores.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/autograd_support.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/capture.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/chat_compose.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/chat_conventions.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/chat_formatters.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/cuda_preflight.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/dispatch.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/facts.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/hooks.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/lens.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/load.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/mappers.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/model.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/moe_routing.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/points.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/residual_basis.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/select.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/steer.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/steer_specs.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/sync.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/tokenize.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/__init__.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/_demux.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/_payload.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/_tree.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/attn.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/capture.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/graphs.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/lens/__init__.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/lens/intervene.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/lens/readout.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/lens/unembed.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/mhc.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/native.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_capture/steering.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/interp_engine/vllm_plugin.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/conftest.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/harness.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/model_expectations.yaml +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/synthetic_families.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_address.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_attn_config_tripwire.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_attn_probs_indexing.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_attn_scores.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_attn_z_gqa.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_autograd_support.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_bench_workloads.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_capability_refusals.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_capture_addressing.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_chat_compose.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_chat_formatters.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_chat_templates.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_core.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_cuda_preflight.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_doc_code_fences.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_eager_autograd.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_facts.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_family_points.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_freeze_dsv4_gpu.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_freeze_parity_gpu.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_freeze_set.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_freeze_warmup.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_gated_attn_out.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_head_contributions.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_hook_call_conventions.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_layer_kinds.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_load.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_logit_transform.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_mappers.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_mlp_internals.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_model_expectations.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_moe.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_multimodal_arch.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_new_models_gpu.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_no_chat_template.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_normalized_hook.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_packaging.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_parity_gpt2.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_per_layer_attn_dims.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_points_registry.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_protocol.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_published_benchmarks.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_qk_norm.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_qkv_layout.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_reasoning_spans.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_release.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_resid_mid.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_residual_basis.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_sandwich_norms.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_select.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_sliding_window_attn.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_small_models_gpu.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_steer_context.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_steer_math_parity.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_sync_parity.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_unified_free_functions.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_unresolved_families.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_capture_gpu.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_capture_scales.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_graph_path.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_graphs_on_gpu.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_hook_availability.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_kv_isolation.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_new_points.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_only_families.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_plugin.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vllm_wire_grammar.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_vocabulary_boundary.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_worker_lens_capture_readout.py +0 -0
- {interp_engine-1.2.7 → interp_engine-1.2.9}/tests/test_worker_lens_readout.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: interp-engine
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.9
|
|
4
4
|
Summary: A fast, standardized interpretability engine that supports most modern models and architectures. Powers Neuronpedia.
|
|
5
5
|
Project-URL: Homepage, https://github.com/decoderesearch/interp-engine
|
|
6
6
|
Project-URL: Repository, https://github.com/decoderesearch/interp-engine
|
|
@@ -71,7 +71,15 @@ pip install interp-engine # eager backend only
|
|
|
71
71
|
```python
|
|
72
72
|
from interp_engine import Address, load_model, run_with_cache
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
# VLLM MODE (default): low VRAM, medium speed
|
|
75
|
+
model = load_model("Qwen/Qwen3-8B")
|
|
76
|
+
|
|
77
|
+
# VLLM-FREEZE MODE: high VRAM, high speed, only frozen points (default resid_post)
|
|
78
|
+
# model = load_model("Qwen/Qwen3-8B", freeze_points="auto")
|
|
79
|
+
|
|
80
|
+
# EAGER MODE: low VRAM, low speed
|
|
81
|
+
# model = load_model("Qwen/Qwen3-8B", backend="eager")
|
|
82
|
+
|
|
75
83
|
point = Address("resid_post", 10) # or string: "resid_post.10"
|
|
76
84
|
cache = run_with_cache(model, model.to_tokens("Hello, world"), [point])
|
|
77
85
|
cache[point] # [batch, pos, ...]
|
|
@@ -87,7 +95,7 @@ Add "use interp-engine" to your prompt and let your agent figure it out - everyt
|
|
|
87
95
|
|
|
88
96
|
## Performance / Speed
|
|
89
97
|
|
|
90
|
-
vLLM gives `interp-engine` high throughput via concurrency, and **graph freeze** adds CUDA-graph replay on top of that
|
|
98
|
+
vLLM gives `interp-engine` high throughput via concurrency, and **graph freeze** adds CUDA-graph replay on top of that *without giving up capture or steering*. Every column below is capture-capable.
|
|
91
99
|
|
|
92
100
|
<!-- THROUGHPUT:START -->
|
|
93
101
|
|
|
@@ -117,15 +125,7 @@ One stream (tok/s):
|
|
|
117
125
|
|
|
118
126
|
<!-- THROUGHPUT:END -->
|
|
119
127
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
**Graph freeze** is opt-in, via `freeze_points`. Ordinary hooks cannot survive CUDA graphs — replay never calls the Python forward a hook is attached to — so the tap becomes a preallocated buffer plus a `copy_` that graph capture records and replay re-executes. Steering rides the same wrap, so additive, orthogonal, projection-cap and j-lens steer/ablate/swap all keep working under graphs, position masks included.
|
|
123
|
-
|
|
124
|
-
```python
|
|
125
|
-
model = load_model("Qwen/Qwen3-8B", freeze_points="auto") # resid_post at every layer, under graphs
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
The trade is that a frozen engine serves _the set it froze_ rather than any point on request: `"auto"` covers `resid_post` at every layer on a conventional trunk, an explicit list covers whatever you name, and anything outside the set is refused rather than quietly returned empty. Omit `freeze_points` for today's hooked vLLM, which still serves every point. `qwen3.8-27b` is a hybrid trunk, so its freeze row runs prefill eagerly and keeps the decode graphs — freeze pins that mode, because breakable graphs turn `torch.compile` off and vLLM's mixed prefill-decode capture then miscomputes prefill on a gated-delta trunk. On a hyper-connection trunk such as `deepseek-v4-flash-0731`, whose block carries four parallel residual streams, `"auto"` freezes `resid_streams` instead — the whole stack per layer, which is four times the width and so four times the buffer, and is what that row's freeze cell prices. See [PERFORMANCE.md](docs/PERFORMANCE.md) for the full trade-off, and [`benchmarks/results-latest.md`](benchmarks/results-latest.md) for the sweep, including capture, steering and lens latencies.
|
|
128
|
+
**Graph freeze** is opt-in via `freeze_points`, and a frozen engine serves only the set it froze. [PERFORMANCE.md](docs/PERFORMANCE.md) has how it works and what it trades; [benchmarks/results-latest.md](benchmarks/results-latest.md) has every figure at full precision, including capture, steering and lens latencies; [benchmarks/README.md](benchmarks/README.md) has how the tables above are rounded.
|
|
129
129
|
|
|
130
130
|
## Correctness
|
|
131
131
|
|
|
@@ -40,7 +40,15 @@ pip install interp-engine # eager backend only
|
|
|
40
40
|
```python
|
|
41
41
|
from interp_engine import Address, load_model, run_with_cache
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
# VLLM MODE (default): low VRAM, medium speed
|
|
44
|
+
model = load_model("Qwen/Qwen3-8B")
|
|
45
|
+
|
|
46
|
+
# VLLM-FREEZE MODE: high VRAM, high speed, only frozen points (default resid_post)
|
|
47
|
+
# model = load_model("Qwen/Qwen3-8B", freeze_points="auto")
|
|
48
|
+
|
|
49
|
+
# EAGER MODE: low VRAM, low speed
|
|
50
|
+
# model = load_model("Qwen/Qwen3-8B", backend="eager")
|
|
51
|
+
|
|
44
52
|
point = Address("resid_post", 10) # or string: "resid_post.10"
|
|
45
53
|
cache = run_with_cache(model, model.to_tokens("Hello, world"), [point])
|
|
46
54
|
cache[point] # [batch, pos, ...]
|
|
@@ -56,7 +64,7 @@ Add "use interp-engine" to your prompt and let your agent figure it out - everyt
|
|
|
56
64
|
|
|
57
65
|
## Performance / Speed
|
|
58
66
|
|
|
59
|
-
vLLM gives `interp-engine` high throughput via concurrency, and **graph freeze** adds CUDA-graph replay on top of that
|
|
67
|
+
vLLM gives `interp-engine` high throughput via concurrency, and **graph freeze** adds CUDA-graph replay on top of that *without giving up capture or steering*. Every column below is capture-capable.
|
|
60
68
|
|
|
61
69
|
<!-- THROUGHPUT:START -->
|
|
62
70
|
|
|
@@ -86,15 +94,7 @@ One stream (tok/s):
|
|
|
86
94
|
|
|
87
95
|
<!-- THROUGHPUT:END -->
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
**Graph freeze** is opt-in, via `freeze_points`. Ordinary hooks cannot survive CUDA graphs — replay never calls the Python forward a hook is attached to — so the tap becomes a preallocated buffer plus a `copy_` that graph capture records and replay re-executes. Steering rides the same wrap, so additive, orthogonal, projection-cap and j-lens steer/ablate/swap all keep working under graphs, position masks included.
|
|
92
|
-
|
|
93
|
-
```python
|
|
94
|
-
model = load_model("Qwen/Qwen3-8B", freeze_points="auto") # resid_post at every layer, under graphs
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
The trade is that a frozen engine serves _the set it froze_ rather than any point on request: `"auto"` covers `resid_post` at every layer on a conventional trunk, an explicit list covers whatever you name, and anything outside the set is refused rather than quietly returned empty. Omit `freeze_points` for today's hooked vLLM, which still serves every point. `qwen3.8-27b` is a hybrid trunk, so its freeze row runs prefill eagerly and keeps the decode graphs — freeze pins that mode, because breakable graphs turn `torch.compile` off and vLLM's mixed prefill-decode capture then miscomputes prefill on a gated-delta trunk. On a hyper-connection trunk such as `deepseek-v4-flash-0731`, whose block carries four parallel residual streams, `"auto"` freezes `resid_streams` instead — the whole stack per layer, which is four times the width and so four times the buffer, and is what that row's freeze cell prices. See [PERFORMANCE.md](docs/PERFORMANCE.md) for the full trade-off, and [`benchmarks/results-latest.md`](benchmarks/results-latest.md) for the sweep, including capture, steering and lens latencies.
|
|
97
|
+
**Graph freeze** is opt-in via `freeze_points`, and a frozen engine serves only the set it froze. [PERFORMANCE.md](docs/PERFORMANCE.md) has how it works and what it trades; [benchmarks/results-latest.md](benchmarks/results-latest.md) has every figure at full precision, including capture, steering and lens latencies; [benchmarks/README.md](benchmarks/README.md) has how the tables above are rounded.
|
|
98
98
|
|
|
99
99
|
## Correctness
|
|
100
100
|
|
|
@@ -104,6 +104,21 @@ python -m benchmarks.publish # rewrite both
|
|
|
104
104
|
python -m benchmarks.publish --check # exit 1 if either has drifted, and name it
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
Both print the same cells in a display form of their own, applied by `publish.py` and pinned by
|
|
108
|
+
`tests/test_published_benchmarks.py`:
|
|
109
|
+
|
|
110
|
+
- **tok/s is whole at 10 and above, one decimal below.** A tenth beside a four-digit figure in the
|
|
111
|
+
next column claims a resolution the reader cannot use. At 3 tok/s that same tenth is worth several
|
|
112
|
+
percent, so the small rows keep it.
|
|
113
|
+
- **every comparison is a multiplier, never a percent**, with one decimal below 20x, where it is
|
|
114
|
+
still checkable against the two printed figures. `+20%` beside `27x` makes the reader convert one
|
|
115
|
+
of them.
|
|
116
|
+
- **multipliers are ratios of the unrounded metrics**, each against eager on the same workload, so
|
|
117
|
+
dividing two printed figures by hand can differ in the last place. Ratios of the rounded figures
|
|
118
|
+
would make the published win depend on the rounding, which is worse.
|
|
119
|
+
|
|
120
|
+
`results-latest.md` keeps every figure at full precision, so nothing is lost to those rules.
|
|
121
|
+
|
|
107
122
|
`tests/test_published_benchmarks.py` runs that check over the committed cells, so a stale copy is a
|
|
108
123
|
red suite rather than a claim nobody re-read. The visualizer's chatbot answers out of a bundle holding
|
|
109
124
|
the README verbatim, so a publish that changed the README also wants `make viz-knowledge` -- the
|
|
@@ -225,12 +240,15 @@ already refers to, so a replay serves capture and steering without a Python forw
|
|
|
225
240
|
`freeze_points="auto"` takes in production, and the row exists to price it against the
|
|
226
241
|
`enforce_eager=True` column capture would otherwise have to use.
|
|
227
242
|
|
|
228
|
-
`"auto"`
|
|
229
|
-
half the feature and reported the other half as `n/a` -- with a message that blamed graph
|
|
230
|
-
it, which is the thing freeze exists to work around.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
243
|
+
`"auto"` once installed **reads** only, and a steering op needs a write tap to land in, so this row
|
|
244
|
+
priced half the feature and reported the other half as `n/a` -- with a message that blamed graph
|
|
245
|
+
replay for it, which is the thing freeze exists to work around. Auto now covers both halves, so the
|
|
246
|
+
cell would be a number either way, and this row still passes `freeze_writes` on purpose: an explicit
|
|
247
|
+
list *narrows* what auto would install, to the one mid-stack site the `steer` workload actually
|
|
248
|
+
writes. A row that priced a write buffer at every layer would not be comparable with the ones beside
|
|
249
|
+
it, which is the whole job of the column. Its value is the sentinel `run_bench.STEER_WRITES` rather
|
|
250
|
+
than a site, because that layer differs per model and a freeze write is a `load_model` argument, so
|
|
251
|
+
it has to be resolved from the config before a model exists to ask.
|
|
234
252
|
|
|
235
253
|
`VariantSpec.models` restricts the row to the checkpoints freeze has been shown correct on, so a model
|
|
236
254
|
missing from it renders `--` rather than a number nobody checked.
|
|
@@ -264,12 +264,14 @@ VARIANTS: tuple[VariantSpec, ...] = (
|
|
|
264
264
|
# Its write tap is `mlp_out`, not `resid_post`: the steer workload addresses the model's
|
|
265
265
|
# `capture_point`, and a hyper-connection trunk refuses the default name (`run_bench._steer_site`).
|
|
266
266
|
#
|
|
267
|
-
# `freeze_writes`
|
|
267
|
+
# `freeze_writes` was once what made the `steer` cell a number instead of `n/a`: `"auto"` installed
|
|
268
268
|
# reads, and a steering op needs a write tap to land in, so this row priced capture under replay
|
|
269
269
|
# and left the other half of the feature unmeasured -- with a message that blamed graph replay for
|
|
270
|
-
# it.
|
|
271
|
-
#
|
|
272
|
-
#
|
|
270
|
+
# it. Auto covers writes now, so the cell stands either way, and naming them here has become a
|
|
271
|
+
# *narrowing*: one write buffer at the site the workload steers rather than one per layer, which
|
|
272
|
+
# is what keeps this row's memory comparable with the columns beside it. The value is the sentinel
|
|
273
|
+
# `run_bench.STEER_WRITES`, resolved there to the mid-stack `resid_post` the workload steers,
|
|
274
|
+
# because the layer differs per model and a freeze write has to be named before the model exists.
|
|
273
275
|
VariantSpec(
|
|
274
276
|
"vllm-freeze",
|
|
275
277
|
"vllm",
|