entoscope.patching¶
Activation patching.
The operator, its input, configs, enums, collectors, method base and factory are importable from
entoscope.patching; the operator, its input, configs and enums from entoscope too.
- class entoscope.patching.config.PatchingType(*values)[source]¶
Bases:
StrEnumWhat a patch writes, named on its source element. A target element is always
replace.replacewrites the source run’s activation andvalue_scalethe same timesvalue.value_replacewrites the constantvalue, zero ablation with the default 0.0, andgaussian_noisethe target run’s own activation plus noise at three times its spread, the corruption of causal tracing. Neither of those two reads the source run.
- class entoscope.patching.config.PatchingMetric(*values)[source]¶
Bases:
StrEnumThe scalar read off one run’s output distribution.
randr'are the first and second of the tokens a metric names in itstokens.kl_divergencereads none: it scores the whole distribution against the source run’s.
- class entoscope.patching.config.MetricComparison(*values)[source]¶
Bases:
StrEnumHow a patched run’s metric is reported against the two runs it sits between.
Chosen per metric: a divergence is normally read as an
indirect_effectand a logit difference asnormalized.An ineffective patch reproduces the target run, and one that takes over entirely reproduces the source run, so
normalizedreads 0 and 1 at those two ends whichever of the pair is the clean prompt - that choice is expressed by the tokens a metric reads and their order, not here.
- class entoscope.patching.config.PatchingElementConfig(*, activation: ModelLayerLocation | None = None, location: list[ModelAxis] = <factory>, filter: Filter = <factory>, group: Group = <factory>, incremental: Incremental = <factory>, combination: Combination = <factory>, coordinates: Coordinates | None = None, type: PatchingType, value: float = 0.0)[source]¶
Bases:
ModelLocatorConfigOne side of a patch element: a locator, plus what the patch writes.
- Variables:
type (entoscope.patching.config.PatchingType) – What the patch writes, on a source element, and
replaceon a target one.value (float) – The constant
value_replacewrites and the factorvalue_scalemultiplies by.
- class entoscope.patching.config.SinglePatchingConfig(source: PatchingElementConfig, target: PatchingElementConfig)[source]¶
Bases:
objectA patch element: what is read at row
iof the source index is written at rowiof the target’s.An index of a single row pairs with every row of the other. A config lists several elements to patch them together: patched run
iapplies rowiof every element, so their indices have the same number of rows, or one. The result is laid out along the element with the most rows.- Variables:
source (entoscope.patching.config.PatchingElementConfig) – Where to read, and what to write.
target (entoscope.patching.config.PatchingElementConfig) – Where to write.
- class entoscope.patching.config.PatchingMetricConfig(*, type: PatchingMetric, tokens: list[str] = <factory>, comparison: MetricComparison)[source]¶
Bases:
objectA metric a run reads off every patched run, the tokens it reads and what it is reported against.
The config’s
metricnames it, so several metrics of one type can each read tokens of their own, or be reported under a comparison of their own.- Variables:
type (entoscope.patching.config.PatchingMetric) – The scalar read off a run.
tokens (list[str]) – The tokens the metric reads, by their names in the input’s
tokens: two for a difference, the first read against the second, one forprobabilityandlog_prob, and none forkl_divergence.comparison (entoscope.patching.config.MetricComparison) – What the metric is reported against.
- class entoscope.patching.config.PatchingMethodConfig(*, type: str)[source]¶
Bases:
MethodConfigThe method config of a patching method that takes no fields, such as
exact.A method with fields of its own names a dataclass extending this one.
- classmethod factory() type[PatchingMethodFactory][source]¶
Name the factory patching methods register with.
- Returns:
PatchingMethodFactory.
- class entoscope.patching.config.PatchingConfig(*, config_id: str | None = None, metric: dict[str, ~entoscope.patching.config.PatchingMetricConfig], method: ~entoscope.patching.config.PatchingMethodConfig, patch: list[~entoscope.patching.config.SinglePatchingConfig] = <factory>)[source]¶
Bases:
AbstractConfigWhat a patching run patches, and what it reads off every patched run.
Every metric is read off the same patched run, so a second metric costs no extra forward pass. Each metric’s result column is drawn as its own plot on the result page.
- Variables:
metric (dict[str, entoscope.patching.config.PatchingMetricConfig]) – Each metric, by a name of the config’s choosing, which names its result column too.
method (entoscope.patching.config.PatchingMethodConfig) – How the change in a metric is obtained, its
typenaming the method.exactpatches and runs the model once per index row, whileattributionandintegrated_gradientsestimate every row from gradients instead, trading a linearity assumption for a cost that does not grow with the index. In a YAML file it is the mapping read strictly into the method’s config class, or just the method’s type for its defaults.patch (list[entoscope.patching.config.SinglePatchingConfig]) – The patch elements, applied together in every patched run.
- class entoscope.patching.input.PatchingInput(config: PatchingConfig, source_prompt: str | None, target_prompt: str, tokens: dict[str, str | int]=<factory>)[source]¶
Bases:
OperationInputThe two prompts a patching run sits between, and the tokens its metrics read.
The target run is the one patched, and the source run is what
replaceandvalue_scaleread. A source element that reads no source run, a value or noise on the target’s own activation, counts its positions in the target prompt.- Variables:
config (entoscope.patching.config.PatchingConfig) – The patching config.
source_prompt (str | None) – The prompt patched from.
Nonewhen no element reads it, and thenkl_divergenceandnormalized, which score against the source run, are unavailable.target_prompt (str) – The prompt patched into.
tokens (dict[str, str | int]) – The tokens the config’s metrics read, by the names the metrics give them, each a string that tokenizes to a single token or a token id. A string of several tokens is read as its first, with a warning. Only the tokens a metric reads are checked and resolved, so one mapping can serve configs that read different ones.
- Raises:
ValueError – If the config has no patch element, names a patch type, metric or comparison nothing implements, reads or scores against the source run without a source prompt, or a metric names other than as many tokens as its type reads, or a token that
tokensdoes not name or that is neither a string nor a token id.
- prepare(model: TransformerBridge | CachedModel, batch_size: int = 1, *, index_only: bool = False) PatchingInput[source]¶
Resolve the index and the tokens, then run both prompts, caching what it reads, as wide as the patched runs.
A backend may round differently at different batch shapes (MPS does, by up to half a logit in bfloat16), so a patched run has to be compared with, and patched from, runs of its own shape: only then does a patch that writes back what was there reproduce the target run exactly. Each prompt is therefore run
batch_widthcopies abreast and kept at its first row.- Parameters:
model – The model to run.
batch_size – How many patched runs each forward pass holds.
index_only – Whether to stop after the index and the tokens, before any forward pass.
- Returns:
The input itself, prepared in place.
- Raises:
ValueError – If the elements’ row counts cannot be paired, the model computes no transformer activation an element names, or a token a metric reads is a string that holds no token or an id outside the vocabulary.
- rows() list[tuple][source]¶
Group the index’s rows as a run patches them.
- Returns:
One tuple per patched run, in result row order, holding that run’s row of every element.
- activation_names() list[str][source]¶
Name every activation the run touches, on either side of the patch.
The target’s own names are read only by the gradient methods, which need the clean activation a patch would overwrite and the value they interpolate towards. The two sides name the same activation in the common case, so caching both usually costs nothing.
- Returns:
The transformer activation names, sorted.
- target_activation_names() list[str][source]¶
Name every activation a patch writes.
- Returns:
The transformer activation names, sorted.
- property source_tokens: Int[Tensor, 'batch pos']¶
The source prompt’s tokens, once the index is prepared.
- property target_tokens: Int[Tensor, 'batch pos']¶
The target prompt’s tokens, once the index is prepared.
- property source_logits: Float[Tensor, 'batch pos d_vocab']¶
The unpatched source run’s logits, once the input is prepared.
- property target_logits: Float[Tensor, 'batch pos d_vocab']¶
The unpatched target run’s logits, once the input is prepared.
- property source_generation: int¶
The token the unpatched source run predicts, once the input is prepared.
- property target_generation: int¶
The token the unpatched target run predicts, once the input is prepared.
- property source_cache: ActivationCache¶
The source run’s activations, once the input is prepared.
- property target_cache: ActivationCache¶
The target run’s activations, once the input is prepared.
- property index: list[Index[PatchingElementConfig]]¶
One index per patch element, once the index is prepared.
- property layout_index: Index[PatchingElementConfig]¶
the first with the most rows, so every run has a row.
- Type:
The element index the result is laid out along
- property batch_width: int¶
How many rows every patched run holds, the width the cached runs were made at.
- property metrics: dict[str, AbstractMetric]¶
Every metric of the config by its name, built on the ids of the tokens it reads when first read.
Built again once the prompts are re-run, or the input moved, so what a metric keeps of the unpatched runs is always of the runs the input holds.
- noise_scale(name: str) Tensor[source]¶
Find the standard deviation
gaussian_noisedraws at for an activation.Measured once per activation rather than once per row that noises it.
- Parameters:
name – The transformer activation name.
- Returns:
Three times the target run’s own spread there, as in causal tracing (Meng et al. 2022).
- to(device: str | device = 'cpu') PatchingInput[source]¶
Move the tensors the input holds to
device.- Parameters:
device – The device to move to.
- Returns:
The input itself, moved in place.
- class entoscope.patching.patcher.Patcher(model: TransformerBridge | CachedModel, collector_class: type[PatchingCollector] = PatchingVisualizationCollector, batch_size: int = 1)[source]¶
Bases:
OperatorPatches the source run into the target run and reports how the metrics moved, one row per patched run.
Backends round differently at different batch shapes, so the cached source and target runs are made at the same width as the patched runs.
- Parameters:
model – The model to patch.
collector_class – The collector to write the results with. The default also draws
result.html, andPatchingCollectorwrites the CSV files alone.batch_size – How many patched runs one forward pass of
exactholds. The gradient methods score the whole index from passes of their own and ignore it.
- apply(patching_input: PatchingInput, save_dir: str | None = None, return_collector: bool = False, verbose: bool = True) PatchingCollector | None[source]¶
Patch every row of the input’s index and read the metrics off each patched run.
The method is built before any forward pass, so a config that names something the run cannot do fails before the model is touched. Where the results were saved is logged through the
entoscopelogger.- Parameters:
patching_input – The config, prompts and answer tokens to run, prepared in place.
save_dir – The directory to write
result.csv, oneindex-{i}.csvper patch element,config.jsonand the page into, created if missing.Nonewrites nothing.return_collector – Whether to return the collector.
verbose – Whether to show a progress bar.
- Returns:
The collector, whose
resultholds every patched run’s metric columns, ifreturn_collectoris set, andNoneotherwise.
- plan(patching_input: PatchingInput, save_dir: str | None = None, verbose: bool = True) OperationPlan[source]¶
Describe the run
applywould make, without a forward pass and without touchingsave_dir.The input’s index is resolved exactly as the run resolves it, and kept for
apply.- Parameters:
patching_input – The config, prompts and answer tokens the run would use.
save_dir – The directory the run would write into.
verbose – Whether to also log the plan.
- Returns:
The plan – one step per patched run, and the forward and backward passes the method makes on top of one cached run per prompt.
- class entoscope.patching.collector.PatchingCollector(operation_input: InputT, model: TransformerBridge | CachedModel, save_dir: str | None = None)[source]¶
Bases:
FrameCollector[PatchingInput]Writes the metrics of every patched run as
result.csv, plus one index file per element.A run that patched the model also records what it then predicts next, as
generation(the token id, exact) andstr_generation(its string, seestr_tokenon reading it back).Each metric’s column is its name with
_metricappended, such aslogit_diff_metric, so no metric can take a column the run writes itself.This base collector writes the CSV files only, and
PatchingVisualizationCollectoralso drawsresult.html.
- class entoscope.patching.collector.PatchingVisualizationCollector(operation_input: InputT, model: TransformerBridge | CachedModel, save_dir: str | None = None)[source]¶
Bases:
VisualizationCollector[PatchingInput,PatchingFigure],PatchingCollectorA
PatchingCollectorthat also draws its result as an interactive Plotlyresult.html.Its
figuresare keyed by the metric names the config gives.- figure_class¶
alias of
PatchingFigure
- class entoscope.patching.metric.AbstractMetric(tokens: list[int])[source]¶
Bases:
ABCOne scalar read off a run’s final-position logits, on the tokens it reads.
The input, which holds the two unpatched runs, is handed to it with every run it reads. The input also builds it, and builds it again whenever it re-runs its prompts, so a metric belongs to one pair of unpatched runs: what it reads off them, which every row is reported against, it reads once and keeps.
- Parameters:
tokens – The ids of the tokens the metric reads, in the order its config names them.
- Variables:
effect_sign (ClassVar[int]) – The sign an
indirect_effectis reported with, -1 for a metric that falls as the patch restores the source run.n_tokens (ClassVar[int]) – How many tokens the metric reads, which its config names in
tokens.needs_source_run (ClassVar[bool]) – Whether the metric scores against the source run.
tokens – The ids of the tokens the metric reads.
- source(patching_input: PatchingInput) torch.Tensor[source]¶
Read the metric off the unpatched source run, the first time it is asked.
- Parameters:
patching_input – The prepared input that built the metric, which has a source prompt.
- Returns:
The metric, a scalar.
- target(patching_input: PatchingInput) torch.Tensor[source]¶
Read the metric off the unpatched target run, the first time it is asked.
- Parameters:
patching_input – The prepared input that built the metric.
- Returns:
The metric, a scalar.
- abstractmethod compute(patching_input: PatchingInput, logits: Logits) torch.Tensor[source]¶
Read the metric off one run, differentiably, so the gradient methods can back-propagate through it.
- Parameters:
patching_input – The prepared input, whose unpatched runs a metric may score against.
logits – The run’s logits at the final position.
- Returns:
The metric, a scalar.
- static get(metric: PatchingMetric) type[AbstractMetric][source]¶
Pick the implementation of a metric.
- Parameters:
metric – The metric.
- Returns:
The metric’s class.
- Raises:
ValueError – If the metric is unknown.
- class entoscope.patching.metric.LogitDiffMetric(tokens: list[int])[source]¶
Bases:
AbstractMetriclogit(r) - logit(r').- compute(patching_input: PatchingInput, logits: Logits) torch.Tensor[source]¶
Read the metric off one run, differentiably, so the gradient methods can back-propagate through it.
- Parameters:
patching_input – The prepared input, whose unpatched runs a metric may score against.
logits – The run’s logits at the final position.
- Returns:
The metric, a scalar.
- class entoscope.patching.metric.ProbabilityMetric(tokens: list[int])[source]¶
Bases:
AbstractMetricP(r).- compute(patching_input: PatchingInput, logits: Logits) torch.Tensor[source]¶
Read the metric off one run, differentiably, so the gradient methods can back-propagate through it.
- Parameters:
patching_input – The prepared input, whose unpatched runs a metric may score against.
logits – The run’s logits at the final position.
- Returns:
The metric, a scalar.
- class entoscope.patching.metric.LogProbMetric(tokens: list[int])[source]¶
Bases:
AbstractMetriclog P(r).- compute(patching_input: PatchingInput, logits: Logits) torch.Tensor[source]¶
Read the metric off one run, differentiably, so the gradient methods can back-propagate through it.
- Parameters:
patching_input – The prepared input, whose unpatched runs a metric may score against.
logits – The run’s logits at the final position.
- Returns:
The metric, a scalar.
- class entoscope.patching.metric.LogProbDiffMetric(tokens: list[int])[source]¶
Bases:
AbstractMetriclog P(r) - log P(r').Numerically the same thing as
LogitDiffMetric, since the softmax’s normalizer is shared by the two tokens and cancels, and kept apart because the papers that use it call it by this name.- compute(patching_input: PatchingInput, logits: Logits) torch.Tensor[source]¶
Read the metric off one run, differentiably, so the gradient methods can back-propagate through it.
- Parameters:
patching_input – The prepared input, whose unpatched runs a metric may score against.
logits – The run’s logits at the final position.
- Returns:
The metric, a scalar.
- class entoscope.patching.metric.KLDivergenceMetric(tokens: list[int])[source]¶
Bases:
AbstractMetricD_KL(P_source || P_run), how far a run’s whole distribution sits from the source run’s.Needs no answer token, which is what makes it the task-agnostic choice.
kl_div(input, target)readsinputas log-probabilities and computesD_KL(target || exp(input)), so the run being scored is the one passed asinput.- compute(patching_input: PatchingInput, logits: Logits) torch.Tensor[source]¶
Read the metric off one run, differentiably, so the gradient methods can back-propagate through it.
- Parameters:
patching_input – The prepared input, whose unpatched runs a metric may score against.
logits – The run’s logits at the final position.
- Returns:
The metric, a scalar.
- class entoscope.patching.metric.AbstractComparison[source]¶
Bases:
ABCTurns the change a patch made to a metric into the number a run reports.
Every method produces the same primitive,
delta, the patched run’s metric minus the unpatched target run’s: exactly forexactand as a gradient estimate for the others.- Variables:
needs_source_run (bool) – Whether the comparison scores against the source run.
- abstractmethod classmethod apply(metric: AbstractMetric, patching_input: PatchingInput, delta: torch.Tensor) torch.Tensor[source]¶
Report a change in a metric.
- Parameters:
metric – The metric that changed.
patching_input – The prepared input, whose unpatched runs the change is reported against.
delta – The patched run’s metric minus the unpatched target run’s.
- Returns:
The reported number.
- static get(comparison: MetricComparison) type[AbstractComparison][source]¶
Pick the implementation of a comparison.
- Parameters:
comparison – The comparison.
- Returns:
The comparison’s class.
- Raises:
ValueError – If the comparison is unknown.
- class entoscope.patching.metric.AbsoluteComparison[source]¶
Bases:
AbstractComparisonThe patched run’s metric itself.
- classmethod apply(metric: AbstractMetric, patching_input: PatchingInput, delta: torch.Tensor) torch.Tensor[source]¶
Report a change in a metric.
- Parameters:
metric – The metric that changed.
patching_input – The prepared input, whose unpatched runs the change is reported against.
delta – The patched run’s metric minus the unpatched target run’s.
- Returns:
The reported number.
- class entoscope.patching.metric.IndirectEffectComparison[source]¶
Bases:
AbstractComparisonThe patched run’s metric minus the unpatched target run’s, signed by the metric’s
effect_sign.- classmethod apply(metric: AbstractMetric, patching_input: PatchingInput, delta: torch.Tensor) torch.Tensor[source]¶
Report a change in a metric.
- Parameters:
metric – The metric that changed.
patching_input – The prepared input, whose unpatched runs the change is reported against.
delta – The patched run’s metric minus the unpatched target run’s.
- Returns:
The reported number.
- class entoscope.patching.metric.NormalizedComparison[source]¶
Bases:
AbstractComparison0 where the patch changed nothing, 1 where it reproduced the source run.
The same ratio circuit work calls faithfulness, with the unpatched target run playing the part of the fully-ablated model. Two runs that score the same leave no gap to divide by: every row then reads inf, or nan where the patch changed nothing, and a warning is logged.
- classmethod apply(metric: AbstractMetric, patching_input: PatchingInput, delta: torch.Tensor) torch.Tensor[source]¶
Report a change in a metric.
- Parameters:
metric – The metric that changed.
patching_input – The prepared input, whose unpatched runs the change is reported against.
delta – The patched run’s metric minus the unpatched target run’s.
- Returns:
The reported number.
- class entoscope.patching.processor.SourceStrategy[source]¶
Bases:
ABCWhat a patch writes, by the
typeof its source element.- Variables:
needs_source_run (bool) – Whether the strategy reads the source run.
- abstractmethod static extract(index: IndexElement[PatchingElementConfig], patching_input: PatchingInput) torch.Tensor[source]¶
Produce the value a patch writes.
- Parameters:
index – The source element.
patching_input – The prepared input.
- Returns:
The value, shaped as the source element’s slice or broadcastable to the target’s.
- static get(patching_type: PatchingType) type[SourceStrategy][source]¶
Pick the strategy of a source element’s type.
- Parameters:
patching_type – The source element’s type.
- Returns:
The strategy.
- Raises:
ValueError – If the type is unknown.
- class entoscope.patching.processor.TargetStrategy[source]¶
Bases:
ABCHow a patch is written, by the
typeof its target element.- abstractmethod static set(index: IndexElement[PatchingElementConfig], target_activation: Tensor, extracted_source: Tensor, batch: int) Tensor[source]¶
Write a value into the patched run’s activation.
- Parameters:
index – The target element.
target_activation – The patched run’s activation, written in place unless it is a sublayer’s input.
extracted_source – What the source strategy produced.
batch – The batch row of the patched run.
- Returns:
The patched activation, the one the hook hands on.
- static get(patching_type: PatchingType) type[TargetStrategy][source]¶
Pick the strategy of a target element’s type.
- Parameters:
patching_type – The target element’s type.
- Returns:
The strategy.
- Raises:
ValueError – If the type is not
replace.
- class entoscope.patching.processor.ReplaceSourceStrategy[source]¶
Bases:
SourceStrategyThe source run’s activation.
- static extract(source_index: IndexElement[PatchingElementConfig], patching_input: PatchingInput) torch.Tensor[source]¶
Produce the value a patch writes.
- Parameters:
index – The source element.
patching_input – The prepared input.
- Returns:
The value, shaped as the source element’s slice or broadcastable to the target’s.
- class entoscope.patching.processor.ValueReplaceSourceStrategy[source]¶
Bases:
SourceStrategyThe element’s constant
value.- static extract(source_index: IndexElement[PatchingElementConfig], patching_input: PatchingInput) torch.Tensor[source]¶
Produce the value a patch writes.
- Parameters:
index – The source element.
patching_input – The prepared input.
- Returns:
The value, shaped as the source element’s slice or broadcastable to the target’s.
- class entoscope.patching.processor.ValueScaleSourceStrategy[source]¶
Bases:
SourceStrategyThe source run’s activation times the element’s
value.- static extract(source_index: IndexElement[PatchingElementConfig], patching_input: PatchingInput) torch.Tensor[source]¶
Produce the value a patch writes.
- Parameters:
index – The source element.
patching_input – The prepared input.
- Returns:
The value, shaped as the source element’s slice or broadcastable to the target’s.
- class entoscope.patching.processor.GaussianNoiseSourceStrategy[source]¶
Bases:
SourceStrategyThe target’s own activation plus
N(0, noise_scale)noise, the corruption of causal tracing.Seeded the same on every call, so each row of a sweep is corrupted by the same draw and differs from the others only in where it lands, and a rerun repeats the sweep exactly.
- Variables:
SEED – The seed every draw starts from.
- static extract(source_index: IndexElement[PatchingElementConfig], patching_input: PatchingInput) torch.Tensor[source]¶
Produce the value a patch writes.
- Parameters:
index – The source element.
patching_input – The prepared input.
- Returns:
The value, shaped as the source element’s slice or broadcastable to the target’s.
- class entoscope.patching.processor.ReplaceTargetStrategy[source]¶
Bases:
TargetStrategyOverwrites the target element’s slice with the value.
- static set(index: IndexElement[PatchingElementConfig], target_activation: Tensor, extracted_source: Tensor, batch: int) Tensor[source]¶
Write a value into the patched run’s activation.
- Parameters:
index – The target element.
target_activation – The patched run’s activation, written in place unless it is a sublayer’s input.
extracted_source – What the source strategy produced.
batch – The batch row of the patched run.
- Returns:
The patched activation, the one the hook hands on.
- class entoscope.patching.processor.PatchProcessor[source]¶
Bases:
objectApplies one patch, source strategy then target strategy.
- static patch(index: SingleIndex[PatchingElementConfig], patching_input: PatchingInput, target_activation: torch.Tensor, batch: int) torch.Tensor[source]¶
Write a row’s source into one batch row of the patched run’s activation.
- Parameters:
index – The row to patch.
patching_input – The prepared input.
target_activation – The patched run’s activation, written in place unless it is a sublayer’s input.
batch – The batch row of the patched run.
- Returns:
The patched activation, the one the hook hands on.
- class entoscope.patching.processor.HookedPatchProcessor[source]¶
Bases:
PatchProcessorApplies a patch as a
transformer_lensforward hook.- classmethod hook(index: SingleIndex[PatchingElementConfig], patching_input: PatchingInput, batch: int) tuple[str, Callable][source]¶
Build the forward hook that patches one row.
- Parameters:
index – The row to patch.
patching_input – The prepared input.
batch – The batch row of the patched run.
- Returns:
The hook name and the hook function, as
run_with_hookstakes them.
Interactive Plotly rendering of a patching run.
The grid is the run’s own index, layer up and position across for the canonical sweep, coloured by the metric on a diverging scale centred on the value an ineffective patch would produce, so warm cells are the locations that moved the model toward the source. One such grid is drawn per column the config names, each centred on its own comparison’s ineffective value. A cell’s hover names the token its patched run predicts next, and the subtitle the token each unpatched prompt does and the tokens the grid’s metric reads.
- class entoscope.patching.visualization.PatchingFigure(result: DataFrame, operation_input: PatchingInput, model: TransformerBridge | CachedModel, index: Index)[source]¶
Bases:
GridFigure[PatchingInput,str]The page of a patching run: one grid per result column, each panel a metric, by its name.
The patch elements the result is not laid out along are described in the subtitle when they patch the same location in every run, and in each cell’s hover when they vary with the row.
- Parameters:
result – The run’s result frame.
operation_input – The input the run iterated.
model – The model the run patched.
index – The index that laid the result out.
- property title: str¶
The page’s title.
- panels() list[str][source]¶
Name the page’s panels.
- Returns:
The panels, in page order, each drawn as its own plot.
- heading(panel: str) str[source]¶
Name one panel’s plot.
- Parameters:
panel – One of
panels().- Returns:
The plot’s heading, shown above the subtitle line.
- subtitle(panel: str) str[source]¶
Describe what one panel’s plot holds, under its heading.
- Parameters:
panel – One of
panels().- Returns:
The subtitle, as HTML.
- value_column(panel: str) str[source]¶
Name the result column one panel colours its cells by.
- Parameters:
panel – One of
panels().- Returns:
A column of the result frame.
- value_range(panel: str, values: Sequence[float]) tuple[float, float][source]¶
Choose the range one panel’s colours span.
- Parameters:
panel – One of
panels().values – The panel’s values, one per result row.
- Returns:
The low and high ends of the colour range, by default 0 and 1.
- str_tokens() dict[str, list[str]][source]¶
Read the prompt’s token strings, to label the position axes with.
Read once at construction. A figure whose index carries no position, or a run with no prompt to read one from, labels its ticks with the coordinates alone.
- Returns:
The token strings for each position column of the result, keyed by that column. Empty by default.
- entoscope.patching.method.patching.metric_column(metric: str) str[source]¶
Name the result column a metric is written to.
Every metric’s column carries the same suffix, so none is a column the run writes itself:
generation,str_generationor one of the index’s.- Parameters:
metric – The metric’s name in the config.
- Returns:
<name>_metric, such aslogit_diff_metric.
- class entoscope.patching.method.patching.RowResult(output: int, metrics: dict[str, float], generation: int | None = None)[source]¶
Bases:
objectWhat a method reports for one index row.
- Variables:
output (int) – The result row the collector files the report under.
metrics (dict[str, float]) – The row’s value of every metric, keyed by the metric’s name; the collector writes each to its
metric_column.generation (int | None) – The token the patched run predicts next. Only a method that actually runs the patched model has one, and the gradient methods, which estimate the metric without such a run, leave it unset.
- class entoscope.patching.method.patching.AbstractPatchingMethod(model: TransformerBridge | CachedModel, config: PatchingConfig)[source]¶
Bases:
ABC,Generic[PatchingMethodConfigT]The base of every patching method: how a run turns its index into one number per row.
Every method produces the same primitive for each row,
delta, the metric of the patched run minus the metric of the unpatched target run, one per metric, and_reportreports each under its metric’s comparison. What separates the methods is only howdeltais reached: by patching and running the model, or by estimating from gradients.A method is built once per run. Its type argument names the dataclass of its method config, extending
PatchingMethodConfig, which a config file’smethodis read into. A method naming none takesPatchingMethodConfigitself, which no field fits.- Parameters:
model – The model the method patches.
config – The run’s config.
- Variables:
batched (ClassVar[bool]) – Whether the method runs the patched model
batch_sizerows at a time, so a plan reports its batches.method_config – The run’s method config, typed by the method’s type argument.
- abstractmethod scores(patching_input: PatchingInput, verbose: bool = True) Iterator[RowResult][source]¶
Score every patched run.
- Parameters:
patching_input – The prepared input.
verbose – Whether to show a progress bar.
- Yields:
One
RowResultper patched run, its metric values keyed by the metric’s name.
- abstractmethod passes(patching_input: PatchingInput, batches: int) tuple[int, int][source]¶
Count the passes the sweep costs, over and above the input’s cached runs.
- Parameters:
patching_input – The input, its index resolved:
rows()lists the patched runs andtarget_activation_names()the transformer activations a patch writes.batches – The number of batches the patched runs fall into, for a batched method.
- Returns:
The forward and the backward passes.
- check(patching_input: PatchingInput) None[source]¶
Reject an input the method cannot score, before either prompt is run.
Called once the input’s index is resolved, by
planas well as by the run, so a plan never promises a run the method would refuse. Nothing is rejected by default.- Parameters:
patching_input – The input, its index resolved and no forward pass made.
- Raises:
ValueError – If the method cannot score the input.
- class entoscope.patching.method.exact.ExactPatchingMethod(model: TransformerBridge | CachedModel, config: PatchingConfig)[source]¶
Bases:
AbstractPatchingMethod[PatchingMethodConfigT]Patches and runs the model, once per index row.
The reference the other methods approximate: nothing is assumed about how the model responds to the intervention, at the price of a forward pass per row. Its last batch is padded to the full width, so every patched run has the shape the cached runs were made at.
- scores(patching_input: PatchingInput, verbose: bool = True) Iterator[RowResult][source]¶
Score every patched run.
- Parameters:
patching_input – The prepared input.
verbose – Whether to show a progress bar.
- Yields:
One
RowResultper patched run, its metric values keyed by the metric’s name.
- passes(patching_input: PatchingInput, batches: int) tuple[int, int][source]¶
Count the passes the sweep costs, over and above the input’s cached runs.
- Parameters:
patching_input – The input, its index resolved:
rows()lists the patched runs andtarget_activation_names()the transformer activations a patch writes.batches – The number of batches the patched runs fall into, for a batched method.
- Returns:
The forward and the backward passes.
- class entoscope.patching.method.attribution.AttributionPatchingMethod(model: TransformerBridge | CachedModel, config: PatchingConfig)[source]¶
Bases:
AbstractPatchingMethod[PatchingMethodConfigT]Attribution patching, the first-order Taylor expansion of the true indirect effect.
IE ~= grad(m) . (a_patch - a_clean), with the gradient taken on the target run at the activation a patch would overwrite. One backward pass scores the whole index, so the cost is flat in the number of rows rather than linear in it. The price is that the estimate is only as good as the model’s local linearity, which a large intervention (zero ablation of a whole layer, say) leaves well behind.The intervention itself is unchanged: the replacement value comes from the same
SourceStrategythe exact method uses, so resampling, zero ablation, scaling and noise are all scored the same way.- scores(patching_input: PatchingInput, verbose: bool = True) Iterator[RowResult][source]¶
Score every patched run.
- Parameters:
patching_input – The prepared input.
verbose – Whether to show a progress bar.
- Yields:
One
RowResultper patched run, its metric values keyed by the metric’s name.
- passes(patching_input: PatchingInput, batches: int) tuple[int, int][source]¶
Count the passes the sweep costs, over and above the input’s cached runs.
- Parameters:
patching_input – The input, its index resolved:
rows()lists the patched runs andtarget_activation_names()the transformer activations a patch writes.batches – The number of batches the patched runs fall into, for a batched method.
- Returns:
The forward and the backward passes.
- class entoscope.patching.method.attribution.IntegratedGradientsConfig(*, type: str, interpolation_steps: int = 10)[source]¶
Bases:
PatchingMethodConfigThe method config of
integrated_gradients.- Variables:
interpolation_steps (int) – The number of points the gradient is averaged over.
- Raises:
ValueError – If
interpolation_stepsis below 1.
- class entoscope.patching.method.attribution.IntegratedGradientsMethod(model: TransformerBridge | CachedModel, config: PatchingConfig)[source]¶
Bases:
AttributionPatchingMethod[IntegratedGradientsConfig]Integrated gradients in activation space (Marks et al. 2024, Eq. 4).
Averages the gradient over
interpolation_stepspoints on the straight path from the source activation to the target one instead of reading it once at the target. That recovers the effects a flat gradient at the clean point hides, at a forward and a backward pass per step for each transformer activation, still flat in the rows of the index.Each patched activation is interpolated on passes of its own, one per step but the clean one, which a single pass serves for all of them. The cost so grows with the number of transformer activations the index patches, such as the layers it sweeps, and never with its rows: every position, head or neuron of one is scored from the same passes.
The path runs between the two runs’ activations, so it is the path the intervention actually traverses only when the source resamples from the source run. A value-based source (zero ablation, scaling, noise) writes something off that path, and the averaged gradient then belongs to a change other than the one being scored. Attribution patching, whose expansion point does not depend on a path at all, is the estimate to reach for there.
- check(patching_input: PatchingInput) None[source]¶
Reject an input the method cannot score, before either prompt is run.
Called once the input’s index is resolved, by
planas well as by the run, so a plan never promises a run the method would refuse. Nothing is rejected by default.- Parameters:
patching_input – The input, its index resolved and no forward pass made.
- Raises:
ValueError – If the method cannot score the input.
- class entoscope.patching.method.factory.PatchingMethodFactory[source]¶
Bases:
RegistryFactory[AbstractPatchingMethod]Resolves the patching method a config’s
method.typenames and builds it for a run.It holds
exact,attribution,integrated_gradientsand every method registered withregister.- classmethod create(model: TransformerBridge | CachedModel, config: PatchingConfig) AbstractPatchingMethod[source]¶
Build the method a config names, once per run.
- Parameters:
model – The model the method patches.
config – The run’s config, whose
method.typenames the method.
- Returns:
The method.
- Raises:
ValueError – If no method is registered under the name, or the method rejects the config.