HiddenGroup#
- class braintrace.HiddenGroup#
The data structure recording a hidden-group relation.
A hidden group bundles the hidden states that are mutually connected through a recurrence transition, together with the jaxpr that computes that transition
\[h_1^t, h_2^t, \ldots = f(h_1^{t-1}, h_2^{t-1}, \ldots, x^t).\]- Variables:
index (int) – Position of this group in the compiled group sequence.
hidden_paths (list of Path) – The module path to each hidden state in the group.
hidden_states (list of brainstate.HiddenState) – The hidden states in the group.
hidden_invars (list of HiddenInVar) – The input jaxpr
Varof each hidden state (at the previous step).hidden_outvars (list of HiddenOutVar) – The output jaxpr
Varof each hidden state (at the current step).transition_jaxpr (Jaxpr) – The jaxpr computing the hidden-state transition for the group.
transition_jaxpr_constvars (list of Var) – The other input variables required to evaluate
transition_jaxpr.is_diagonal_recurrence (bool) – Whether the recurrence is diagonal across the leading
varshapepositions (see the field comment for the full contract).snap (SnapPattern or None) – The SnAp-n neighbourhood the trace is widened onto (
recurrence_scope='sparse_n');Nonefor every other scope.descent (GroupDescent or None) – Descent context when this group’s transition is one substep of a descended scan (Phase 4 structured scan descent);
Nonefor ordinary groups.
See also
find_hidden_groups_from_moduleBuild hidden groups directly from a model.
Examples
>>> import brainstate >>> import braintrace >>> gru = braintrace.nn.GRUCell(3, 4) >>> _ = brainstate.nn.init_all_states(gru) >>> inputs = brainstate.random.randn(3) >>> hidden_groups, _ = braintrace.find_hidden_groups_from_module(gru, inputs) >>> len(hidden_groups) 1
- static __new__(_cls, index, hidden_paths, hidden_states, hidden_invars, hidden_outvars, transition_jaxpr, transition_jaxpr_constvars, is_diagonal_recurrence=True, snap=None, descent=None)#
Create new instance of HiddenGroup(index, hidden_paths, hidden_states, hidden_invars, hidden_outvars, transition_jaxpr, transition_jaxpr_constvars, is_diagonal_recurrence, snap, descent)
- check_consistent_varshape()#
Check whether the shapes of the hidden states are consistent.
- Raises:
NotSupportedError – If the shapes of the hidden states are not consistent.
- concat_hidden(splitted_hid_vals)#
Concatenate split hidden-state values into a single array.
Concatenates a sequence of split hidden-state values along the last axis. For non-
HiddenGroupStatevalues, an extra trailing dimension is added before concatenation.- Parameters:
splitted_hid_vals (sequence of jax.Array) – A sequence of split hidden-state values, each corresponding to a hidden state in the group.
- Returns:
jax.Array – A single array containing all hidden-state values concatenated along the last axis.
- Raises:
ValueError – If
splitted_hid_valsdoes not have exactly one entry per hidden state in the group.
Notes
The length check is not decorative. Before it existed this method zipped the value list against
hidden_states, andziptruncates to the shorter argument: a short value list produced a concatenated array with a too-narrow trailing axis instead of an error, so a mis-routed cotangent surfaced later as a shape mismatch in unrelated trace math – or not at all, when the widths happened to coincide. It is anif ... raiseand not anassertso thatpython -Ocannot strip it.The check reads only Python-level lengths, never array data, so it costs nothing in the compiled program.
- descent#
Alias for field number 9
- diagonal_jacobian(hidden_vals, input_vals)#
Compute the diagonal Jacobian matrix along the last dimension.
- Parameters:
hidden_vals (sequence of jax.Array) – The hidden-state values.
input_vals (PyTree) – The input values.
- Returns:
jax.Array – The per-position block-diagonal of the recurrent Jacobian
d h^t / d h^{t-1}, with shape(*varshape, num_states, num_states)– or, whensnapis set, the SnAp-n widened operator of shape(*varshape, trace_state_width, trace_state_width)whose entry[p, (k, a), (k', b)]isd h^t[nbr[p,k], a] / d h^{t-1}[nbr[p,k'], b]. Entry[p, a, b]isd h^t[p, a] / d h^{t-1}[p, b]– the cross-position termsd h^t[p] / d h^{t-1}[q](p != q) are intentionally dropped (the D-RTRL / e-prop diagonal approximation).
Notes
For diagonal recurrence (
is_diagonal_recurrenceisTrue) the positions are independent, so the cheap column-sum produced byjacrev_last_dimalready equals this block diagonal. For coupled recurrence the column sum would instead add in the off-diagonal cross-position terms – inflating every entry and driving the eligibility trace to overflow – so the true block diagonal is extracted directly viablock_diagonal_last_dim.When the transition contains a
whileequation (an opaque forward node), reverse-mode differentiation is unavailable (JAX has no transpose rule forwhile), so the Jacobian is extracted in forward mode instead (jacfwd_last_dim, orblock_diagonal_last_dimwithuse_forward_mode=True) – same values, different derivative mode.
- dict()#
Return this group’s named fields as a plain dictionary.
- Returns:
dict – An ordered mapping from field name to value, as produced by the underlying
typing.NamedTuple.
- full_jacobian(hidden_vals, input_vals)#
Compute the complete within-group hidden-to-hidden Jacobian.
The sibling of
diagonal_jacobian()that keeps the cross-position terms that method drops. Selected by the graph executor when the algorithm’strace_factorizationis'random_projection': UORO’s rank-1 estimator is unbiased for the recursion it rolls, so rolling the block diagonal would make it an unbiased estimate of an already-biased trace (matrix rule 11 rejects that coordinate).- Parameters:
hidden_vals (sequence of jax.Array) – The hidden-state values.
input_vals (PyTree) – The input values.
- Returns:
jax.Array – Shape
(*varshape, num_state, *varshape, num_state), with entry[p, a, q, b] = d h^t[p, a] / d h^{t-1}[q, b].
Notes
snapis ignored: the SnAp neighbourhood is a sparsity pattern for a stored trace, and this Jacobian is consumed immediately by a matrix-vector product rather than stored, so there is nothing to sparsify. Rule 11 rejectsrecurrence_scope='sparse_n'under'random_projection'for that reason, so the combination cannot reach here.The Jacobian is only full if the recurrent ETP mixing was traced into the transition, i.e. under
include_recurrent_mixing. Rule 11 guarantees that by requiringrecurrence_scope='coupled'.
- hidden_invars#
Alias for field number 3
- hidden_outvars#
Alias for field number 4
- hidden_paths#
Alias for field number 1
- hidden_states#
Alias for field number 2
- index#
Alias for field number 0
- is_diagonal_recurrence#
Alias for field number 7
- property num_state#
The number of hidden states.
- Returns:
int – The total number of hidden states across the group.
- snap#
Alias for field number 8
- split_hidden(concat_hid_vals)#
Split a concatenated hidden-state array into individual arrays.
Splits a concatenated array of hidden-state values into separate arrays, one per hidden state in the group.
HiddenGroupStateand non-HiddenGroupStatevalues are handled differently.- Parameters:
concat_hid_vals (jax.Array) – A concatenated array of hidden-state values. The last dimension is assumed to contain the concatenated states.
- Returns:
list of jax.Array – A list of split hidden-state arrays. For non-
HiddenGroupStatevalues, the last dimension is squeezed.- Raises:
ValueError – If the trailing axis of
concat_hid_valsis notnum_statewide, i.e. the array is not this group’s concatenated slab.
Notes
The width check is the inverse of
concat_hidden()’s length check and closes the same silent path.u.math.splitat this group’s cumulative boundaries returns one part per hidden state plus a trailing remainder, and that remainder is dropped by thezipbelow – so a too wide slab silently loses its surplus, and a too narrow one silently yields empty parts. Like the sibling check this is anif ... raiserather than anassertsopython -Ocannot strip it, and it reads only the static shape.
- property trace_state_width#
The width of a trace leaf’s trailing axis.
num_statenormally;K * num_stateunder SnAp-n, where the trailing axis carries a(neighbour, state)pair rather than a state alone. Every trace allocation, recursion and solve reads this rather thannum_state, which keeps the per-primitive kernels – all generic in that axis’s size – untouched.- Returns:
int – The trailing-axis width of this group’s trace leaves.
- transition(hidden_vals, input_vals)#
Compute the hidden-state transitions.
Evaluates the group transition jaxpr
\[h_1^t, h_2^t, \cdots = f(h_1^{t-1}, h_2^{t-1}, \cdots, x^t).\]- Parameters:
hidden_vals (sequence of jax.Array) – The old hidden-state values.
input_vals (PyTree) – The input values.
- Returns:
list of jax.Array – The new hidden-state values.
- transition_jaxpr#
Alias for field number 5
- transition_jaxpr_constvars#
Alias for field number 6
- property varshape#
The shape of each state variable.
- Returns:
tuple of int – The variable shape shared by the hidden states in the group.
- HiddenGroup.__init__()#