Repository navigation
Make symmetric SymplecticAttention symplectic with VectorSoftmax - #378
Conversation
The symmetric method computed the increment 2 A X σ(XᵀAX) for either activation. That is the gradient of the attention potential only when σ is symmetric, which holds for MatrixSoftmax but not for the column-wise VectorSoftmax; there the layer was not symplectic. Compute A X (σ + σᵀ), the gradient for both activations, in the layer and in its inverse, and correct the symmetric formula in the docs page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion test file Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 6 minutes. View limit details
No actionable comments were generated in the recent review. Summary
Merge Risk:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #378 +/- ##
=======================================
Coverage 94.48% 94.49%
=======================================
Files 63 63
Lines 2738 2741 +3
=======================================
+ Hits 2587 2590 +3
Misses 151 151 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
michakraus
left a comment
There was a problem hiding this comment.
JuliaGNI/GeometricMachineLearning.jl PR #378 — Make symmetric SymplecticAttention symplectic with VectorSoftmax
Verdict: approve
Reviewed: 826fe5b
CI: green on all 13 required and release-matrix checks (Julia 1 and Julia min on ubuntu-latest, macOS-latest, and windows-latest, Downgrade, Doctests, Documentation, Metal on Julia 1 and Julia min, Scripts, codecov/patch at 100%, codecov/project at 94.49%); the 2 advisory continue-on-error prerelease jobs (Julia pre and Julia nightly on ubuntu-latest) fail in julia-buildpkg while precompiling LLVM (LoadError: UndefVarError: libLLVMExtra not defined in LLVM.API).
Findings
| # | severity | file:line | claim | evidence |
|---|---|---|---|---|
| 1 | nit |
docs/src/layers/symplectic_attention.md:24,26,52,54,60 |
Pre-existing documentation defects on the same page (also flagged in coderabbitai[bot] review comment #discussion_r4454495583 and listed in the PR body under "Pre-existing, not changed here") are neither fixed in this change nor recorded in KNOWN_ISSUES.md: lines 26 and 54 place the sum inside the exponential (\exp(\sum C) instead of \sum \exp(C)), line 60 pulls 1 / (1 + \sum_m \exp(C_{mj})) outside \sum_n in the first term instead of keeping 1 / (1 + \sum_m \exp(C_{mn})) inside \sum_n, and lines 24 and 52 write "The staring point". Note on #discussion_r4454495583: the change on line 78 (\nabla_Z\Sigma(Z) = AZ(\mathrm{softmax}_1(C) + \mathrm{softmax}_1(C)^T)) is algebraically consistent with lines 66 and 72, and both standard column-wise \mathrm{softmax} (for \Sigma(Z) = \sum_n \log \sum_m \exp(C_{mn})) and \mathrm{softmax}_1 (for \Sigma(Z) = \sum_n \log(1 + \sum_m \exp(C_{mn}))) have the same gradient form A Z \sigma(C)^T + A^T Z \sigma(C) = A Z (\sigma(C) + \sigma(C)^T) when A^T = A. |
Read docs/src/layers/symplectic_attention.md:24-86, src/activations/softmax.jl:27-38, and KNOWN_ISSUES.md. |
| 2 | nit |
test/layers/inverse_layers.jl:87-92 |
@testset "exact layerwise inversion ($T)" tests (symmetric = true, MatrixSoftmax()), (symmetric = false, MatrixSoftmax()), and (symmetric = true, VectorSoftmax()), leaving out (symmetric = false, VectorSoftmax()). |
Read test/layers/inverse_layers.jl:84-92; verified in a cold Julia 1.13.3 process that SymplecticAttentionQ(6; symmetric = false, activation = VectorSoftmax()) and SymplecticAttentionP(6; symmetric = false, activation = VectorSoftmax()) also invert within 10 * eps(T) for Float32 and Float64 on 1D, 2D, and 3D arrays and (q, p) NamedTuples. |
Verified and fine
- Symplecticity defect on
mainand fix on branch: Re-measuredmaximum(abs, J' * Ω * J - Ω)in a cold Julia 1.13.3 process. With the test sequence intest/layers/symplectic_attention.jl(Random.seed!(1234),d = 2, L = 4), themainformula2 * σXAXgives0.972(Q) and0.102(P), whereas the branch formulaσXAX + _custom_transpose(σXAX)gives2.22e-16(Q) and2.78e-17(P). Across a sweep ofd ∈ (1, 2, 3, 4),L ∈ (2, 4, 8), 5 random draws each (QandP, 120 cases), themainformula gives cell medians in[0.309, 1.769](overall range[2.27e-3, 5.045], median0.932), while the branch formula gives a maximum residual of6.66e-15(median3.47e-16). - Direct potential gradient identity (2D and 3D): Verified in a cold process that
_mul(_mul(ps.A, x), σXAX + _custom_transpose(σXAX))matchesZygote.gradient(X -> sum(log.(sum(exp.(X' * Matrix(ps.A) * X); dims = 1))), x)[1](and the batch sum for 3D inputs) with maximum absolute difference4.44e-16(6×4),8.88e-16(6×5),3.33e-16(6×4×1), and1.78e-15(6×5×3). MatrixSoftmaxinvariance: BecauseC = _mul(_mul(_custom_transpose(x), A), x)is symmetric per batch slice whenAis aSymmetricMatrixandMatrixSoftmaxnormalises over(1, 2)by a scalar per slice,σXAX + _custom_transpose(σXAX)equals2 * σXAXup to floating-point rounding (max|new - old| = 1.19e-7 = 1 * eps(Float32)forQand5.96e-8 = 0.5 * eps(Float32)forPinFloat32;2.78e-17forQand1.11e-16 = 0.5 * eps(Float64)forPinFloat64).- Exact layerwise inversion (
src/layers/inverse_layers.jl:128-134): Verified that_attention_displacementonInverseSymplecticAttention{M, M, LayerType, :symmetric}uses the identical increment_mul(_mul(A, x), σXAX + _custom_transpose(σXAX))and satisfiesl_inv(l(z, ps), ps) ≈ zandl(l_inv(z, ps), ps) ≈ zwithin10 * eps(T)for all 4(symmetric, activation)combinations,Float32andFloat64, 1D/2D/3D arrays, and(q, p)NamedTuples. SymmetricMatrixparameter gradient structure: BindingA = ps.Aonce in each:symmetricmethod (src/layers/symplectic_attention.jl:141, 150andsrc/layers/inverse_layers.jl:131) preservesg.L1.A isa SymmetricMatrixunderZygote.gradientfor bothMatrixSoftmax()andVectorSoftmax(),QandP, forward and inverse layers, on 2D and 3D inputs.- Type stability and allocations:
@inferredpasses on 1D, 2D, 3D arrays andNamedTupleinputs for forward and inverse layers. In a cold process on(M, N) = (6, 4)(Float64),@allocatedis2704bytes (2 * σXAX) vs2720bytes (σXAX + _custom_transpose(σXAX)); on(M, N, B) = (6, 4, 2),@allocatedis5072bytes vs5856bytes (the extrapermutedims(σXAX, (2, 1, 3))allocation of a4×4×2array). - Test suite, formatting, linting, and layout: Ran
layers/symplectic_attention.jl,layers/inverse_layers.jl,layers/symplectic_attention_network_parameters_gradient.jl, andquality/aqua.jl(852/852 passed);JuliaFormatter.format(..., overwrite = false)on all 5 changed.jlfiles (formatted);fatou lint --force-exclude(0 findings);test-layout.jl --check(0 violations);closingIssuesReferencesis empty.
Not checked
- Full
Pkg.test()locally: CI ran the full test suite across Julia 1 and Julia min on Ubuntu, macOS, and Windows (plus Metal on macOS-15 and Doctests/Documentation), all green. - GPU/JLArray parameter gradient pullback for
SymplecticAttention: verified in a cold process withJLArraysandallowscalar(false)that the forward passl(z_jl, ps_jl)succeeds without scalar indexing on 2D and 3DJLArray{Float32}inputs, whereas parameter gradient accumulationZygote.accum(::SymmetricMatrix{Float32, <:JLArray}, ::SymmetricMatrix{Float32, <:JLArray})hits pre-existingBase.Broadcastscalar indexing onSymmetricMatrixinGeometricOptimizers.
Review follow-up (
|
| # | severity | file:line | action | resolution |
|---|---|---|---|---|
| 1 | nit |
docs/src/layers/symplectic_attention.md:24,26,52,54,60,78 |
not fixed | Lines 24, 26, 52, 54, 60, 66, 72, and 83–86 are pre-existing text outside the changed hunk (docs/src/layers/symplectic_attention.md:75-82). Inside the changed hunk, \nabla_Z\Sigma(Z) = AZ(\mathrm{softmax}_1(C) + \mathrm{softmax}_1(C)^T) on line 78 is the exact sum of TermI (AZ(\mathrm{softmax}_1(C))^T, line 72) and TermII (A^TZ\mathrm{softmax}_1(C), line 66) for symmetric A, and both standard column-wise \mathrm{softmax} and \mathrm{softmax}_1 share the gradient form A Z (\sigma(C) + \sigma(C)^T). This also addresses the coderabbitai[bot] comment (#discussion_r4454495583) and walkthrough summary (#issuecomment-6603405300). |
| 2 | nit |
test/layers/inverse_layers.jl:87-94 |
fixed (23a0228f) |
Added SymplecticAttentionQ(6; symmetric = false, activation = VectorSoftmax()) and SymplecticAttentionP(6; symmetric = false, activation = VectorSoftmax()) to @testset "exact layerwise inversion ($T)", completing the (symmetric, activation) grid (test/layers/inverse_layers.jl: 931/931 passed). |
Review follow-up (
|
| # | severity | file:line | action | resolution |
|---|---|---|---|---|
| 1 | nit |
docs/src/layers/symplectic_attention.md:23-86 |
fixed (e0f73284) |
Addressed coderabbitai[bot] (#discussion_r4454495583 and #issuecomment-6603405300) and the review finding: rewrote the Matrix Softmax and Vector Softmax potentials and gradients to use the standard softmax (\sum \exp(C) denominator and \mathrm{softmax}(C)) matching MatrixSoftmax and VectorSoftmax, kept the miller2023attention one softmax note as an !!! info remark, and fixed the typos "staring point", \sum{m, n}, \exp(C), and "than". |
| 2 | nit |
test/layers/inverse_layers.jl:87-94 |
fixed (23a0228f) |
Added SymplecticAttentionQ(6; symmetric = false, activation = VectorSoftmax()) and SymplecticAttentionP(6; symmetric = false, activation = VectorSoftmax()) to @testset "exact layerwise inversion ($T)", completing the (symmetric, activation) grid (test/layers/inverse_layers.jl: 931/931 passed). |
Summary
SymplecticAttentionQandSymplecticAttentionPwithsymmetric = truecomputed the shear increment2 A X σ(XᵀAX)for either activation. That is the gradient of the attention potential only whenσ(XᵀAX)is symmetric:MatrixSoftmax(the default) normalises the whole matrix, soσis symmetric and the layer was correct.VectorSoftmaxnormalises each column. The potentialΣ_j log Σ_i exp(c_ij)then has the gradientA X σᵀ + Aᵀ X σ, which isA X (σ + σᵀ)for symmetricA. With2 A X σthe layer was not a gradient shear and not symplectic:JᵀΩJ − Ωis of order one at the default initialisation.This PR computes
A X (σ + σᵀ)for both activations:src/layers/symplectic_attention.jl: the:symmetricmethod. The singleA = ps.Abinding stays, so the parameter gradient is still aSymmetricMatrix.src/layers/inverse_layers.jl:InverseSymplecticAttentionuses the same formula, so it still inverts the layer.docs/src/layers/symplectic_attention.md: the vector-softmax simplification for symmetricAis corrected.The
symmetric = falsemethod already computedA X σᵀ + Aᵀ X σand is unchanged. WithMatrixSoftmaxthe output is unchanged up to round-off; withVectorSoftmaxandsymmetric = true, outputs change for the same parameters.Tests
test/layers/symplectic_attention.jl: a new testset checksJᵀΩJ ≈ Ωfor the Zygote Jacobian over a sequence, for Q and P layers, both activations and both values ofsymmetric. It fails onmainforVectorSoftmax, symmetric = trueand passes on this branch; the other cases are controls that pass on both.test/layers/inverse_layers.jl: the exact-inversion test now covers theVectorSoftmaxsymmetric layers.Pre-PR verification
Two verifier runs: a full seven-point pass on b869c8e and 525ab39, and a scoped re-check of 8dbb8b0.
Fixed
JᵀΩJ − Ωis of order one (8dbb8b0).@safetestsetlabel now names both testsets of the file (8dbb8b0).Unresolved: none.
Pre-existing, not changed here
docs/src/layers/symplectic_attention.md: the vector-softmax potential is written with the sum inside the exponential (\exp(\sum_m C_{mn})), while the derivative needs\sum_m \exp(C_{mn}).1 +in the denominator), while the code uses the standard softmax.Checked and clean
MatrixSoftmaxoutputs are unchanged to ≤ 4.4e-16, so the pinned outputs still hold.SymmetricMatrix.treat_as_own = [Batch]; all forward and inverse calls infer to concrete types on Julia 1.13;fatou lintis clean;test-layout.jl --checkpasses.Not checked
makedocs(the docs change adds no@refand no docstring) and inference on Julia 1.12.Release: patch. A bug fix with no API change.
🤖 Generated with Claude Code