FORCE#
- class braintools.optim.FORCE(alpha=1.0, *, forgetting=1.0)#
FORCE learning: RLS on the readout of a recurrent network with feedback.
FORCE (first-order reduced and controlled error) learning [1] trains the linear readout \(z = W^\top r\) of a chaotic recurrent network whose output is fed back into the network. The readout is updated by RLS at every (or every few) time steps, with a strong initial learning rate (\(P_0 = I / \alpha\), \(\alpha\) of order 1), which keeps the error small from the start and suppresses the chaos. The update rule is exactly
RLS; this class provides the FORCE defaults and the protocol documented below.- Parameters:
- Raises:
ValueError – If
alpha <= 0orforgettingis outside(0, 1].
See also
RLSthe underlying update and the
stepsignature.
Notes
Per time step: compute the rates \(r = \tanh(x)\) and the readout \(z = W^\top r\), advance the network with \(z\) fed back, then call
step(r, z, target). Wrap the time loop inbrainstate.transform.for_loopso that it compiles to a single XLA loop.References
Examples
Train a chaotic rate network (
g = 1.5) to produce a sine wave, then let it run on its own feedback:>>> import brainstate >>> import jax >>> import jax.numpy as jnp >>> import braintools >>> N, g, dt, tau = 200, 1.5, 1.0, 10.0 >>> k1, k2, k3 = jax.random.split(jax.random.PRNGKey(3), 3) >>> J = g * jax.random.normal(k1, (N, N)) / jnp.sqrt(N) >>> w_fb = jax.random.uniform(k2, (N,), minval=-1., maxval=1.) >>> x = brainstate.HiddenState(0.5 * jax.random.normal(k3, (N,))) >>> w = brainstate.ParamState(jnp.zeros((N, 1))) >>> opt = braintools.optim.FORCE(alpha=1.0) >>> _ = opt.register_trainable_weights({'readout': w}) >>> >>> def run(target, train): ... r = jnp.tanh(x.value) ... z = r @ w.value ... x.value = x.value + dt / tau * (-x.value + J @ r + w_fb * z[0]) ... if train: ... opt.step(r[None], z[None], target[None]) ... return z[0] >>> >>> t = jnp.arange(5000) * dt >>> target = jnp.sin(2 * jnp.pi * t / 100.)[:, None] >>> _ = brainstate.transform.for_loop(lambda y: run(y, True), target[:4000]) >>> z = brainstate.transform.for_loop(lambda y: run(y, False), target[4000:]) >>> bool(jnp.mean((z - target[4000:, 0]) ** 2) < 0.05) True