Repository navigation
GML part M5: layers and architectures share one method per Q/P pair, Bool choice and triangle - #351
michakraus wants to merge 5 commits into
Conversation
…Bool choice and triangle - _shift(Val(C), z, f) serves the Q/P pairs of the SympNet, symplectic attention and linear symplectic attention layers; every Bool keyword picks a Symbol type parameter in one expression, and ResNetLayer encodes its bias as :bias/:no_bias. - VolumePreservingFeedForwardLayer is the one struct of the lower and upper layers, whose initialparameters takes init_bias. - MultiHeadAttention has one initialparameters, keeps its draw order, and builds no head key per forward pass. - LASympNet has one Chain; _gradient_layers serves GSympNet, LST and ST; the DataLoader constructors delegate; GSympNet.activation; one encoder and decoder per AutoEncoder. - LinearSymplecticTransformer keeps its activation; upscaling_activation is spelled right; PositionalEncoding allocates on the backend of its input. - Pins against 4c4a832 at 8 ULPs, structure tests and forward inference tests. Closes known issues B11, C19 and K5. Co-Authored-By: Claude Opus 5.5 <[email protected]>
The three merged SympNet forward methods check size(x.q, 1) == M ÷ 2 again, as the parent does; a dimension-2 activation layer broadcast a half of any length without it. The MHA forward pass finds each head by its name head_i from a generated constant tuple, so a reordered parameter set gives the parent's output and no key is built per pass. Tests for both, the LASympNet Chain signature on one line, the out-of-scope comment path restored, and known issues K20 and K21 recorded. Co-Authored-By: Claude Opus 5.5 <[email protected]>
K20 is a late finding about a field name, and the architectures with several activations name them with a prefix. K22 records the measured behaviour of a p of the wrong size: an error from the product or the unbroadcast +, never a value. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…23, K24 The verifier found that the headline and the header of test/layers/layer_structure.jl claimed every layer encodes its choices as a Symbol, while MultiHeadAttention and ClassificationLayer keep Bool parameters. K23 (decoder block count) and K24 (transformer docstrings) are present on 4c4a832. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…c4a832 Co-Authored-By: Claude Opus 5.5 <[email protected]>
📝 Summary
Priority: ⬇️ Low Change: Refactor Merge Risk: 🔵 Low · up to
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Organization UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
92ffaa16-27f6-49ca-9fd9-8942f33614e7
📒 Files selected for processing: 29
CHANGELOG.mdKNOWN_ISSUES.mdsrc/architectures/autoencoder.jlsrc/architectures/linear_symplectic_transformer.jlsrc/architectures/standard_transformer_integrator.jlsrc/architectures/symplectic_autoencoder.jlsrc/architectures/symplectic_transformer.jlsrc/architectures/sympnet.jlsrc/layers/linear_symplectic_attention.jlsrc/layers/multi_head_attention.jlsrc/layers/positional_encoding.jlsrc/layers/psd_like_layer.jlsrc/layers/resnet.jlsrc/layers/symplectic_attention.jlsrc/layers/sympnets.jlsrc/layers/transformer.jlsrc/layers/volume_preserving_attention.jlsrc/layers/volume_preserving_feedforward.jltest/architectures/architecture_pins.jltest/architectures/architecture_structure.jltest/architectures/forward_inference.jltest/helpers/pinned_outputs.jltest/helpers/pins.jltest/integration/documented_defaults.jltest/layers/layer_pins.jltest/layers/layer_structure.jltest/layers/multi_head_attention_allocation.jltest/layers/positional_encoding.jltest/runtests.jl
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.
| NeuralNetwork( | ||
| UnknownDecoder(nn.architecture.full_dim, nn.architecture.reduced_dim, nn.architecture.n_encoder_blocks), | ||
| decoder_model(nn.architecture), | ||
| _unknown_decoder(arch)(arch.full_dim, arch.reduced_dim, arch.n_encoder_blocks), |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Pass arch.n_decoder_blocks to the decoder wrapper.
This PR rewrites Line 236. The third argument of UnknownDecoder and UnknownSymplecticDecoder fills the field n_decoder_blocks. The line passes arch.n_encoder_blocks to that field. If an AutoEncoder has different encoder and decoder block counts, the decoder architecture stores the wrong count. KNOWN_ISSUES.md K23 records this defect.
decoder_model(arch) and decoder_parameters(nn) already read arch.n_decoder_blocks. The fix therefore changes only the stored field, and no pinned output moves. The PR already edits this line, so the fix can go in now, and K23 can close.
🐛 Proposed fix
--- "a/src/architectures/autoencoder.jl"
+++ "b/src/architectures/autoencoder.jl"
@@ -233,7 +233,7 @@
function decoder(nn::NeuralNetwork{<:AutoEncoder})
arch = nn.architecture
NeuralNetwork(
- _unknown_decoder(arch)(arch.full_dim, arch.reduced_dim, arch.n_encoder_blocks),
+ _unknown_decoder(arch)(arch.full_dim, arch.reduced_dim, arch.n_decoder_blocks),
decoder_model(arch),
decoder_parameters(nn),
networkbackend(nn))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| _unknown_decoder(arch)(arch.full_dim, arch.reduced_dim, arch.n_encoder_blocks), | |
| _unknown_decoder(arch)(arch.full_dim, arch.reduced_dim, arch.n_decoder_blocks), |
Summary
Part M5 of the GeometricMachineLearning 0.9 simplification: the layers and architectures share one method where a pair differed in one choice, two bugs are fixed, the multi-head attention builds its head keys once, and
PositionalEncodingallocates on the backend of its input. The outputs do not change._shift(Val(C), z, f), addsfof one half of a(q, p)input to the other half:src/layers/sympnets.jlhas 3 forward methods on a(q, p)input where it had 6,symplectic_attention.jl2 where it had 4,linear_symplectic_attention.jl1 where it had 2. Each of the three SympNet forward methods keeps the layer's dimension check.GradientLayer.second_dimis anInt, and the aliasesLinearLayerQ/LinearLayerPno longer name an unused parameter.Boolladders. EachBoolkeyword ofVolumePreservingAttention, the two volume-preserving feedforward layers,SymplecticAttentionQ/P,SymplecticAutoencoderandResNetLayerpicks aSymboltype parameter in one expression.ResNetLayerencodes its bias as:bias/:no_bias, as the volume-preserving layers do; itsuse_bias::Boolkeyword stays.VolumePreservingLowerLayerandVolumePreservingUpperLayerare aliases of one structVolumePreservingFeedForwardLayer{M, N, bias, AT, Triangle}, with oneinitialparameters; the bias keyword isinit_biasin every layer.initialparametersfor both weight kinds. The forward pass finds each head by its namehead_i, from a key tuple that a generated function builds once for each number of heads, where it builtSymbol("head_", i)on every pass.LASympNethas oneChainmethod where it had four; one_gradient_layersbuilds the gradient layers ofGSympNet,LinearSymplecticTransformerandSymplecticTransformerand replaces the two_make_block_for_initializationmethods (known issue C19 leavesKNOWN_ISSUES.md); theDataLoaderconstructors ofLASympNetandGSympNetdelegate;GSympNetnames its activation fieldactivation; oneencoderand onedecoderserve everyAutoEncoderthat is not aSymplecticAutoencoder.LinearSymplecticTransformerkeeps its activation (it builtnew{typeof(tanh)}, soactivation = sinraised aMethodError).StandardTransformerIntegrator's fieldupsacling_activationis spelledupscaling_activation.::Type{T}everywhere undersrc/layers/.PositionalEncodingfillssimilar(x, eltype(x), dim, seq_length)by one broadcast, so it runs on aJLArraywith scalar indexing disallowed; the "CPU only" docstring warnings go (known issues B11 and K5 leaveKNOWN_ISSUES.md).Breaking changes are listed in
CHANGELOG.md:ResNetLayer's third type parameter, the one volume-preserving feedforward struct,init_bias!→init_bias,GSympNet.act→activation, and theupscaling_activationspelling.Tests
test/layers/layer_pins.jlandtest/architectures/architecture_pins.jl: 27 layer cases, 13 architecture cases and the encoders and decoders of two autoencoders, each inFloat32andFloat64, against the outputs that4c4a8320gives for the same seeds and inputs. The cases cover dense,SymmetricMatrix, triangular,SkewSymMatrixand Stiefel leaves.test/layers/layer_structure.jlandtest/architectures/architecture_structure.jl: the merged methods, the type parameters, the two bugs, the dimension check, the MHA draw order and head lookup by name, and the::Type{T}grep.test/layers/multi_head_attention_allocation.jl: the forward pass allocates what the same head products allocate with constant keys, within 1024 B over 1000 passes, for one and two heads.test/architectures/forward_inference.jl:@inferredon the forward pass of every exported architecture with a chain, inFloat32andFloat64.test/layers/positional_encoding.jl: the layer on aJLArraywith scalar indexing disallowed.The MultiHeadAttention draw order is unchanged, and no seeded pin moved. The one
initialparametersdraws head by head, and in each head the query, the key and the value projection, as before.Out of the
Bool-ladder item:MultiHeadAttention(Stiefel,add_connection) andClassificationLayer(average) encode other choices and keep theirBoolparameters, and the ANNDenselayer is outside this part.The pinned outputs were recorded on arm64 and are compared at 8 ULPs of the larger magnitude. The Linux and Windows CI jobs are the check of that tolerance on other platforms: in the critic's probe, a one-ULP change of the input moves 34 of 80 pin cases by more than 8 ULPs, so the pins are sensitive and those jobs must be read.
Suite at the critic-passed code: full suite with Metal on Julia 1.13.2, pass (Metal 40/40, one known broken: the JET
@test_brokenof #325); full suite with Metal on Julia 1.12.7 (the floor), pass (Metal 40/40, one broken); doctests pass; the Documenter docs build gives 0 unresolved references on Julia 1.13.2.Critic
Verdict: PASS (round verify 2, branch simplify/part-m5-3 at 179d093, judged 7ada06d..HEAD). Mutants: 12 CAUGHT, 0 SURVIVED, 0 UNKNOWN, 0 INVALID. Blocking defects: none.
@test_broken isempty(reports) # #325at quality/jet.jl:96)Earlier blocking defects (round 1): the SympNet dimension guard deleted; the MHA forward pass reading heads by field position. Both are fixed, and their reproducers pass.
The two commits after the critic's PASS change text only:
KNOWN_ISSUES.md(K20's kind and scope, K22 to K26), the headline of oneCHANGELOG.mdentry, and the header comment oftest/layers/layer_structure.jl.Known issues added
K20 —
LagrangianNeuralNetworkstores its activation in the fieldact. Present on4c4a8320.K21 — a comment in
src/layers/symplectic_attention.jlnames a test file undertest/parameters/, which does not exist. Present on4c4a8320.K22 — the SympNet forward methods check the rows of
qonly, so apof the wrong size fails later, in the product or the unbroadcast+, with another error than the layer's own. Present on4c4a8320. The critic read this from the code and did not run it; it suggested that such an input returns a value. The run for this entry shows that every case raises an error and none returns a value.K23 —
decoder(::NeuralNetwork{<:AutoEncoder})gives the decoder'sUnknownDecoderorUnknownSymplecticDecoderthe encoder'sn_encoder_blocks; the model and the parameters read the right count, so only the stored field is wrong. Present on4c4a8320, kept so that the outputs stay unchanged.K24 — the docstrings of
LinearSymplecticTransformerandSymplecticTransformersay thatn_sympnet = 1gives oneGradientLayerQand oneGradientLayerP; withinit_upper = truethe chain has twoGradientLayerQ. Present on4c4a8320.K25 — the
SymplecticAutoencoderdocstring says thatdecoder_init_q = truemakes the first layer of each decoder block a p-type layer; it is aGradientLayerQ. Present on4c4a8320.K26 — the
UnknownDecoderdocstring names its third argumentn_encoder_blocksand links to itself for an example. Present on4c4a8320.Known issues closed: B11, C19, K5.
Reported, not fixed
decoder(::NeuralNetwork{<:AutoEncoder})gives the decoder'sUnknownDecoderthe encoder'sn_encoder_blocks(K23). It is kept so that the outputs stay unchanged.VolumePreservingFeedForward(the architecture) keeps itsif/elseinit_upperladder.LagrangianNeuralNetwork.act(K20).symplectic_attention.jl(K21).n_sympnet = 1(K24).Advisor decisions
For review, verbatim from the plan of this part:
(The plan corrects that figure to the measured one: one rebuilt key costs 192 B a pass on Julia 1.13.2, 187× the 1024 B tolerance. The tolerance stays as decided.)
(The advisor's
test/architectures/forward_pins.jlistest/architectures/architecture_pins.jlon this branch.)Pre-PR verification
Two passes. Pass 1 ran over the full branch. Pass 2 ran over the text-only commits after the critic's PASS, and it checked every CHANGELOG line that the branch adds.
Fixed
Symbol-parameter change said too much. It now namesResNetLayer's bias parameter, the single volume-preserving feedforward struct, and the two renamed fields and the renamed keyword.test/layers/layer_structure.jlnow names the layers whoseBoolkeywords becomeSymbolparameters.4c4a8320.Unresolved
test/layers/layer_structure.jl) says too much:MultiHeadAttention'sStiefeland the architectures'init_upperkeywords stayBool. Left as is, because the test code does not change after the critic's PASS.Checked and clean
src,test,docs,scriptsorext. The fourLASympNetcombinations match the base. The CHANGELOG counts and the K20, K22–K25 evidence reproduce.test_piraciespasses.Float32andFloat64(82 combinations).initialparameters(::MultiHeadAttention)cannot infer on the base either, because its keys depend on the runtimen_heads.fatou lintis clean. The shared_shiftmethods andPositionalEncodingallocate the same bytes as the base bodies, with equal outputs, in a warm session. The 384 000 B difference for a two-headMultiHeadAttentionover 1000 passes at the base reproduces (Julia 1.13.2).CHANGELOG.md.Not checked
forward_inference.jl, passed on 1.12.7.PositionalEncodingon a device is covered by theJLArraytestset.🤖 Generated with Claude Code