Source code for mllm_shap.value.logprob

"""Logprob-based value function.

@domain value
@see [[knowledge/architecture/value]]
@tested-by [[tests/value/test_logprob.py]]
"""

from typing import TYPE_CHECKING, ClassVar

from ..domain.generation import GenerationRecord
from ..errors import LogprobsUnavailableError
from ..protocols.backend import GenerationResult
from ..protocols.plugin import PluginOptions

if TYPE_CHECKING:
    from ..plugins.context import PluginContext


[docs] class LogprobValue: """Score a coalition by the model's confidence in its own generation. ``v(S)`` is the mean natural-log probability of the tokens the backend generated for coalition ``S`` (its ``GenerationRecord.logprobs``), so it lies in ``(-inf, 0]``; an empty generation scores 0. The base generation is not read: ``v(N)`` is the base generation's own mean logprob. """ options_model: ClassVar[type[PluginOptions]] = PluginOptions """Accepts no ``explanation.plugin_options``.""" def __init__(self, context: "PluginContext | None" = None) -> None: """Accept the plugin context; this plugin reads no settings from it.""" _ = context @property def name(self) -> str: """Return the registered value-function identifier.""" return "logprob" @property def needs_logprobs(self) -> bool: """Always true; scoring reads ``GenerationRecord.logprobs``.""" return True
[docs] def score(self, base: GenerationResult, candidate: GenerationResult) -> float: """Return the mean token logprob of ``candidate``. Raises: LogprobsUnavailableError: If ``candidate`` carries no logprobs. """ _ = base logprobs = ( candidate.logprobs if isinstance(candidate, GenerationRecord) else None ) if logprobs is None: msg = ( "value_fn 'logprob' needs token logprobs, but the generation " f"{candidate.text[:40]!r} has none" ) raise LogprobsUnavailableError(msg) return sum(logprobs) / len(logprobs) if logprobs else 0.0