Hello,
I’m able to calculate the gradients of the spectral norm in CPU but not in GPU
This works fine :
julia> using CUDA, Zygote, LinearAlgebra
julia> X = randn(Float32, 5, 1);
julia> function snorm(W::AbstractArray)
S = svdvals(W)
return maximum(S)
end
snorm (generic function with 1 method)
julia> Zygote.gradient(x -> snorm(x), X)
(Float32[0.06287575; -0.03134879; … ; -0.20840532; -0.61453784;;],)
If I move X to gpu then it errors out :
julia> using Flux
julia> X = X |> gpu
5×1 CuArray{Float32, 2, CUDA.DeviceMemory}:
0.12716164
-0.06340073
1.5322151
-0.42148516
-1.2428597
julia> Zygote.gradient(x -> snorm(x), X)
ERROR: Scalar indexing is disallowed.
Invocation of getindex resulted in scalar indexing of a GPU array.
This is typically caused by calling an iterating implementation of a method.
Such implementations *do not* execute on the GPU, but very slowly on the CPU,
and therefore should be avoided.
If you want to allow scalar iteration, use `allowscalar` or `@allowscalar`
to enable scalar iteration globally or for the operations in question.
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] errorscalar(op::String)
@ GPUArraysCore ~/.julia/packages/GPUArraysCore/aNaXo/src/GPUArraysCore.jl:151
[3] _assertscalar(op::String, behavior::GPUArraysCore.ScalarIndexing)
@ GPUArraysCore ~/.julia/packages/GPUArraysCore/aNaXo/src/GPUArraysCore.jl:124
[4] assertscalar(op::String)
@ GPUArraysCore ~/.julia/packages/GPUArraysCore/aNaXo/src/GPUArraysCore.jl:112
[5] getindex
@ ~/.julia/packages/GPUArrays/uiVyU/src/host/indexing.jl:50 [inlined]
[6] scalar_getindex
@ ~/.julia/packages/GPUArrays/uiVyU/src/host/indexing.jl:36 [inlined]
[7] _getindex
@ ~/.julia/packages/GPUArrays/uiVyU/src/host/indexing.jl:19 [inlined]
[8] getindex
@ ~/.julia/packages/GPUArrays/uiVyU/src/host/indexing.jl:17 [inlined]
[9] macro expansion
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:351 [inlined]
[10] macro expansion
@ ./simdloop.jl:77 [inlined]
[11] __muldiag!(out::CuArray{Float32, 2, CUDA.DeviceMemory}, D::Diagonal{Float32, ChainRules.OneElement{…}}, B::CuArray{Float32, 2, CUDA.DeviceMemory}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool})
@ LinearAlgebra ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:350
[12] _mul_diag!
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:424 [inlined]
[13] _mul!
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:430 [inlined]
[14] _mul!
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/bidiag.jl:434 [inlined]
[15] mul!
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:285 [inlined]
[16] mul!
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:253 [inlined]
[17] *
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:114 [inlined]
[18] _tri_matmul(A::CuArray{Float32, 2, CUDA.DeviceMemory}, B::Diagonal{Float32, ChainRules.OneElement{Float32, 1, Tuple{Int64}, Tuple{Base.OneTo{Int64}}}}, C::CuArray{Float32, 2, CUDA.DeviceMemory}, δ::Nothing)
@ LinearAlgebra ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:1142
[19] _tri_matmul
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:1136 [inlined]
[20] *
@ ~/.julia/juliaup/julia-1.11.4+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:1132 [inlined]
[21] svdvals_pullback
@ ~/.julia/packages/ChainRules/H7bwg/src/rulesets/LinearAlgebra/factorization.jl:290 [inlined]
[22] ZBack
@ ~/.julia/packages/Zygote/kdCjv/src/compiler/chainrules.jl:222 [inlined]
[23] snorm
@ ./REPL[4]:2 [inlined]
[24] #3
@ ./REPL[9]:1 [inlined]
[25] (::Zygote.var"#88#89"{Zygote.Pullback{Tuple{var"#3#4", CuArray{Float32, 2, CUDA.DeviceMemory}}, Tuple{Zygote.Pullback{Tuple{typeof(snorm), CuArray{…}}, Tuple{Zygote.ZBack{…}, Zygote.ZBack{…}}}}}})(Δ::Float32)
@ Zygote ~/.julia/packages/Zygote/kdCjv/src/compiler/interface.jl:97
[26] gradient(f::Function, args::CuArray{Float32, 2, CUDA.DeviceMemory})
@ Zygote ~/.julia/packages/Zygote/kdCjv/src/compiler/interface.jl:154
[27] top-level scope
@ REPL[9]:1
If I don’t use the maximum of the singular values but the sum, it works on gpu:
julia> function snorm(W::AbstractArray)
S = svdvals(W)
return sum(S)
end
snorm (generic function with 1 method)
julia> X = X |> gpu
5×1 CuArray{Float32, 2, CUDA.DeviceMemory}:
0.12716164
-0.06340073
1.5322151
-0.42148516
-1.2428597
julia> Zygote.gradient(x -> snorm(x), X)
(Float32[0.06287575; -0.03134879; … ; -0.20840532; -0.61453784;;],)
However the sum is not something I want here . Do you know how I can make it work ? Thanks
This question is related to : Implementation of Spectral Normalization for Machine Learning