From /simplify codebase sweep (2026-06-10). Hottest path in a transparency run.
transparency/explainers/shap_explainer.py:339-379 (_compute_legacy), :436-446 (_compute_modern), driven by the batch loop in base_explainer.py:248-268: compute_attributions is called once per chunk by _compute_with_optional_batches, and each call constructs a fresh shap.GradientExplainer/DeepExplainer/KernelExplainer(model, background_data) (or a fresh masker + PartitionExplainer etc. on the modern path).
Cost: Deep/Kernel/Gradient explainer construction runs model forwards over the entire background set (expected-value computation, hook setup). background_data is in _NON_BATCHABLE_KWARGS, so it is byte-identical across chunks -- with raitap.batch_size: 8 over 64 samples the background forwards run 8x for zero benefit.
Fix: memoise the constructed SHAP explainer on the instance keyed by (algorithm, id(model), id(background_data), frozen init_kwargs); the per-batch invoker then only calls .shap_values()/__call__. Captum method construction is cheap (stores a model ref) -- scope the cache to SHAP, do not complicate the invoker seam (#266).
From /simplify codebase sweep (2026-06-10). Hottest path in a transparency run.
transparency/explainers/shap_explainer.py:339-379(_compute_legacy),:436-446(_compute_modern), driven by the batch loop inbase_explainer.py:248-268:compute_attributionsis called once per chunk by_compute_with_optional_batches, and each call constructs a freshshap.GradientExplainer/DeepExplainer/KernelExplainer(model, background_data)(or a fresh masker +PartitionExplaineretc. on the modern path).Cost: Deep/Kernel/Gradient explainer construction runs model forwards over the entire background set (expected-value computation, hook setup).
background_datais in_NON_BATCHABLE_KWARGS, so it is byte-identical across chunks -- withraitap.batch_size: 8over 64 samples the background forwards run 8x for zero benefit.Fix: memoise the constructed SHAP explainer on the instance keyed by
(algorithm, id(model), id(background_data), frozen init_kwargs); the per-batch invoker then only calls.shap_values()/__call__. Captum method construction is cheap (stores a model ref) -- scope the cache to SHAP, do not complicate the invoker seam (#266).