Optim #
TorchLean optimizer wrappers.
This connects the pure tensor optimizers in NN/Runtime/Optim/Optimizers.lean to the runtime
training structures (Torch.ParamList + gradient TorchLean.TensorPack).
Design notes:
- Optimizer state is stored in a shape-indexed list aligned with the parameter shapes.
- Trainable storage aliases share one history and one update from their summed gradients.
- Updates run on plain tensors after the backward pass, so they are not recorded on the autograd tape.
- Parameters marked
requiresGrad := falseare left unchanged (state is preserved).
PyTorch references #
torch.optimoverview: https://pytorch.org/docs/stable/optim.htmltorch.optim.SGD: https://pytorch.org/docs/stable/generated/torch.optim.SGD.htmltorch.optim.Adam: https://pytorch.org/docs/stable/generated/torch.optim.Adam.htmltorch.optim.AdamW: https://pytorch.org/docs/stable/generated/torch.optim.AdamW.html
For the core math and algorithm-level citations (Adam, AdamW, RMSProp, etc.), see
NN/Runtime/Optim/Optimizers.lean.
Generic optimizer interface #
A shape-indexed list of optimizer state values.
This mirrors the parameter-shape list used by Torch.ParamList. Trainable storage aliases carry
copies of one immutable optimizer state. Initialize through the optimizer and retain the complete
returned list between steps; alias entries must not be edited independently.
- nil {State : (α : Type) → [TorchLean.Storage α] → Spec.Shape → Type} {α : Type} [TorchLean.Storage α] : StateList State α []
- cons {State : (α : Type) → [TorchLean.Storage α] → Spec.Shape → Type} {α : Type} [TorchLean.Storage α] {s : Spec.Shape} {ss : List Spec.Shape} : State α s → StateList State α ss → StateList State α (s :: ss)
Instances For
Runtime-facing optimizer interface.
This is the analogue of a PyTorch torch.optim.Optimizer, but made explicit about:
- which parameter shapes it manages (
paramShapes), and - how it stores internal state (
State) aligned with those shapes.
- State : Type
The optimizer's own state type: momentum buffers, second moments, step counts. Leaving it abstract here is what lets SGD and Adam share one interface despite storing different things.
- init : Torch.ParamList α paramShapes → IO self.State
Allocate initial state for the given parameters.
- step : self.State → Torch.ParamList α paramShapes → TorchLean.TensorPack α paramShapes → IO self.State
One update: state, parameters and gradients in, new state out. Parameters are updated in place through
ParamList, which is why only the state is returned. The same state with every parameter's learning rate set to the given value; schedules use it between steps.
- native? : self.State → Option (Torch.NativeOptimizer α)
The update this state names among the trainer's native optimizers, if any. A trainer whose backend keeps parameters, gradients and optimizer moments on the device (eager CUDA) runs it in place of the generic
backward+steppath, and the state is then kept as is, since the moments live on the device.nonealways takes the generic path.
Instances For
Run optimizer's native update on a nonempty batch when both the optimizer and the trainer's
backend have one; one sample is a batch of one. The outer option reports whether the native path
ran, and the inner loss is present exactly when readLoss was requested.
Instances For
An optimizer state with its shape, used to copy a canonical state into later alias slots.
- shape : Spec.Shape
- state : State α self.shape
Instances For
Retrieve an earlier canonical state without comparing state or tensor contents.
Instances For
Read a shape-independent field from the first optimizer state, or use fallback when there
are no parameters.
Instances For
Apply f to every per-parameter optimizer state.
Instances For
Initialize once per trainable storage and copy that immutable state into its alias slots.
Frozen slots retain independent placeholder states so the public shape-indexed list is unchanged. All alias decisions use the same canonical-slot map as SGD and checkpoints.
Instances For
Instances For
Run one optimizer update per trainable storage using its summed occurrence gradients.
updateOne is called only at canonical slots. Its one immutable returned state is copied into
all aliases with a shape check; frozen states are preserved.
Alias states must remain coherent, as produced by initialization or previous steps for the same
storage layout. Generic State has no equality operation: divergent external histories are outside
this contract and are not detected or merged. Checkpoint restoration must preserve this invariant.
Instances For
Instances For
Concrete optimizers #
Stochastic gradient descent.
PyTorch analogy: torch.optim.SGD(lr=lr) without momentum.
Instances For
SGD with classical momentum.
PyTorch analogy: torch.optim.SGD(lr=lr, momentum=momentum).
Instances For
AdaGrad (per-parameter learning rate scaling by accumulated squared gradients).
PyTorch analogy: torch.optim.Adagrad(lr=lr, eps=epsilon).
Instances For
RMSProp (exponentially-decayed second moment / running average of squared gradients).
PyTorch analogy: torch.optim.RMSprop(lr=lr, alpha=decay, eps=epsilon) (we use the common naming
decay for alpha).
Instances For
Adam (first/second moment estimates).
PyTorch analogy: torch.optim.Adam(lr=lr, betas=(beta1,beta2), eps=epsilon).
Instances For
AdamW (Adam with decoupled weight decay).
PyTorch analogy: torch.optim.AdamW(lr=lr, weight_decay=weightDecay, betas=(beta1,beta2), eps=epsilon).
Instances For
AdaDelta (adaptive learning rate method similar to RMSProp but with a running RMS of updates).
PyTorch analogy: torch.optim.Adadelta(lr=lr, rho=rho, eps=epsilon).
Instances For
Optimizer extension points #
Projected SGD.
This is the runtime-safe part of a GaLore-style optimizer: every parameter gets a same-shape
projector/lift pair, and the update applies p ← p - lr * lift(project(g)).
Full GaLore also needs a rank-changing projector and a refresh schedule. Those pieces require matrix-specific state and SVD/randomized-SVD infrastructure, so they are not hidden inside this generic constructor.
Instances For
Muon-style momentum with a caller-supplied same-shape orthogonalization backend.
Using the identity backend gives ordinary momentum-SGD behavior. A production Muon backend should provide a matrix-specific Newton-Schulz orthogonalizer and optional CUDA kernels.