mixle.models.sigma_weighted_projection module¶
Sigma-weighted structured projections (roadmap G2): thin solvers over borrowed primitives.
Given a weight matrix W (out_dim x in_dim) and the covariance Sigma (in_dim x in_dim,
PSD) of the activations it will actually be multiplied against – e.g. the propagated-law covariance
coming out of mixle.models.moment_propagation (roadmap G1) – the objective that matters for
preserving downstream behavior is NOT plain Frobenius compression (||W - What||_F^2, which treats
every input direction as equally important) but the SIGMA-WEIGHTED version
min_What tr((W - What) @ Sigma @ (W - What)^T)
which penalizes reconstruction error in input directions the real data varies along more, and tolerates more error in directions the data barely explores (the “optimal brain damage” / Fisher-weighted pruning idea, generalized from a diagonal Hessian approximation to a full covariance weighting).
Per the roadmap’s build-vs-borrow note, this module BORROWS the heavy primitives rather than reimplementing them:
the low-rank case has a real closed-form solution via a whiten/SVD/un-whiten reduction to plain Eckart-Young truncated SVD (
sigma_weighted_low_rank()) – no iterative solver needed;the block-sparse / 2:4 case has no closed form, so
sigma_weighted_block_sparse()uses a textbook projected-gradient (“alternating projection”) scheme: a gradient step on the (convex, quadratic-in-What) weighted objective, alternated with a hard projection onto the structural constraint set (a fixed support mask, or a dynamically re-selected 2:4 pattern);the permutation case is solved with Sinkhorn’s algorithm – the standard entropic-OT relaxation of a linear assignment problem.
torchsort/POT/geomlosswere checked (see the PR description) and are not installed in this environment; Sinkhorn itself is a well-known ~10-line fixed-point iteration (alternating row/column normalization of a Gibbs kernel in log-domain for numerical stability), so it is implemented directly here rather than pulling in a heavy optional dependency for a few lines of numpy. This is also the differentiable “profile . arrangement” building block roadmap item G4 (later, not this item) reuses for permutation x profile quantization.
- sigma_weighted_error(w, w_hat, sigma)[source]
tr((W - What) @ Sigma @ (What - W)^T)– the Sigma-weighted reconstruction objective itself.Used both as the convergence check inside the iterative solvers below and as the metric the tests compare solvers against each other with.
Sigmais assumed PSD (a covariance matrix); this function does not itself validate that – callers pass a real covariance (e.g. frommixle.models.moment_propagation.propagate_moments()) or a syntheticA @ A.Tconstruction.
- sigma_weighted_low_rank(w, sigma, rank)[source]
Exact closed-form solver for
min_{rank(What)<=rank} tr((W-What) Sigma (W-What)^T).Derivation (generalized SVD via whitening): for symmetric PSD
Sigmawith symmetric square rootSigma^(1/2)(Sigma = Sigma^(1/2) Sigma^(1/2), itself symmetric so(Sigma^(1/2))^T = Sigma^(1/2)),- tr((W-What) Sigma (W-What)^T) = tr((W-What) Sigma^(1/2) Sigma^(1/2) (W-What)^T)
= || (W-What) @ Sigma^(1/2) ||_F^2 .
Substituting
B = W @ Sigma^(1/2)andBhat = What @ Sigma^(1/2), the constraintrank(What) <= rankbecomes (for full-rankSigma^(1/2)) exactlyrank(Bhat) <= rank, and the objective becomes the PLAIN (unweighted) Frobenius low-rank problemmin ||B - Bhat||_F^2, whose exact global optimum is the truncated SVD ofB(Eckart-Young). Un-whiteningWhat = Bhat @ Sigma^(1/2)^+(pseudo-inverse, needed ifSigmais rank-deficient) recovers the optimalWhatin the ORIGINAL objective. WhenSigmahas a null space, those input directions contribute nothing to the objective regardless ofWhat’s value there, so the pseudo-inverse un-whitening (which zeroesWhaton that null space) is one particular optimum among many – still provably attaining the true minimum objective value, which is all the stated objective can see.This is the SAME closed form used for Fisher/Hessian-weighted low-rank compression (a diagonal special case of this is “optimal brain damage”-style weighted SVD); here it is implemented for a full (non-diagonal)
Sigma.
- sigma_weighted_block_sparse(w, sigma, block_pattern_or_2_4, max_iter=200, tol=1e-10)[source]
Alternating-projection solver for
min_{What in S} tr((W-What) Sigma (W-What)^T)whereSis a structural constraint set with no closed form: a fixed block-sparse/arbitrary support mask, or the 2:4 semi-structured pattern.block_pattern_or_2_4:the literal string
"2:4"– 2:4 semi-structured sparsity (pattern re-selected every step, see_project_2_4());a boolean array shaped like
W– an explicit (e.g. block-sparse) fixed support pattern.
Algorithm: projected gradient descent on the (convex, quadratic-in-
What) objective –grad_What = -2 (W - What) Sigma– with step size1 / (2 * lambda_max(Sigma))(the standard Lipschitz-safe step for a quadratic with Hessian2*Sigmaacting on the right), alternated with a HARD projection onto the structural constraint set after every gradient step. Convergence contract: for a FIXED mask the constraint set is a linear subspace, so this is plain convex projected gradient descent and converges to the GLOBAL optimum of that subspace-constrained problem (matches the closed-form per-row constrained-least-squares solution – see the optimality test). For 2:4 the constraint set is a finite, non-convex union of subspaces (the pattern itself is re-chosen every step), so only convergence to a LOCAL optimum of the alternating scheme is guaranteed – NOT global optimality over all possible 2:4 masks (that combinatorial problem is not attempted here).
- sigma_weighted_permutation(w, sigma, target_profile, temperature=0.1, max_iter=100)[source]
Sinkhorn-based soft-permutation solver for
What = P @ target_profile– the “profile o arrangement” pattern (roadmap H4/R1, feeding G4’s permutation x profile quantization): find the ROW-permutationPof a fixed canonicaltarget_profilethat best matchesWunder the Sigma-weighted objectivemin_P tr((W - P @ target_profile) Sigma (W - P @ target_profile)^T).This is a linear assignment problem in disguise: it decomposes over ROW-PAIRS (row
iofWmatched to rowjoftarget_profile) with pairwise costcost[i,j] = (W_i - profile_j) @ Sigma @ (W_i - profile_j)^T, so the discrete problemmin_{P permutation} sum_i cost[i, perm(i)]is EXACTLY a linear assignment problem. We solve it with the differentiable Sinkhorn relaxation the roadmap asks for (a Gibbs kernelK = exp(-cost/temperature), alternately row/column normalized in log-domain – this is thetorchsort/POT-style soft-permutation building block G4 later reuses for a jointly-differentiable profile+arrangement objective), THEN round the converged soft doubly-stochastic coupling to a hard permutation via linear-sum-assignment (Hungarian) on the SAME cost matrix – a standard, exact final-rounding step (the Sinkhorn relaxation supplies the differentiable pattern; committing to a hard answer is a separate, exact combinatorial step, not claimed to itself be “the Sinkhorn solution”). Convergence contract: the returned answer is the exact optimum of the linear assignment problem (Hungarian rounding is exact for assignment problems); the SINKHORN PLAN itself only converges to the true permutation in the low-temperature limit – what “converged Sinkhorn solution” means here is that repeated Sinkhorn normalization has converged to a fixed doubly-stochastic coupling for the giventemperature, not that temperature itself has been annealed to zero.
- sigma_weighted_butterfly(w, sigma, n_stages=None, n_sweeps=4)[source]
Sigma-weighted BUTTERFLY structured projection: constrain
Whatto be (the top-leftd_out x d_inblock of) anN x N“butterfly matrix” – a product ofLsparse factors, each with exactly 2 nonzeros per row connecting indexjtoj XOR stride(stridedoubling stage to stage: 1, 2, 4, …) – the SAME block-diagonal-then-permute connectivity pattern FFT’s radix-2 decimation uses. This givesO(N log N)free parameters (2 * Nper stage,L = log2(N)stages) instead ofO(N^2)for a dense matrix, whereNis the next power of two>= max(d_out, d_in).Solved by ALTERNATING LEAST SQUARES over the
Lstage factors, per the roadmap card’s Steps: reusing the SAME whiten-by-Sigma^(1/2)reductionsigma_weighted_low_rank()uses (via_symmetric_sqrt_and_pinv_sqrt()) to turn each per-stage subproblem into a plain (unweighted) linear least-squares problem in that stage’s2*Nfree parameters (closed-form, vianumpy.linalg.lstsq()) given every OTHER stage held fixed – a genuine block-coordinate solve, monotonically non-increasing in the Sigma-weighted objective per stage update (seesigma_weighted_error(), the same convergence metric the other three solvers already use).Two SIMPLIFICATIONS versus a textbook FFT butterfly, both bounded and stated here rather than hidden:
Each stage’s two taps per row are FREE real parameters fit to the data, not fixed unitary FFT twiddle factors – this follows the “butterfly matrices for structured compression” line of work (generalizing FFT’s O(n log n) connectivity to a learnable factorization), not a literal (inverse) Fourier transform.
Rectangular
Wis handled by zero-paddingW/Sigmaup to the squareN x Nproblem and reading off the top-leftd_out x d_inblock at the end.Sigma’s padded rows/columns are zero (those input directions cost nothing, same convention as_symmetric_sqrt_and_pinv_sqrt()’s null-space handling), but padded OUTPUT rows (beyondd_out, whend_outis not already a power of two) are fit toward zero using the SAME shared stage parameters as the real rows – a mild, honest dilution of fitting capacity for non-power-of-twod_out, not a hidden bug.n_sweepsbounds the number of ALS passes over allLstages rather than iterating to convergence – the “fixed number of butterfly stages/sweeps” bounded-fix simplification the roadmap card allows for. It does not make the family a no-op or fold it into another family: each stage solve is a real, distinct least-squares fit and the returnedWhathas the genuine sparse butterfly parameter count, not a dense low-rank or block-sparse structure.
- class ProjectionReport(structure, sigma_weighted_error, stats=<factory>)[source]
Bases:
objectUniform report shape
project()returns alongsideWhat, regardless ofstructure.sigma_weighted_erroris always the SAME objective (sigma_weighted_error()) every solver in this module already minimizes/reports, computed once here so callers get one consistent number to compare across families.statscarries whatever structure-specific numbers that solver’s own return value already lets a caller compute (rank, sparsity fraction, stage/parameter counts, …) – nothing new is invented here, this just wraps numbers each solver already makes derivable.
- project(w, sigma, structure, **kw)[source]
Unified front door for roadmap G2’s four structure families:
structure in {"low_rank", "block_sparse", "butterfly", "perm_profile"}.Dispatches to this module’s existing standalone solvers (
sigma_weighted_low_rank(),sigma_weighted_block_sparse(),sigma_weighted_butterfly(),sigma_weighted_permutation()) – this function does not reimplement any solver, it only picks one by name and wraps its result (plus the sharedsigma_weighted_error()metric and a few structure-specific stats already derivable from that result) into a singleProjectionReportshape, so callers that want to pick a structure by string (e.g. a search/schedule over structures) do not need a per-family if/elif of their own.**kwper structure (forwarded to the underlying solver; see each solver’s docstring for details):"low_rank":rank(int, required)."block_sparse":pattern("2:4"or a boolean mask shaped likeW; required), optionalmax_iter,tol."butterfly": optionaln_stages,n_sweeps."perm_profile":target_profile(required), optionaltemperature,max_iter.