mixle.stats.latent.responsibility_attention module¶
Responsibility attention: one attention head as an EM-able mixture over context positions.
A single attention head, written as a generative latent-variable model. The latent z is which
context position you attend to; the “gate” is generative (the query is generated from the attended
token’s key) so the attention weights are posterior responsibilities rather than a discriminative
dot-product softmax. That one change is what makes the head fully EM-able: every M-step is a
closed-form, additively-mergeable sufficient-statistic update (a GMM mean for the keys, a weighted
categorical for the emission, counts for the position prior), so the head trains by expectation-
maximization and composes with the rest of mixle (drop it into a mixture, an HMM emission, a
composite) instead of needing gradient descent.
Generative story for one observation (context, query, target) with context tokens c_1..c_N:
z ~ Categorical(position_prior) query ~ Normal(key_means[c_z], sigma2 I) # query generated from the attended token’s key target ~ Categorical(emission[c_z, :]) # target emitted from the attended token
so p(query, target | context) = sum_i position_prior_i N(query; key_means[c_i]) emission[c_i, target]
and the attention weight on position i is the posterior p(z = i | query, target, context).
The observation is the triple (context, query, target); the context is conditioned on (it is the
covariate that defines the positions), so the density is the conditional p(query, target | context)
that EM maximizes. This is the single-hop leaf; deeper / stackable multi-hop versions compose several
of these latents (a chain is forward–backward, an HME-style tree is nested responsibilities).
This is not a new idea – it is the EM-able / generative reading of attention. Closely related prior
work: latent-alignment EM (Brown et al. 1993, IBM models; Vogel & Ney 1996, HMM word alignment),
attention-as-kernel-smoothing (Tsai et al. 2019; Ramsauer et al. 2020, modern Hopfield), hierarchical
mixtures of experts (Jordan & Jacobs 1994), and attention-as-a-latent-variable with variational
inference (Deng, Kim, Chiu, Guo & Rush 2018, “Latent Alignment and Variational Attention”). The
contribution here is packaging it as a composable, EM-fit mixle Distribution primitive – which is
exactly the “compose attention with probabilistic models / do posterior inference” gap Deng et al.
identify – and the empirical confirmation that exact marginalization (our closed-form E-step) is the
right call, matching their finding that exact latent models beat soft attention.
- class ResponsibilityAttentionDistribution(key_means, emission, position_prior=None, sigma2=1.0, name=None)[source]
Bases:
SequenceEncodableProbabilityDistributionOne generative-gate attention head; a mixture over context positions (EM-able).
- Parameters:
- density(x)[source]
Density
p(query, target | context)at one observation.
- log_density(x)[source]
Log conditional density
log p(query, target | context)at one observation(ctx, y, t).
- seq_log_density(x)[source]
Vectorized
log p(query, target | context)over an encoded batch ->(n,).
- predict_proba(context, query)[source]
Predictive target distribution
p(target | context, query)(target marginalized over z).Attention here does not see the target:
a_i ∝ pi_i N(query; K[c_i]), thenp(target) = sum_i a_i emission[c_i, :]. Accepts a single example or a batch.
- sampler(seed=None)[source]
Return a sampler for drawing observations from this distribution.
- Parameters:
seed (int | None)
- Return type:
ResponsibilityAttentionSampler
- estimator(pseudo_count=None)[source]
Return an estimator for fitting this distribution from data.
- Parameters:
pseudo_count (float | None)
- Return type:
ResponsibilityAttentionEstimator
- dist_to_encoder()[source]
Return the data encoder used by this distribution for vectorized methods.
- Return type:
ResponsibilityAttentionDataEncoder
- class ResponsibilityAttentionSampler(dist, seed=None)[source]
Bases:
DistributionSamplerJoint generative sampler (adds a uniform-distinct context prior so it is a full generator).
- Parameters:
dist (ResponsibilityAttentionDistribution)
seed (int | None)
- sample(size=None, *, batched=True)[source]
Draw observations.
Combinator samplers (mixture/sequence/…) accept
batched. Withbatched=True(the default) each child stream is drawn in one vectorized call instead of a per-draw Python loop – far faster. Because every child sampler owns an independentRandomState, batching consumes each stream in the same order as the loop, so the draws are identical to the legacy path.batched=Falseforces that legacy per-draw loop as a guaranteed- stable reference. Leaf samplers are already vectorized and ignore the flag.
- class ResponsibilityAttentionAccumulator(num_symbols, context_length, query_dim, num_targets, keys=None, name=None)[source]
Bases:
SequenceEncodableStatisticAccumulatorAccumulates the additive sufficient statistics for the responsibility-attention M-step.
- Parameters:
- update(x, weight, estimate)[source]
- Parameters:
weight (float)
estimate (ResponsibilityAttentionDistribution | None)
- Return type:
None
- seq_update(x, weights, estimate)[source]
- Parameters:
weights (ndarray)
estimate (ResponsibilityAttentionDistribution | None)
- Return type:
None
- initialize(x, weight, rng)[source]
- Parameters:
weight (float)
rng (RandomState)
- Return type:
None
- seq_initialize(x, weights, rng)[source]
- Parameters:
weights (ndarray)
rng (RandomState)
- Return type:
None
- combine(suff_stat)[source]
- Return type:
ResponsibilityAttentionAccumulator
- value()[source]
- from_value(x)[source]
- Return type:
ResponsibilityAttentionAccumulator
- key_merge(stats_dict)[source]
Pool this accumulator’s statistics into
stats_dictunder its merge key.The structural default implements the common single-key pattern: store the accumulator under
self.keysthe first time the key is seen, elsecombineinto the one already there. Accumulators with several named keys (e.g. an HMM’s init/trans/state keys) or a non-accumulator stats payload override this. AkeysofNone(the default) is a no-op.
- key_replace(stats_dict)[source]
Replace this accumulator’s statistics from the pooled
stats_dictentry (see key_merge).
- acc_to_encoder()[source]
- Return type:
ResponsibilityAttentionDataEncoder
- class ResponsibilityAttentionAccumulatorFactory(num_symbols, context_length, query_dim, num_targets, keys=None, name=None)[source]
Bases:
StatisticAccumulatorFactory- Parameters:
- make()[source]
- Return type:
ResponsibilityAttentionAccumulator
- class ResponsibilityAttentionEstimator(num_symbols, context_length, query_dim, num_targets, *, sigma2=1.0, estimate_sigma2=False, min_sigma2=1e-6, emission_smoothing=1e-6, pseudo_count=None, name=None, keys=None)[source]
Bases:
ParameterEstimatorEstimate a
ResponsibilityAttentionDistributionby closed-form EM M-steps.- Parameters:
- accumulator_factory()[source]
- Return type:
ResponsibilityAttentionAccumulatorFactory
- class ResponsibilityAttentionDataEncoder[source]
Bases:
DataSequenceEncoderEncodes a sequence of
(context, query, target)triples into stacked arrays.
- sequence_to_triples(tokens, context_length, *, num_symbols=None, embeddings=None)[source]
Unroll a token sequence into the
(context, query, target)triples this head consumes.For each prediction point
p(with a full window behind it and a next token ahead), emitscontext = tokens[p-N+1 : p+1](theNmost recent tokens, including the current one),queryderived from the current tokentokens[p](its embedding, or a one-hot), andtarget = tokens[p+1]. This is the bridge from a real sequence to the iid-triple leaf.Honest scope: with the single-hop leaf this yields an attention-weighted next-token model whose predictive is a function of the current token (an attention-flavoured bigram) – because the emission is keyed by the attended token’s identity, the prediction depends only on which token the query selects. In-context copy / induction (example-specific values) is what the multi-hop / stackable extension adds; this helper is the plumbing both share.
- Parameters:
tokens (Sequence[int]) – a 1-D sequence of integer token ids.
context_length (int) – the attention window
N.num_symbols (int | None) – vocabulary size (for the one-hot query dim); inferred from
tokensif omitted.embeddings (ndarray | None) – optional
(S, D)embedding table; if given the query isembeddings[token], otherwise a one-hot of dimensionnum_symbols.
- Returns:
A list of
(context, query, target)triples ready formixle.inference.optimize().- Return type: