GNNLux GATConv/GATv2Conv initialize the attention vector `a` without the setup rng, so it's identical for every seed

Aperta Adatta ai principianti
#736 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
76/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
julia

Direzione di ricerca

La issue indica GNNLux/src/layers/conv.jl, agli inizializzatori GATConv e GATv2Conv, intorno alle righe 901 e 1058. Leggi quei costruttori e confronta come gli altri layer di GNNLux passano l’RNG di setup a init_weight; l’esempio minimo della issue mostra come verificare il comportamento con seed diverse e con un inizializzatore che usa solo un RNG. Il lavoro è completato quando entrambi i vettori di attenzione usano l’RNG fornito e l’esempio non segnala più vettori uguali tra seed diverse.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

In GNNLux, GATConv and GATv2Conv create the attention parameter a without passing the rng given to initialparameters:

https://github.com/JuliaGraphs/GraphNeuralNetworks.jl/blob/54025c6257a1e00a8521a6197dd793ce3941a8cc/GNNLux/src/layers/conv.jl#L901

https://github.com/JuliaGraphs/GraphNeuralNetworks.jl/blob/54025c6257a1e00a8521a6197dd793ce3941a8cc/GNNLux/src/layers/conv.jl#L1058

a = l.init_weight(ein > 0 ? 3out : 2out, l.heads)   # GATConv
a = l.init_weight(out, l.heads)                     # GATv2Conv

With the default glorot_uniform, the rng-less WeightInitializers method falls back to its internal fixed Xoshiro(1234), so a comes out the same no matter which rng is passed to Lux.setup. Every GAT layer with the same shape therefore starts with an identical attention vector, and changing the seed (e.g. for multiple runs or an ensemble) doesn't change it. A custom init_weight that only has an (rng, dims...) method would also fail here with a MethodError.

Minimal example
using GNNLux, Lux, Random

for L in (GATConv(3 => 4; heads = 2), GATv2Conv(3 => 4; heads = 2))
    p0 = Lux.setup(Xoshiro(0), L)[1]
    p1 = Lux.setup(Xoshiro(1), L)[1]
    println(nameof(typeof(L)), ": a equal across seeds = ", p0.a == p1.a,
            ", first Dense weight equal across seeds = ", first(values(p0)).weight == first(values(p1)).weight)
end

# init_weight is called without an rng for `a`
calls = Any[]
myinit(rng::AbstractRNG, dims::Integer...) = (push!(calls, (typeof(rng), dims)); zeros(Float32, dims...))
myinit(dims::Integer...) = (push!(calls, ("no rng", dims)); zeros(Float32, dims...))
Lux.setup(Xoshiro(0), GATv2Conv(3 => 4; heads = 2, init_weight = myinit))
println(calls)

Output (Julia 1.13.3, GNNLux 0.3.0, Lux 1.31.6, WeightInitializers 1.3.5, CPU):

GATConv: a equal across seeds = true, first Dense weight equal across seeds = false
GATv2Conv: a equal across seeds = true, first Dense weight equal across seeds = false
Any[(Xoshiro, (8, 3)), (Xoshiro, (8, 3)), ("no rng", (4, 2))]

The Dense sublayers react to the seed, but a doesn't. The two lines above are unchanged on current master (54025c6), so I expect the same behaviour there, though I ran the example against the registered 0.3.0.

Expected

a should be drawn from the rng passed to initialparameters, i.e. l.init_weight(rng, ...), like the other GNNLux layers (GCNConv, GMMConv, NNConv, ...).

Related (smaller)

In GNNLux GATConv, dense_x and dense_e are built as Dense(... , use_bias = false) without passing init_weight (L888-889), so a custom init_weight only affects a. GATv2Conv passes init_weight to its dense_i/dense_j/dense_e. Happy to split this into a separate issue if you prefer.

Lingua principale
Julia
Stelle
312
Fork
76
Merge medio
2g 19h
PR unite (30g)
13

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di JuliaGraphs/GraphNeuralNetworks.jl

Tutte le issue di JuliaGraphs/GraphNeuralNetworks.jl

Issue simili

Altre issue su Julia

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.