Add GNNGraphsMooncakeExt.jl - #704
Conversation
Signed-off-by: Parvm1102 <parvmittal31757@gmail.com>
|
@CarloLucibello , please review this pr |
| # Values of `A` at the extracted edge positions, via AD-friendly linear indexing | ||
| # (works on GPU, unlike CartesianIndex indexing). The integer-adjacency method is | ||
| # non-differentiable (Mooncake rule in GNNGraphsMooncakeExt); float values stay | ||
| # on the AD path. | ||
| _edge_values(A::AbstractMatrix, s, t) = vec(A)[s .+ (t .- 1) .* size(A, 1)] |
There was a problem hiding this comment.
why the integer case was made with zero derivatives?
Does also zygote return zero derivatives for this case?
There was a problem hiding this comment.
No, Zygote returns non zero gradients here. Array{<:Integer} is NoTangent anyway, so the rule loses nothing. It is needed because Mooncake's CUDA getindex rule covers just float arrays, so the integer path fails on GPU.
There was a problem hiding this comment.
Array{<:Integer} is NoTangent anyway,
what do you mean by this? Also, the zygote gradient for integer input is not necessarily an integer.
I don't like zygote and mooncake derivatives giving different results, but if there are no better ways to do it then let's just do it and move on.
Signed-off-by: Parvm1102 <parvmittal31757@gmail.com>
Part of #702 (Mooncake on CUDA tracker).
Mooncake does not use the ChainRules
@non_differentiableannotations that keep Zygote working, so it traces into graph-structure functions and fails on CUDA (CPU to GPU index copies,findallonCuArray, bounds checks of integer indexing). This PR gives Mooncake the equivalent rules.Changes
GNNGraphs/ext/GNNGraphsMooncakeExt.jlwith threeMooncake.@zero_derivativerules, all on integer structure extraction:add_self_loops(::GNNGraph), mirroring the existing@non_differentiablein transform.jl_findnz_idx(::Any), mirroring the existing@non_differentiablein convert.jl_edge_values(::AbstractMatrix{<:Integer}, ...), integer edge values have no derivativeto_cooand_to_coo_graph. A new helper_edge_values(A, s, t) = vec(A)[s .+ (t .- 1) .* size(A, 1)]replacesv = A[nz]. Mooncake has a CUDA rule for linear indexing but not for CartesianIndex indexing. With this, both conversions are ordinary traceable code and float edge weights stay differentiable under Mooncake, same as Zygote and Enzyme.GNNGraphs/test/ext/Mooncake.jl: Mooncake vs Zygote vs finite differences throughadd_self_loops,edge_indexon dense and sparse graphs,_to_coo_graph, and a float-weighted dense adjacency. Mooncake parts only run on Julia >= 1.12, as in the other suites.Mooncakeweakdep with compat"0.5.24", version bump to1.6.0-DEV.This is simpler than the sketch in #702. The original 4 rules marked all of
to_coozero-derivative, which silently dropped edge weight gradients for float dense adjacencies. With the rewrite those rules are not needed and that problem is gone. I checked each remaining rule is really required by probing the bare functions on GPU with the extension disabled.Tests
CPU (Julia 1.12.5, Mooncake 0.5.45, Enzyme 0.13.198): new testitem 12/12, full GNNGraphs suite 1346 pass and 0 fail (includes the #703 Enzyme test on the rewritten helper), GraphNeuralNetworks GCNConv/GraphConv/SGConv/TAGConv/EdgeConv items 316/316, GNNlib propagate 40/40.
GPU (RTX 3050, CUDA.jl 6.2.1), all of these errored before and now pass, gradients compared against Zygote:
e_mul_xj(matrix e) on densew_mul_xjon densebroken = truetest in msgpass.jl)Still failing on GPU, all upstream Mooncake gaps tracked in #702: GAT, GATv2, Transformer, GMMConv, unweighted dense SGConv (missing
sum(x; dims)rule), TAGConv and Transformer (CuMatrix + CuMatrixhas no rule), TGCN family (repeathas no rule).