|
1 | 1 | using CUDA |
2 | 2 | using Zygote: Grads |
| 3 | +using LinearAlgebra |
3 | 4 | using Random: randn! |
4 | 5 | CUDA.allowscalar(false) |
5 | 6 |
|
6 | 7 | # Test GPU movement inside the call to `gradient` |
7 | 8 | @testset "GPU movement" begin |
8 | 9 | r = rand(Float32, 3,3) |
9 | | - @test gradient(x -> sum(cu(x)), r)[1] isa Array{Float32, 2} |
| 10 | + @test gradient(x -> sum(cu(x)), r)[1] isa Matrix{Float32} |
| 11 | + @test gradient(x -> sum(x->log(x), cu(x)), r)[1] isa Matrix |
| 12 | + @test gradient((x,cy) -> sum(cu(x) * cy) + sum(cy'), r, cu(r))[2] isa CUDA.CuArray |
| 13 | + @test_skip gradient((x,cy) -> sum(cu(x[:,1])' * cy), r, cu(r))[2] isa CUDA.CuArray # generic_matmatmul! |
| 14 | + |
| 15 | + # Other direction: |
| 16 | + @test_skip gradient(x -> sum(Array(x)), cu(r))[1] isa CUDA.CuArray |
| 17 | + @test_skip gradient((x,cy) -> sum(x * Array(cy)) + sum(cy'), r, cu(r))[2] isa CUDA.CuArray |
10 | 18 | end |
11 | 19 |
|
12 | 20 | @testset "broadcasting" begin |
|
31 | 39 | g3 = gradient(x -> sum(x .^ 3) / count(x .> 3), a)[1] # was Can't differentiate gc_preserve_end expression |
32 | 40 | @test_skip cu(g3) ≈ gradient(x -> sum(x .^ 3) / sum(x .> 3), a_gpu)[1] # was KernelException -- not fixed by PR #1018 |
33 | 41 | @test cu(g3) ≈ gradient(x -> sum(x .^ 3) / count(x .> 3), a_gpu)[1] |
| 42 | + |
| 43 | + # Projection: eltype preservation: |
| 44 | + @test gradient(x -> 2.3 * sum(x.^4), a_gpu)[1] isa CuArray{Float32} |
| 45 | + @test_skip gradient(x -> sum(x .* 5.6), a_gpu)[1] isa CUDA.CuArray{Float32} # dot(x::CuArray{Float64}, y::CuArray{Float32}) fallback |
| 46 | + # structure restoration: |
| 47 | + @test gradient(x -> sum(sqrt.(x)), a_gpu')[1] isa Adjoint # previously a matrix |
| 48 | + @test gradient(x -> sum(exp.(x)), Diagonal(a_gpu))[1] isa Diagonal |
| 49 | + # non-differentiables |
| 50 | + @test gradient((x,y) -> sum(x.^2 .+ y'), a_gpu, a_gpu .> 0)[2] === nothing |
34 | 51 | end |
35 | 52 |
|
36 | 53 | @testset "sum(f, x)" begin |
37 | | - a = Float32.([-1.5, -9.0, 2.4, -1.3, 0.01]) |
| 54 | + a = Float32[-1.5, -9.0, 2.4, -1.3, 0.01] |
38 | 55 | a_gpu = a |> cu |
39 | 56 |
|
40 | 57 | f(x) = sum(abs, x) |
41 | 58 | g = gradient(f, a)[1] |
42 | 59 | g_gpu = gradient(f, a_gpu)[1] |
43 | 60 | @test g_gpu isa CuArray |
44 | 61 | @test g_gpu |> collect ≈ g |
| 62 | + |
| 63 | + f2(x) = sum(abs2, x) # sum(abs2, x) has its own rrule |
| 64 | + g2 = gradient(f2, a)[1] |
| 65 | + g2_gpu = gradient(f2, a_gpu)[1] |
| 66 | + @test g2_gpu isa CuArray |
| 67 | + @test g2_gpu |> collect ≈ g2 |
| 68 | + |
| 69 | + f3(x) = sum(y->y^3, x') # anonymous function |
| 70 | + g3 = gradient(f3, a')[1] |
| 71 | + g3_gpu = gradient(f3, a_gpu')[1] |
| 72 | + @test g3_gpu isa Adjoint{Float32, <:CuArray{Float32, 1}} # preserves structure |
| 73 | + @test g3_gpu |> collect ≈ g3 |
45 | 74 | end |
46 | 75 |
|
47 | 76 | @testset "jacobian" begin |
|
103 | 132 | r = cu(rand(Float32, 3)) |
104 | 133 | grads = (cu(ones(Float32, 3)), 1.f0) |
105 | 134 | @test gradient((x,y) -> sum(vcat(x,y)), r, 5) == grads |
| 135 | + |
| 136 | + @test gradient((x,y) -> sum(vcat(x,y)), r, Float64(5))[1] isa CUDA.CuArray{Float32} |
| 137 | + @test gradient((x,y) -> sum(vcat(x,y)), r, Float64(5))[2] isa Float64 # projection |
| 138 | + |
| 139 | + @test_skip gradient((x,y) -> sum(vcat(x,y)), 5f0, r)[2] isa CUDA.CuArray{Float32} # wrong order |
| 140 | + @test_skip gradient((x,y) -> sum(vcat(x,y)), 1f0, r, 2f0, r)[2] isa CUDA.CuArray{Float32} |
106 | 141 | end |
107 | 142 |
|
0 commit comments