def make_attn_weighted_value_scalar_deriver(
    dst_config: DstConfig,
) -> ScalarDeriver:
    """Returns a scalar deriver for the attention value weighted by the post-softmax
    attention between each pair of tokens. Output shape: (n_tokens, n_attended_to_tokens, n_heads, v_channels)
    """

    def attn_weighted_value_tensor_calculate_derived_scalar_fn(
        raw_activation_data_tuple: tuple[torch.Tensor, ...],
        layer_index: LayerIndex,
        pass_type: PassType,
    ) -> torch.Tensor:
        assert len(raw_activation_data_tuple) == 2, ([t.shape for t in raw_activation_data_tuple],)
        assert pass_type == PassType.FORWARD, "weighted value only implemented for forward pass"
        attn_post_softmax, attn_value = raw_activation_data_tuple
        _check_attn_post_softmax_shape(attn_post_softmax)
        attn_weighted_value = torch.einsum("fth,thd->fthd", attn_post_softmax, attn_value)
        return attn_weighted_value

    return ScalarDeriver(
        dst=DerivedScalarType.ATTN_WEIGHTED_VALUE,
        dst_config=dst_config,
        sub_scalar_sources=(
            RawScalarSource(
                activation_location_type=ActivationLocationType.ATTN_QK_PROBS,
                pass_type=PassType.FORWARD,
            ),
            RawScalarSource(
                activation_location_type=ActivationLocationType.ATTN_VALUE,
                pass_type=PassType.FORWARD,
            ),
        ),
        tensor_calculate_derived_scalar_fn=attn_weighted_value_tensor_calculate_derived_scalar_fn,
    )
Returns a scalar deriver for the attention value weighted by the post-softmax
    attention between each pair of tokens. Output shape: (n_tokens, n_attended_to_tokens, n_heads, v_channels)
    
neuron_explainer/activations/derived_scalars/attention.py