UORO#
- class braintrace.UORO#
Unbiased Online Recurrent Optimization.
The coordinate is
ETraceConfig(trace_factorization='random_projection', recurrence_scope='coupled'). Both halves are load-bearing:random_projection replaces the per-parameter influence trace with one rank-1 pair per hidden group,
eps_tilde[j, u] ~= s_tilde[u] * theta_tilde[j], re-randomised each step with a Rademacher draw.coupled is required, not merely recommended (matrix rule 11). A rank-1 unbiased estimator of an already-biased recursion would be strictly worse than the biased recursion itself: same asymptotic error, more variance, no memory saved — the anchored per-parameter trace is already the smaller carrier.
coupledis the cheapest scope whose transition actually contains the hidden-to-hidden ETP mixing, so it is the coordinate where the projection buys something. Measured: rolling the block-diagonal transition converges cleanly onto the biased trace and never onto the exact one.
What follows is the claim in full, because “unbiased” on its own overstates it: UORO is an unbiased estimator of the exact within-group influence recursion that the compiled transition defines — that is, the saturating end of the
SnApscale, at SnAp-1 memory, in expectation. It does not repair cross-group coupling, the F-31 instantaneous tail, or any primitive’s own solve regime. On a single hidden group with a position-preserving elementwise tail, that recursion is itself exact, so there UORO is unbiased for BPTT; elsewhere it is unbiased for the block-local recursion. It runs on every model either way.- Parameters:
model (brainstate.nn.Module) – The one-step model.
name (str, optional) – Node name.
vjp_method (str, optional) –
'multi-step'(default) or'single-step'. The finite-window oracle path — and hence every acceptance criterion — uses'multi-step'.fast_solve (bool, optional) – Whether registered closed-form kernels may be used when building the projector. Default
True.control_flow (ControlFlowPolicy, optional) – Control-flow canonicalization policy.
projection_key (int or jax.Array, optional) – Seed for the projection stream. Default
42. Two different keys give two different gradients;reset_statere-derives the stream from this value, so a reset run repeats bit-for-bit.projection_eps (float, optional) – Guard added to every norm before its ratio. Default
1e-12;0.0makes the first step NaN, since both norms start at zero.random_feedback_key (jax.Array, optional) – Required when combining with
learning_signal='random_feedback'.snap_max_jacobian_elements (int, optional) – Passed through; unused at
recurrence_scope='coupled'.
Examples
>>> import brainstate, braintrace, jax.numpy as jnp >>> class Net(brainstate.nn.Module): ... def __init__(self): ... super().__init__() ... self.w = brainstate.ParamState(0.1 * jnp.ones((4, 4))) ... self.h = brainstate.HiddenState(jnp.ones((1, 4)) * 0.4) ... def update(self, x): ... self.h.value = jnp.tanh(x + braintrace.matmul(self.h.value, self.w.value)) ... return self.h.value >>> model = Net() >>> brainstate.nn.init_all_states(model, batch_size=1) >>> learner = braintrace.UORO(model, projection_key=0) >>> learner.compile_graph(braintrace.MultiStepData(jnp.zeros((1, 1, 4)))) >>> learner.init_etrace_state()
UORO is multi-step by construction, so
etrace_graddrives it in window mode: passchunk_size=kwithk >= 2, andstep_fnreceives a(k, ...)slice, wraps its model input inMultiStepData, and returns a(k,)vector of per-step losses rather than a scalar.>>> xs = jnp.zeros((10, 1, 4)) >>> ys = jnp.zeros((10, 1, 4)) >>> def window_loss(x, y): # x, y are (k, 1, 4) ... out = learner(braintrace.MultiStepData(x)) ... return jnp.mean((out - y) ** 2, axis=(1, 2)) # (k,) >>> grads, losses = learner.etrace_grad( ... xs, ys, step_fn=window_loss, chunk_size=5, return_value=True)
Notes
Variance grows with the number of window boundaries. The estimate is unbiased, not low-variance: a single run can be far from the mean, and averaging is the caller’s job. Antithetic sampling does not help here and looks like it should — flipping the sign of the entire draw sequence leaves the estimate bit-identical, because
rho1is even and both factors flip together, so their product is invariant.See also
braintrace.SnApthe deterministic scale whose saturating end this estimates, at higher memory.
braintrace.D_RTRLthe diagonal-scope biased trace.
- UORO.__init__(model, name=None, vjp_method='multi-step', fast_solve=True, control_flow=None, projection_key=42, projection_eps=1e-12, random_feedback_key=None, snap_max_jacobian_elements=16777216)#