mixle.experimental.program module¶
Declarative optimization programs (differentiable games) over parameter groups and objectives.
The whole zoo of “fit this model” – supervised, LoRA fine-tuning, multi-objective, GANs, constrained optimization, policy-gradient RL, continual learning, and classical EM – is one idea at the optimization level: a program built from MOVES and COMBINATORS.
A move is minimize / maximize an objective over scoped parameters (
minimize(),maximize()). Anem(...)step on a mixle estimator is also a move, so probabilistic and neural models compose in one program.Scoped parameters decide which tensors move:
trainable(),freeze(),subset(), andlora()(low-rank adapters – the base stays frozen).Combinators schedule the moves:
weighted()(cooperative / multi-objective),alternate()(adversarial / coordinate / EM).constrain()adds a Lagrange-multiplier dual player (constrained optimization is the same min-max game as a GAN).reinforce()turns a sampled reward into a score-function objective (RL).fit()runs the program.
Examples:
fit(minimize(nll, over=trainable(net))) # supervised
fit(minimize(lm_loss, over=lora(model, rank=8))) # LoRA fine-tune
fit(weighted([(recon, 1.0), (kl, beta)], over=trainable([enc, dec]))) # multi-objective (VAE)
fit(alternate(minimize(d_loss, over=D), minimize(g_loss, over=G))) # GAN
fit(minimize(f, over=th), constraints=[constrain(g, 0.0, "<=")]) # constrained (primal-dual)
fit(maximize(reinforce(sample_reward), over=policy)) # policy-gradient RL
fit(weighted([(new_loss, 1.0), (replay_loss, 1.0)], over=net)) # continual learning (replay)
Torch is imported lazily, so this module imports without it; the gradient moves require torch, the em
move requires only mixle estimators.
- trainable(module)[source]
All
requires_gradparameters of a module (or a list of modules).
- freeze(module)[source]
Freeze a module in place (
requires_grad = False) and return it – e.g. a teacher / old checkpoint.
- subset(module, *name_substrings)[source]
Trainable parameters whose name contains any of
name_substrings(partial fine-tuning).
- class LoRALinear(base, rank, alpha)[source]
Bases:
objectA
torch.nn.Modulewrapping a frozenLinearwith a trainable low-rank adapterB @ A.
- lora(module, rank=8, alpha=16.0)[source]
Replace every
Linearundermodulewith a LoRA adapter (base frozen) and return the adapter params.The module’s forward now routes through low-rank adapters; only the
A/Bmatrices are trainable, sominimize(loss, over=lora(model, rank=8))fine-tunes a large model cheaply.
- class Move(objective, params, sign, lr=None)[source]
Bases:
objectMinimize (
sign=+1) or maximize (sign=-1)objective()overparams(a list of tensors).
- minimize(objective, over, lr=None)[source]
- maximize(objective, over, lr=None)[source]
- class EMMove(estimator, data, init)[source]
Bases:
objectAn EM step on a mixle estimator – a first-class move, so stats models join the program.
move.modelis the current fitted distribution; other moves’ objectives may read it (e.g. a gating network reading the mixture’s responsibilities), making neural<->stats coupling one program.- Parameters:
estimator (Any)
data (Sequence)
init (Any)
- property model: Any
- em(estimator, data, init)[source]
A mixle EM step as a move.
initis the starting distribution (the E-step needs a current model).
- alternate(*items)[source]
Run each move (or sub-program) once per round, in order – GANs, EM, coordinate ascent.
- Parameters:
items (Any)
- Return type:
Program
- weighted(terms, over)[source]
A single move minimizing
sum(w * objective() for objective, w in terms)– cooperative multi-objective.
- constrain(g, bound=0.0, kind='<=')[source]
g() <= bound(or>=). Passed tofit()asconstraints=[...]; enforced by dual ascent.
- reinforce(sample_and_reward)[source]
Wrap
sample_and_reward() -> (log_probs, rewards)into the score-function surrogateE[r·logπ].Maximizing it gives the policy gradient
E[r·∇logπ].log_probsare the log-probabilities of the sampled actions (carry grad);rewardsare detached returns.
- fit(program, steps=1000, lr=1e-3, constraints=None, callback=None, data=None, steps_per_chunk=1)[source]
Run an optimization program; each round runs every move once, in order.
Gradient moves take one optimizer step (Adam, per-move learning rate
move.lror the globallr);emmoves take one EM step.constraintsadd dual-ascent multiplier moves (primal-dual).Fixed mode (
datais None): runstepsrounds. Streaming mode (datais aStream): advance through the data chunks – the parameters/optimizers persist across chunks (warm-started), runningsteps_per_chunkrounds per chunk; objectives readstream.current. This is the continuous-pretraining loop (combine the task loss with an anti-forget term viaweighted()). Returns the program updated in place.
- class Stream(chunks)[source]
Bases:
objectA holder over an iterable of data chunks.
fit(data=stream)advances it each round; objectives readstream.current(the active chunk). The model’s parameters persist across chunks (warm-started).- Parameters:
chunks (Iterable)
- advance()[source]
- Return type:
None
- class ReplayBuffer(capacity=16)[source]
Bases:
objectFixed-capacity FIFO of past chunks, for replay-based anti-forgetting.
- Parameters:
capacity (int)
- snapshot(params)[source]
Detached clones of
params– the anchor forewc()/ L2-SP regularization.
- replay(loss_fn, buffer)[source]
An objective averaging
loss_fn(chunk)over the replay buffer – a term forweighted().
- distill(student_out, teacher_out)[source]
MSE distillation: keep student outputs near a frozen teacher’s (logit/feature matching anti-forget).
- ewc(params, fisher, anchor, weight=1.0)[source]
Elastic Weight Consolidation penalty
weight · Σ Fᵢ (θᵢ - anchorᵢ)²– anchors params important to the old task. Pair withfisher_diagonal()(a torch net) or a mixle leaf’sto_fisher.
- fisher_diagonal(net, batches, kind='classification')[source]
Diagonal Fisher information for EWC, using MODEL-sampled labels so it does NOT vanish at convergence.
kind='classification'(netreturns logits) or'regression'(netreturns a Gaussian mean). Returns one tensor per trainable parameter. (The naive data-label Fisher is ~0 at a converged optimum – sampling the label from the model is what makes EWC actually anchor.)
- bilevel(model, inner_loss, outer_loss, sample_tasks, inner_steps=1, inner_lr=0.01)[source]
Meta-learning (MAML): meta-learn
model’s params so a few inner gradient steps adapt to a task.sample_tasks()yields(support, query)batches;inner_loss(forward, support)andouter_loss(forward, query)return scalars, whereforward(x)runs the model with the current (adapted) parameters. The returned move’s objective differentiates through the inner adaptation (second-order), sofit(bilevel(...), steps=N)is MAML;fitminimizes the query loss over the meta-parameters.
- class ParetoMove(objectives, params, lr=None)[source]
Bases:
MoveA move that steps along the MGDA common-descent direction – decreases every objective at once.
- Parameters:
objectives (Sequence[Callable[[], Any]])
params (Iterable)
lr (float | None)
- pareto(objectives, over, lr=None)[source]
Multi-objective optimization with NO fixed weights: each step descends all objectives at once (MGDA).
- class StreamingEMMove(estimator, stream, init, iters_per_chunk=1)[source]
Bases:
objectOnline EM over a
Stream: each round, warm-started EM iterations on the current chunk.Composes in
fit(data=stream)next to gradient moves, so a stats model and a neural net adapt to the same stream together (the LLM<->stats continual-coupling case).move.modelis the current fit.- Parameters:
estimator (Any)
stream (Stream)
init (Any)
iters_per_chunk (int)
- property model: Any
- streaming_em(estimator, stream, init, iters_per_chunk=1)[source]
A stats EM move that continually adapts over a chunk stream (use inside
fit(data=stream)).
- gail(discriminator, sample_expert, sample_policy, disc_params, policy_params)[source]
GAIL / adversarial inverse RL =
alternate(minimize(disc_loss), maximize(reinforce(policy))).Recover an expert’s behavior (and a reward) from demonstrations alone.
discriminator(features) -> logits(high = expert; this logit is the recovered reward).sample_expert() -> featuresis a batch of expert transition features;sample_policy() -> (features, action_logprobs)is a policy rollout. The discriminator separates expert from policy transitions while the policy is reinforced to fool it.
- maxent_irl(reward, reward_params, expert_features, policy_features)[source]
Maximum-entropy inverse RL by feature matching (Ziebart et al.).
reward(features) -> scalar(e.g.w·φ).expert_featuresis the expert’s expected feature vector (from demonstrations).policy_features() -> featuresreturns the expected features under the maxent-optimal policy for the current reward – the inner forward / soft-value solve, recomputed each step. For structured dynamics that inner solve is exactly mixle’s forward (soft-value) pass, so the partition function is computed without sampling. The move’s gradient matches expert to policy features.