1+ # Re-Implementation of MeanHVIApproximationVec where random numbers are
2+ # generated for each block in the correlation matrix separately.
3+ #
4+ # Unfortunately, having many smaller matrix multiplications, the derivative
5+ # computation is slower than with
6+ # one big matrix multiplication of the big sparse blocked covariance matrix.
7+ # As benchmarked 251121 for 20 sites in test_sample_zeta.
8+ # Both on cpu and gpu
9+ #
10+ # For a large number of sites in a forward run across all sites
11+ # this implementaion is faster on gpu, but slower than the Vec
12+ # implementation on CPU (that uses triangular and blocked matrices)
13+ #
14+ # Hence, currently, rather use the MeanHVIApproximationVec CPU implementation.
15+ # for gradient on few sites (1.6ms cpu vs 5.4ms gpu)
16+ # and forward runs for many sites (760mus cpu vs 439ms gpu unit!)
17+
118function sample_ζresid_norm (app:: MeanHVIApproximation ,
219 zP:: AbstractMatrix , zMs:: AbstractMatrix , ζP:: TP , ζMs:: TM ,
320 ϕq:: AbstractVector ;
421 int_ϕq= get_concrete (ComponentArrayInterpreter (ϕq)),
522 cor_ends
623) where {T,TP<: AbstractVector{T} ,TM<: AbstractMatrix{T} }
7- ϕuncc = int_ϕq (CA. getdata (ϕq))
24+ ϕunc = CA. getdata (ϕq)
25+ ϕuncc = int_ϕq (ϕunc)
826 n_θP, n_θMs, (n_θM, n_batch), n_MC = length (ζP), length (ζMs), size (ζMs), size (zP,1 )
927 # do not create a UpperTriangular Matrix of an AbstractGÜUArray in transformU_cholesky1
1028 ρsP = isempty (ϕuncc[Val (:ρsP )]) ? similar (ϕuncc[Val (:ρsP )]) : ϕuncc[Val (:ρsP )] # required by zygote
@@ -21,26 +39,46 @@ function sample_ζresid_norm(app::MeanHVIApproximation,
2139 σP = exp .(logσ2_ζP ./ 2 )
2240 # create random numbers from U diag(σ) z = U (σ .* z)
2341 # for each block separately
24- # σzMs = σMs .* reshape(zMs, (n_θM, n_batch, n_MC))
42+ # Ui, ri = first(zip(UPs, rangesP))
43+ ζP1 = ChainRulesCore. @ignore_derivatives similar (CA. getdata (ϕunc), size (zP' ))
44+ # @benchmark typeof(zP .* ϕq[1:1]) # more allocations and more time
45+ local ζP_resids = if isempty (ζP)
46+ ζP1 # provide init of correct empty matrix type
47+ else
48+ mapreduce (vcat, UPs, rangesP) do Ui, ri
49+ Diagonal (σP[ri]) * Ui' * zP[:,ri]'
50+ end
51+ end :: typeof (ζP1)
52+ #
2553 # Ui, ri = first(zip(UMs, rangesM))
2654 zMs_subjects = reshape (zMs, (n_MC, n_θM, n_batch))
2755 # σM, zM = first(zip(eachcol(σMs), eachslice(zMs_subjects; dims=3)))
2856 cat3 = (x,y) -> cat (x,y,dims= 3 )
2957 # map across subjects (n_batch)
3058 # ζMs_vec = map(eachcol(σMs), eachslice(zMs_subjects; dims=3)) do σM, zM
59+ ζMs1 = ChainRulesCore. @ignore_derivatives similar (ϕunc, size (zMs_subjects[:,:,1 ]' ))
3160 fBlock = let UMs = UMs, rangesM = collect (rangesM) # without collect, type unstable
32- function fBlock_inner (σM, zM)
61+ function fBlock_inner (σM, zM):: typeof (ζMs1)
62+ # generator does not work with Zygote
63+ # vcat(...) is not faster than mapreduce
64+ # g = map( UMs, rangesM) do Ui, ri # n_θM, n_MC
65+ # #(zM[:,ri]' * Ui * diagm(σM[ri]))'
66+ # diagm(σM[ri]) * Ui' * zM[:, ri]'
67+ # end
68+ # vcat(g...)
3369 mapreduce (vcat, UMs, rangesM) do Ui, ri # n_θM, n_MC
34- ri :: UnitRange{Int}
35- # (zM[:,ri]' * Ui * diagm(σM[ri]))'
36- diagm (σM[ri]) * Ui' * zM[:, ri]'
70+ # (zM[:,ri]' * (Ui * Diagonal(σM[ri])))'
71+ # Diagonal is faster than diagm and works with GPU
72+ Diagonal (σM[ri]) * Ui' * zM[:, ri]' # transpose to not return adjoint
3773 end
3874 end
3975 end
40- ζMs1 = ChainRulesCore. @ignore_derivatives fBlock (σMs[:,1 ], zMs_subjects[:,:,1 ])
76+ # ζMs1 = ChainRulesCore.@ignore_derivatives fBlock(σMs[:,1], zMs_subjects[:,:,1])
77+ # TMR = ChainRulesCore.@ignore_derivatives typeof(similar(ϕq, size(zMs)))
4178 # TB = Base.infer_return_type(fBlock, (typeof(σMs[:,1]), typeof(zMs_subjects[:,:,1])))
4279 # ζMs_vec = map(fBlock, eachcol(σMs[:,2:end]), eachslice(zMs_subjects[:,:,2:end]; dims=3), init = ζMs1)
43- ζMs_vec = map ((σM, zM) -> fBlock (σM, zM):: typeof (ζMs1), eachcol (σMs), eachslice (zMs_subjects; dims= 3 ))
80+ # ζMs_vec = map((σM, zM) -> fBlock(σM, zM)::TMR, eachcol(σMs), eachslice(zMs_subjects; dims=3))
81+ ζMs_vec = map ((σM, zM) -> fBlock (σM, zM), eachcol (σMs), eachslice (zMs_subjects; dims= 3 ))
4482 # zM = zMs_subjects[:,:,1]
4583 # ζMs_vec = [fBlock(σMs[:,i], zM) for i in axes(σMs, 2)]
4684 # ζMs_vec = [fBlock(σMs[:,1], zM)]
@@ -62,25 +100,6 @@ function sample_ζresid_norm(app::MeanHVIApproximation,
62100 # end
63101 # ζMs_parfirst_resids = reshape(ζMs_resids_stacked, n_θM, n_batch, n_MC)
64102 #
65- # σzP = σP .* reshape(zP, (n_θP, n_MC))
66- # Ui, ri = first(zip(UPs, rangesP))
67- local ζP_resids = if isempty (ζP)
68- # provide init of correct empty matrix type
69- # single branch with init to mapreduce has Problems with Zygote
70- ChainRulesCore. @ignore_derivatives ζMs_parfirst_resids[1 : 0 ,1 ,1 : n_MC]
71- else
72- mapreduce (vcat, UPs, rangesP) do Ui, ri
73- diagm (σP[ri]) * Ui' * zP[:,ri]'
74- end
75- end
76- #
77- () -> begin
78- tmp = tmp1 = (σzP[ri,:]' * Ui)'
79- tmp = tmp2 = (zP * (Ui * diagm (σP)))'
80- tmp = tmp3 = (zP * Ui * diagm (σP))' # σ on wrong side of U
81- tmp = tmp4 = diagm (σP) * Ui' * zP' # σ on wrong side of U
82- std (tmp[2 ,:])
83- end
84103 diagUσ = vcat (σP, vec (σMs))
85104 ζP_resids, ζMs_parfirst_resids, diagUσ
86- end
105+ end
0 commit comments