Source code for entoscope.model.activation
"""The transformer activation name each activation is cached under, and how a hook writing one hands it on."""
from collections.abc import Iterable
import torch
from entoscope.model.base import Model
from entoscope.model.config import ModelLayerLocation
TRANSFORMER_ACT_NAME: dict[ModelLayerLocation, str] = {
ModelLayerLocation.EMBEDDING: "hook_embed",
ModelLayerLocation.RESIDUAL_PRE: "hook_resid_pre",
ModelLayerLocation.RESIDUAL_MID: "hook_resid_mid",
ModelLayerLocation.RESIDUAL_POST: "hook_resid_post",
ModelLayerLocation.ATTENTION_IN: "attn.hook_in",
ModelLayerLocation.ATTENTION_Q: "attn.hook_q",
ModelLayerLocation.ATTENTION_K: "attn.hook_k",
ModelLayerLocation.ATTENTION_V: "attn.hook_v",
ModelLayerLocation.ATTENTION_PATTERN: "attn.hook_pattern",
ModelLayerLocation.ATTENTION_Z: "attn.hook_z",
ModelLayerLocation.ATTENTION_OUT_PRE_NORM: "attn.hook_out",
ModelLayerLocation.ATTENTION_OUT: "hook_attn_out",
ModelLayerLocation.MLP_IN: "mlp.hook_in",
ModelLayerLocation.MLP_PRE: "mlp.hook_pre",
ModelLayerLocation.MLP_PRE_LINEAR: "mlp.hook_pre_linear",
ModelLayerLocation.MLP_POST: "mlp.hook_post",
ModelLayerLocation.MLP_OUT_PRE_NORM: "mlp.hook_out",
ModelLayerLocation.MLP_OUT: "hook_mlp_out",
}
SUBLAYER_INPUTS = frozenset(
TRANSFORMER_ACT_NAME[activation] for activation in (ModelLayerLocation.ATTENTION_IN, ModelLayerLocation.MLP_IN)
)
[docs]
def writable(name: str, tensor: torch.Tensor) -> torch.Tensor:
"""Pick the tensor a hook writes into and hands on.
Any other activation is written in place, so the write reaches whatever else holds the tensor, which ``resid.mid``
needs: a bridge hooks it on the input of the norm before the MLP, and only an in-place write reaches the
residual stream the block keeps beside that norm. The name is the one the hook is registered under, as
``transformer_activation`` gives it, not the hook point's own: OLMo 2's ``hook_resid_mid`` is ``mlp.hook_in``
by another name.
Args:
name: The transformer activation name the hook writes.
tensor: The tensor the hook is handed.
Returns:
A copy of ``tensor`` for a sublayer's input, which only the sublayer reads, and ``tensor`` itself otherwise.
"""
return tensor.clone() if name.split(".", 2)[-1] in SUBLAYER_INPUTS else tensor