API reference
Signals
Whatever grades your rollouts, can the same instruments attach to it? A signal is the yes. reward_lens.signals defines one protocol and eight adapters that satisfy it, so a classifier reward model, an LLM judge, a DPO checkpoint, and a process reward model all present the same surface to everything downstream. The tour with runnable code is in models and signals.
The protocol
RewardSignal is a runtime-checkable protocol: a signal declares its capabilities, its readouts, and its positions, and answers score, score_prefixes, and capture. Anything that implements it is a first-class citizen of the library.
reward_lens.signals.base.RewardSignal
@runtime_checkable
Bases: Protocol
The substrate abstraction: any reward signal with white-box access (section 2.3.2).
Eight adapters implement this (classifier, judge, process, implicit, rubric, trajectory, dense, ensemble). An Observable written against this protocol runs on all of them; a new grader paradigm the field invents becomes a new adapter passing the conformance suite, and the whole battery, every index, and every science become available to it for free (the extensibility contract, section 5.3).
caps declares capabilities (R3); readouts lists the readouts the signal exposes;
score and score_prefixes return Evidence; capture returns a handle to activations
(possibly cached); with_interventions returns a wrapped signal any Observable accepts
unchanged; tokenize owns span carry-through.
Attributes
| Name | Type | Default |
|---|---|---|
meta | SignalMeta | |
caps | Capability | |
runtime | Runtime |
Methods
readouts() -> list[Readout]
src
score(view: DataView, readout: str = 'reward') -> Any
src
score_prefixes(view: DataView, readout: str = 'reward') -> Any
src
capture(view: DataView, spec: CaptureSpec) -> CaptureHandle
src
with_interventions(*ivs: Intervention = ()) -> RewardSignal
src
tokenize(item: Any) -> TokenizedInput
src
A readout is a named way to read a scalar off the model, and a position spec says where along the sequence to read it. “The reward at the final token” is a Readout at a PositionSpec("final").
reward_lens.signals.base.Readout
@dataclass(frozen=True)
A first-class readout: what to read, where, and how (section 2.3.1).
name is the human key (“reward”, “verdict”, “criterion:coherence”, “quantile:0.9”). For
linear and logit_diff readouts, vector is the direction w (fp32) the scalar is
projected onto; for simplex (Likert over score tokens) and token_value (per-token
value) the meaning is carried in meta. site is where the readout reads, usually the
final residual stream; position says at which token(s). This object is the pivot of R4:
it is architecturally resolved by adapters at load time (w_r is read off the checkpoint, not
probe-extracted), so there is no “is this feature real” regress at the readout (I1, property 2
in section 1.1).
Attributes
| Name | Type | Default |
|---|---|---|
name | str | |
kind | ReadoutKind | |
site | Site | |
position | PositionSpec | |
vector | Any | None |
meta | dict[str, Any] | field(default_factory=dict) |
reward_lens.signals.base.PositionSpec
@dataclass(frozen=True)
A resolvable specification of which token positions a readout reads (section 2.3.1).
Nothing in the kernel hardcodes “final token” (R4). A classifier head reads at final; a
process reward model reads at step_ends; a generative judge reads at judgment (the
verdict token, whose location the signal detects and validates); a dense reward reads at
all. detail carries the kind-specific configuration (the span kind for span_ends,
the explicit indices for explicit, the delimiter config or detected index for
judgment).
Attributes
| Name | Type | Default |
|---|---|---|
kind | PositionKind | 'final' |
detail | Any | None |
Methods
resolve(tokens: TokenizedInput) -> list[int]
src
The position-only kinds (final, all, explicit, and span-derived kinds when
the spans are present) resolve here with no model knowledge. judgment is resolved by
the signal, which detects the verdict position from the chat template and validates it;
when a signal has done that detection it passes the resolved index through detail, so
this method honours an explicit detail index list for judgment as well.
Loading a signal
Two entry points are always available and touch no network: wrap_hf_model around a model and tokenizer you already hold, and from_tiny for a synthetic Llama that builds on CPU in under a minute. Both run a conformance quickcheck as they construct.
reward_lens.signals.loaders.wrap_hf_model
wrap_hf_model(
model: torch.nn.Module,
tokenizer: Any,
adapter: Any = None,
*,
device: str = 'cpu',
numerics: Any = None,
adapter_id: str | None = None,
architecture: str | None = None,
max_length: int = 2048,
lineage: dict[str, Any] | None = None,
conformance_quickcheck: bool = True
) -> ClassifierRM Build a ClassifierRM from an already-loaded model + tokenizer (no download).
Resolves the adapter (v1 dispatch) if not given, builds the SiteMap and numerics policy,
fingerprints the model, reads the reward head into readouts, and runs a fast conformance
quick-check (determinism plus readout-matches-head on two trivial inputs) unless disabled. This
is the constructor the tests and the tiny-model path use, and the one the hub loader ends at once
it has a model in hand.
reward_lens.signals.loaders.from_tiny
from_tiny(
*,
d_model: int = 32,
n_layers: int = 2,
n_heads: int = 4,
seed: int = 0,
vocab_size: int | None = None,
seq_max: int = 256,
tokenizer_name: str = 'gpt2',
conformance_quickcheck: bool = False
) -> ClassifierRM Construct the tiny synthetic ClassifierRM the tests run on, entirely offline.
A real LlamaForSequenceClassification (hidden 32, 2 layers, 4 heads, num_labels=1) so the
adapter, hooks, readout, grad, and hvp see the same module tree they will see on an 8B Skywork
model; only the magnitudes differ. The tokenizer defaults to gpt2 (cached, fast, offset-capable);
if gpt2 cannot be loaded offline, a minimal byte-level tokenizer is used so the tests still run
with no network (section: hardware reality).
load_signal is the front door for a repo id, but it is gated. Handed a hub id without allow_download=True, it raises NotImplementedError naming itself and pointing you at wrap_hf_model or from_tiny, because an 8B model in fp32 does not fit a laptop GPU and the loader will not pretend otherwise. Local paths bypass the gate.
reward_lens.signals.loaders.load_signal
load_signal(spec: str | SignalSpec, **overrides: Any = {}) -> ClassifierRM Load a signal from an HF id, a local path, or a SignalSpec (section 2.3.4).
Sniffs the loading convention from the config architecture and head names, chooses the adapter
and numerics policy, then loads the weights and delegates to wrap_hf_model. The weight load
for the 8B/27B campaign models is GPU/download-gated: unless allow_download=True is set (and
the machine can hold the model), this raises a clear, marked error rather than attempting a
multi-gigabyte download on hardware that cannot run it. Ambiguous conventions raise with the
candidate list, never a silent guess.
The eight adapters
Each adapter wraps a family of grader and advertises exactly the capabilities it can honor. The instruments read those capabilities and refuse rather than fake a measurement the substrate cannot support. Every adapter has its own page under models and signals.
ClassifierRM is the reference case: a scalar reward head on a sequence classifier, with the full capability set down to the linear readout and Hessian-vector products.
reward_lens.signals.classifier.ClassifierRM
ClassifierRM(
*,
runtime: HFRuntime,
meta: SignalMeta,
readouts: list[Readout],
tokenizer: Any,
policy: NumericsPolicy,
max_length: int = 2048,
default_batch_size: int = 16,
interventions: tuple[Any, ...] = (),
legacy_row_mean: Readout | None = None
) A sequence-classification reward model as a RewardSignal (section 2.3.3).
Build it through signals.loaders.wrap_hf_model / from_tiny (which resolve the adapter,
site map, head, policy, and fingerprint); direct construction is for the loader and tests. The
signal holds a HFRuntime, the numerics policy, the readouts read off the head, and the
tokenizer. caps declares its capabilities (R3); meta carries the fingerprint, lineage,
template, and numerics policy.
Methods
readouts() -> list[Readout]
src
A single-row head exposes one reward readout. A multi-row head exposes one
criterion:k readout per row plus a reward composite; the row-mean aggregate is
available separately as a documented legacy readout, never the default.
readout(name: str = 'reward') -> Readout
src
reward_scalar_fn(readout: str = 'reward')
src
ScalarFn computing the readout scalar from a RawOutput (for grad/hvp).
The closure reads the grad-attached head input from RawOutput.extra and projects it onto
the readout vector in fp32, pooling at the resolved final positions. Passed straight into
runtime.grad/runtime.hvp; that is how the M1 Hessian test differentiates the reward.
tokenize(item: Any) -> TokenizedInput
src
Applies the model’s chat template when it has one (else a plain User:/Assistant:
fallback, which is what the gpt2-tokenizer tiny model uses), and requests offset mapping from
the fast tokenizer so span-level patching and attribution stay exact. Explicit character
spans on the item (over the templated text) are mapped into token coordinates and carried on
the TokenizedInput; this is the load-bearing, unglamorous part of the protocol.
score(view: Any, readout: str = 'reward') -> Evidence[Scores]
src
Evidence[Scores] (section 2.3.2).
Each score is the fp32 projection of the item’s final head-input hidden state onto the readout vector (R11). Gauge is INVARIANT (a raw score is gauge-free); trust is EXPLORATORY (no scorecard entry yet, gate 1). Provenance records the token cost and the wall time.
score_prefixes(view: Any, readout: str = 'reward') -> Evidence[TokenCurves]
src
r(y_{1:t}) for every item (section 2.3.2).
One forward per batch: the head input at every valid position is projected onto the readout
vector, and because the classifier pools the last token under causal attention, the value at
position t is exactly the reward the model assigns the prefix ending at t. The final
entry of each curve therefore equals score(...) for that item, which the conformance
suite asserts.
capture(view: Any, spec: CaptureSpec) -> CaptureHandle
src
CaptureHandle (section 2.3.2).
Collates the whole view into one left-padded batch and runs forward_with_capture under
any mounted interventions, returning an in-memory handle. Population-scale, store-backed
streaming is runtime.store.ActivationStore.get_or_compute; this method is the direct,
single-batch path the store calls on a miss.
with_interventions(*ivs: Any = ()) -> ClassifierRM
src
Each intervention is compiled against this signal (if it exposes compile) and mounted on
the runtime’s shared hook path during scoring and capture. The intervention fingerprints
become part of the wrapped signal’s subject, so an intervened Evidence can never masquerade
as a clean one. Interventions land as a full subsystem in M6; this is the signal-side wiring.
GenerativeJudge reads a verdict as the logit difference between two answer tokens. On a tiny model that verdict is near chance; it needs a real instruction-tuned model to mean anything.
reward_lens.signals.judge.GenerativeJudge
Bases: SignalImplBase
GenerativeJudge(
*,
runtime: HFRuntime,
meta: Any,
policy: Any,
tokenizer: Any,
readouts: Sequence[Readout],
max_length: int = 2048,
default_batch_size: int = 16,
interventions: tuple[Any, ...] = ()
) -> None An LLM-as-judge as a RewardSignal (section 2.3.3, adapter 2).
Build it through from_tiny (the offline test vehicle) or from_causal_lm (an
already-loaded instruct model). The verdict readouts are logit_diff directions read off the
LM head; the Likert readout is a simplex over score tokens. score dispatches on the
readout kind: a projection for the logit-diff verdicts, an expected value under the score-token
softmax for the Likert.
Methods
score(view: Any, readout: str | None = None) -> Any
src
Evidence[Scores] (section 2.3.2).
logit_diff readouts (verdict, verdict_ab) project the final hidden state onto the
readout direction in fp32: h . (W_U[a] - W_U[b]) is exactly logit(a) - logit(b) for
the token the model is about to emit. The simplex readout (likert) returns the
expected score under the softmax over the score tokens. Gauge INVARIANT, trust EXPLORATORY.
score_prefixes(view: Any, readout: str | None = None) -> Any
src
verdict(y_{1:t}) for every item (section 2.3.2).
For a logit_diff readout the curve at position t is the verdict the model would emit
if the sequence ended at t; its final entry equals score. Only defined for the
logit-diff verdicts (a simplex has no single direction to trace); raises otherwise.
validate_judgment_position(
calibration_items: Sequence[Any],
k: int = 4
) -> dict[str, Any]
src
Detection is structural: templating with the generation prompt makes the final valid token
the judgment position. Validation runs a forward over up to k calibration prompts and
checks how often the model’s greedy next token there is one of the verdict tokens; the
fraction is the detection confidence. On the random tiny model this is near chance and is
recorded honestly. The production path samples a real instruct model, which this structure is
ready for but does not stand in for. Returns the detection record stored in meta.lineage.
from_causal_lm(
model: torch.nn.Module,
tokenizer: Any,
*,
yes: str = 'Yes',
no: str = 'No',
option_a: str = 'A',
option_b: str = 'B',
likert: Sequence[str] = ('1', '2', '3', '4', '5'),
device: str = 'cpu',
architecture: str | None = None,
lineage: dict[str, Any] | None = None,
validate_with: Sequence[Any] | None = None
) -> GenerativeJudge
src
CausalLM + tokenizer as a judge (no download).
Reads the verdict directions off the LM head: W_U[yes] - W_U[no] for the pointwise
verdict, W_U[A] - W_U[B] for the pairwise, and the score-token ids for the Likert
simplex. Runs the judgment-position validation on validate_with if given (else a small
built-in calibration set). This is the entry point a real instruct judge uses on adequate
hardware; from_tiny calls it on the synthetic model.
from_tiny(
*,
d_model: int = 32,
n_layers: int = 2,
n_heads: int = 4,
seed: int = 0,
seq_max: int = 256,
tokenizer_name: str = 'gpt2'
) -> GenerativeJudge
src
A real LlamaForCausalLM (hidden 32, 2 layers) with a real tokenizer, so the adapter,
hooks, LM-head capture, and logit-diff readout see the same module tree a production judge
would; only the magnitudes differ, and the weights are random so no verdict is meaningful.
The verdict mechanism (reading W_U[Yes] - W_U[No] off the head) is exact and real.
ProcessRM scores per step. The delimiter step-split works; the learned boundary detector is a stub that falls back to treating the whole response as one step, and it says so in its metadata rather than inventing boundaries.
reward_lens.signals.process.ProcessRM
Bases: SignalImplBase
ProcessRM(
*,
runtime: HFRuntime,
meta: Any,
policy: Any,
tokenizer: Any,
readouts: Sequence[Readout],
delimiter: str = '\n',
max_length: int = 2048,
default_batch_size: int = 16,
interventions: tuple[Any, ...] = ()
) -> None A step-level reward model as a RewardSignal (section 2.3.3, adapter 3).
Build it through from_tiny or from_sequence_classifier. score returns the outcome
scalar (the final-token reward of the whole solution, identical to a classifier); step_scores
returns the per-step reward vector read at the detected step boundaries. The step delimiter is
configurable; the default is a newline.
Methods
score(view: Any, readout: str | None = None) -> Any
src
score_prefixes(view: Any, readout: str | None = None) -> Any
src
step_scores(view: Any, readout: str | None = None) -> Any
src
For each item the head input at each step-end token is projected onto the reward direction in
fp32, giving one score per reasoning step. Returns Evidence[StepScores]; the last step’s
score equals the outcome score because the final step ends at the final token.
from_sequence_classifier(
model: torch.nn.Module,
tokenizer: Any,
*,
delimiter: str = '\n',
device: str = 'cpu',
architecture: str | None = None,
lineage: dict[str, Any] | None = None
) -> ProcessRM
src
Reads the scalar reward head (score) direction into a single reward readout whose
position is step_ends rather than final (R4). A production PRM would be a checkpoint
trained with a step-level objective; the adapter’s mechanics are identical either way.
from_tiny(*, seed: int = 0, delimiter: str = '\n', **kw: Any = {}) -> ProcessRM
src
ImplicitRM reads a reward as the DPO log-ratio between a policy and its reference, so a checkpoint you never trained a reward head for becomes a signal.
reward_lens.signals.implicit.ImplicitRM
Bases: SignalImplBase
ImplicitRM(
*,
policy_runtime: HFRuntime,
reference_runtime: HFRuntime,
meta: Any,
reference_meta: Any,
policy: Any,
tokenizer: Any,
beta: float = 0.1,
max_length: int = 2048,
default_batch_size: int = 16,
interventions: tuple[Any, ...] = ()
) -> None The DPO implicit reward r-hat = beta * sum log-ratio as a RewardSignal (adapter 4).
Constructed from a policy model and a reference model (from_models / from_tiny), both
CausalLM with a shared tokenizer. score returns r-hat; score_prefixes returns the
cumulative per-token reward whose last entry equals r-hat; per_token_rewards returns the raw
per-token decomposition (the increments). self.runtime is the policy runtime; the reference
runtime is self.reference_runtime and capture(..., namespace="ref") routes to it.
Methods
score(view: Any, readout: str | None = None) -> Any
src
score_prefixes(view: Any, readout: str | None = None) -> Any
src
score (section 2.3.2).
The curve is the running sum of the per-token log-ratio rewards over the response, so
curve[-1] == r-hat, which is the prefix-consistency invariant conformance checks. The raw
increments (the native per-token decomposition) are per_token_rewards.
per_token_rewards(view: Any, readout: str | None = None) -> Any
src
Each item’s curve is beta * (log pi_policy(y_t) - log pi_ref(y_t)) over the response
tokens; the increments sum to the sequence score. This is the decomposition the verification
and dense-reward sciences consume directly rather than reconstructing by attribution.
capture(view: Any, spec: Any, namespace: Literal['policy', 'ref'] = 'policy') -> Any
src
namespace="ref" captures from the reference model instead. The two runtimes are distinct
models, so a caller must say which one it means; there is no shared “layer L”. Interventions
mount on the chosen runtime.
from_models(
policy: torch.nn.Module,
reference: torch.nn.Module,
tokenizer: Any,
*,
beta: float = 0.1,
device: str = 'cpu',
architecture: str | None = None
) -> ImplicitRM
src
CausalLM (shared tokenizer) as an implicit RM (no download).from_tiny(
*,
policy_seed: int = 1,
reference_seed: int = 2,
beta: float = 0.1,
**kw: Any = {}
) -> ImplicitRM
src
LlamaForCausalLM (distinct seeds) sharing a tokenizer (adapter 4).RubricRM exposes one readout per criterion, and TrajectoryRM scores typed spans of an agent trace.
reward_lens.signals.rubric.RubricRM
Bases: SignalImplBase
RubricRM(
*,
runtime: HFRuntime,
meta: Any,
policy: Any,
tokenizer: Any,
readouts: Sequence[Readout],
spec: RubricSpec,
max_length: int = 2048,
default_batch_size: int = 16,
interventions: tuple[Any, ...] = ()
) -> None A rubric grader as a RewardSignal (section 2.3.3, adapter 5).
Build it through from_tiny (a tiny multi-label classifier) or from_sequence_classifier
(a real multi-objective head). readouts exposes one criterion:<name> per criterion plus a
weighted reward aggregate; score projects the final hidden state onto whichever direction
the readout names. The rubric spec is on self.spec.
Methods
default_readout_name() -> str
src
score resolves to the aggregate reward readout.score(view: Any, readout: str | None = None) -> Any
src
score_prefixes(view: Any, readout: str | None = None) -> Any
src
criterion_scores(view: Any) -> dict[str, Any]
src
criterion name -> Evidence[Scores] for the whole rubric.from_sequence_classifier(
model: torch.nn.Module,
tokenizer: Any,
spec: RubricSpec,
*,
device: str = 'cpu',
architecture: str | None = None,
lineage: dict[str, Any] | None = None
) -> RubricRM
src
Requires the head to have one row per criterion. Reads each row into a criterion:<name>
readout and builds the weighted-sum reward aggregate whose vector is
sum_k weight_k * row_k (so the aggregate is itself a single fp32 projection).
from_tiny(
*,
criteria: Sequence[str] = ('coherence', 'correctness', 'safety'),
weights: Sequence[float] = (),
seed: int = 0,
**kw: Any = {}
) -> RubricRM
src
reward_lens.signals.trajectory.TrajectoryRM
Bases: SignalImplBase
TrajectoryRM(
*,
runtime: HFRuntime,
meta: Any,
policy: Any,
tokenizer: Any,
readouts: Sequence[Readout],
max_length: int = 2048,
default_batch_size: int = 16,
interventions: tuple[Any, ...] = ()
) -> None A trajectory-level reward model as a RewardSignal (section 2.3.3, adapter 6).
Build it through from_tiny or from_sequence_classifier. tokenize accepts a
Trajectory (rendering its steps with receipt/narrative/action span typing) or a plain
(prompt, response) item (the classifier rendering, so the conformance suite’s generic checks
apply). score reads the reward at the trajectory scoring position (the final token).
Methods
score(view: Any, readout: str | None = None) -> Any
src
score_prefixes(view: Any, readout: str | None = None) -> Any
src
from_sequence_classifier(
model: torch.nn.Module,
tokenizer: Any,
*,
device: str = 'cpu',
architecture: str | None = None,
lineage: dict[str, Any] | None = None
) -> TrajectoryRM
src
from_tiny(*, seed: int = 0, **kw: Any = {}) -> TrajectoryRM
src
DenseRewardExtractor derives a per-token reward as the first difference of the prefix curve. It is pinned to EXPLORATORY by design: the dense attribution is a construction, not a calibrated measurement, and the trust level records that.
reward_lens.signals.dense.DenseRewardExtractor
DenseRewardExtractor(signal: Any, *, readout: str | None = None) -> None Per-token reward maps from any outcome signal, shipped GATED (section 2.3.3, adapter 7).
Wraps an outcome RewardSignal and adds dense_rewards: the first difference of the wrapped
signal’s prefix-score curve, a per-token attribution that sums to the outcome score. Every other
protocol method delegates to the wrapped signal, so the same battery reaches the dense extractor
unchanged. dense_rewards Evidence is always EXPLORATORY (no calibration is ever attached),
which is how the design enforces “certify before you trust” for dense credit assignment.
Methods
readouts() -> Any
src
tokenize(item: Any) -> Any
src
score(view: Any, readout: str | None = None) -> Any
src
dense_rewards.score_prefixes(view: Any, readout: str | None = None) -> Any
src
capture(view: Any, spec: Any) -> Any
src
with_interventions(*ivs: Any = ()) -> DenseRewardExtractor
src
dense_rewards(view: Any, readout: str | None = None) -> Evidence[TokenCurves]
src
Each item’s map is the first difference of the wrapped signal’s prefix-score curve, so token t carries r(y_{1:t}) - r(y_{1:t-1}) and the map sums to the outcome score. The Evidence is typed INVARIANT (differences of raw scores are gauge-free) but pinned EXPLORATORY: no calibration reference is attached, by construction, until the verification science certifies the map against labeled error spans. The prefix Evidence is recorded as a provenance parent.
SignalEnsemble composes several signals into one whose capabilities are the intersection, and DistributionalSignal exposes quantile readouts.
reward_lens.signals.ensemble.SignalEnsemble
SignalEnsemble(
members: Sequence[Any],
*,
mode: EnsembleMode = 'mean',
q: float = 0.5,
name: str | None = None
) -> None A composite of several member signals (section 2.3.3, adapter 8).
score scores every member under the requested readout, stacks the results, and reduces them by
mode (mean, min, max, or a quantile at q). The Evidence subject names every member by
fingerprint (member provenance), and the ensemble’s own fingerprint is derived from the members’
so two ensembles over the same members are the same subject. caps is the intersection of the
members’ capabilities, plus DISTRIBUTIONAL for a quantile composite.
Methods
readouts() -> list[Any]
src
tokenize(item: Any) -> Any
src
score(view: Any, readout: str | None = None) -> Evidence[Scores]
src
mode over the members’ scores (section 2.3.3).score_prefixes(view: Any, readout: str | None = None) -> Evidence[TokenCurves]
src
Requires the members to tokenize identically (the common case: a shared tokenizer), so the
per-item curves align in length and reduce position-wise. Prefix consistency is preserved
because mean/min/max/quantile of the members’ final entries equals the composite
score. Misaligned curve lengths raise rather than silently truncate.
member_scores(view: Any, readout: str | None = None) -> dict[ModelFP, np.ndarray]
src
capture(view: Any, spec: Any, member: int = 0) -> Any
src
with_interventions(*ivs: Any = ()) -> SignalEnsemble
src
reward_lens.signals.ensemble.DistributionalSignal
DistributionalSignal(
signal: Any,
taus: Sequence[float],
row_readouts: Sequence[str]
) -> None A distributional wrapper exposing a multi-row head’s rows as quantile readouts (adapter 8).
Wraps a signal whose head rows are quantile levels (a QRM) and presents them as quantile:tau
readouts, declaring DISTRIBUTIONAL. score(view, "quantile:0.9") returns the 0.9-quantile
row; median, quantile, and mean are convenience reductions over the levels. The wrapped
signal does the forward work; this class only relabels and reduces.
Methods
readouts() -> list[Any]
src
quantile:tau readout per level, reusing the wrapped row vectors (section 2.3.1).tokenize(item: Any) -> Any
src
score(view: Any, readout: str | None = None) -> Any
src
quantile:tau maps to the wrapped row for that level.score_prefixes(view: Any, readout: str | None = None) -> Any
src
quantile(view: Any, tau: float) -> Any
src
tau (an exact head row, not an interpolation).median(view: Any) -> Any
src
mean(view: Any) -> Evidence[Scores]
src
capture(view: Any, spec: Any) -> Any
src
with_interventions(*ivs: Any = ()) -> DistributionalSignal
src
from_tiny(
*,
taus: Sequence[float] = (0.1, 0.5, 0.9),
seed: int = 0,
**kw: Any = {}
) -> DistributionalSignal
src
Conformance
Before you trust a wrapped model, check that it behaves. run_conformance runs the classifier suite (determinism, batch-versus-single agreement, left-pad invariance, an exact readout-matches-head check in fp32, and more); run_adapter_conformance runs the checks that apply across all eight adapters. Writing your own adapter and passing these is the subject of write an adapter.
reward_lens.signals.conformance.run_conformance
run_conformance(
signal: ClassifierRM,
tol: float | None = None,
items: list[Any] | None = None
) -> ConformanceReport Run the full conformance suite against a signal (section 2.3.6).
tol defaults to the signal’s numerics-policy tolerance (1e-4). Each check is wrapped so an
exception becomes a failed (or, for the dtype matrix, a skipped) check rather than aborting the
suite, so the report always enumerates every invariant. Returns a ConformanceReport whose
passed property is the M1 acceptance gate.
reward_lens.signals.conformance_adapters.run_adapter_conformance
run_adapter_conformance(
signal: Any,
*,
items: Sequence[Any],
readout: str | None = None,
tol: float | None = None,
check_head: bool = True,
check_prefix: bool = True,
probe: tuple[Any, str, str] | None = None,
probe_inject: bool = False
) -> ConformanceReport Run the applicable conformance checks against one adapter (section 2.3.6).
items is the stimulus set (varied in length so batching forces left-padding). readout names
the readout to score under (the adapter’s default when None). check_head runs the
readout-vs-head check for adapters with a linear/logit_diff readout; pass False for composites.
probe is (item, needle, kind) for the template round-trip: the item must tokenize with a
span of kind covering needle in the rendered text. probe_inject handles adapters that
carry explicit item spans rather than auto-typing them (a rubric grader): the check renders the
item, locates needle, injects an explicit char span over the rendered text, and re-tokenizes.
Each check is wrapped so a raised exception becomes a recorded failure rather than aborting the
suite.