Losses and optimizers
Applicable version · ArcQML 0.1.0
On this page
Losses: input constraints and forward formulas
| Function | Key constraints |
|---|---|
mse_loss |
Nonempty prediction and target, same dtype (F32/F64), broadcast-compatible shapes. |
l1_loss |
Nonempty prediction and target, same dtype (F32/F64), broadcast-compatible shapes. |
binary_nll_loss |
One-dimensional prediction and labels of equal length; labels must be 0 or 1. |
BCE with logits |
logits and targets have identical shape and dtype; target values lie between 0 and 1. |
cross_entropy_loss |
A two-dimensional logits Tensor; the labels count equals batch size, and every label is a valid class index. |
These losses use the current CPU Dense numerical operators. Let N be the element count of the broadcasted error Tensor, with the i th broadcasted elements of prediction and target denoting predicted and target values. For a [B, C] error tensor, for example, N = B × C. Mean squared error is:
The L1 loss is:
In binary_nll_loss, prediction is a Pauli-Z expectation, not an ordinary probability or logit. The framework first clamps the expectation:
The clamped expectation is then converted to probabilities for two classes:
The corresponding binary negative log-likelihood is:
Binary cross entropy taking logits directly uses a numerically stable form, where N is the total number of logits:
For multiclass logits with B samples and C classes, cross entropy is:
Optimizers
SGD: updates with coupled L2 regularization
Sgd::step updates each Parameter that is trainable, has requires_grad enabled, and has a grad. For F32 or F64, each element is updated as:
Parameters without gradients count toward skipped_no_grad; frozen parameters or those with requires_grad=false count toward skipped_frozen.
Adam: bias correction and weight decay placement
At the first step, Adam creates state slots by position in the parameter slice. Later calls must preserve parameter count and order. It stores the step count, first moment, and second moment. Each update first adds the coupled L2 term to the current gradient:
Then it updates the first and second moments:
After bias correction, it updates the parameters:
Here weight_decay therefore enters the moment estimates and is not the decoupled weight decay used by AdamW.
Constructors require finite, nonnegative learning_rate and weight_decay, beta1 and beta2 in [0, 1), and finite positive epsilon. Reuse the same Adam instance during training; recreating it loses momentum and step counts.
Recommended training loop
let mut optimizer = Adam::new(0.01, 0.9, 0.999, 1e-8, 0.0)?;
for _ in 0..steps {
let prediction = simulator.run(&circuit, &observable)?;
let loss = mse_loss(&prediction, &target)?;
loss.backward()?;
optimizer.step(circuit.parameters())?;
optimizer.zero_grad(circuit.parameters());
}
Call zero_grad after each optimizer.step to clear current gradients and prevent accidental accumulation in the next iteration. Do not replace or modify a forward-pass Parameter Tensor in place before backward, or version checks may report modified forward data. Let optimizer.step perform updates.
Custom losses
Rust users can connect quantum outputs to differentiable operators such as sub, square, mul, and mean to build scalar losses. Ordinary operator composition requires no handwritten backward pass. To specify derivatives for out-of-graph computation or a complete expression, use CustomOp and apply_custom_op. Autograd follows local backward rules in the actual graph; it does not symbolically simplify arbitrary equivalent mathematical expressions.
See the Custom loss tutorial (docs/tutorial/custom_loss.md in the release package) and Custom loss example (rust/custom_loss.rs in the release package) for full input contracts, weighted MSE, batch circuit training, analytical/numerical gradient checks, and custom backward examples. Python does not currently export the corresponding general operator-composition or CustomOp interfaces.