Skip to content

Commit f162e69

Browse files
committed
provide HVIApproximation type to sampling
to allow different implementations
1 parent ee5fa88 commit f162e69

10 files changed

Lines changed: 181 additions & 59 deletions

src/HVIApproximation.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""
2+
AbstractHVIApproximation
3+
4+
Provides a type hierarchy to distinguish different forms and
5+
parameterizations of posterior approximations.
6+
"""
7+
abstract type AbstractHVIApproximation end
8+
9+
abstract type AbstractMeanHVIApproximation <: AbstractHVIApproximation end
10+
11+
struct MeanHVIApproximation <: AbstractMeanHVIApproximation end
12+
struct MeanHVIApproximationMat <: AbstractMeanHVIApproximation end
13+
14+

src/HybridProblem.jl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct HybridProblem <: AbstractHybridProblem
3939
n_site::Int
4040
n_batch::Int
4141
pbm_covars::NTuple{_N, Symbol} where _N
42+
approx::AbstractHVIApproximation
4243
#inner constructor to constrain the types
4344
function HybridProblem(
4445
θM::CA.ComponentVector,
@@ -57,10 +58,11 @@ struct HybridProblem <: AbstractHybridProblem
5758
n_batch::Int,
5859
cor_ends::NamedTuple = (P = [length(ϕq[Val(:μP)])], M = [length(θM)]),
5960
pbm_covars::NTuple{N,Symbol} = (),
61+
approx::AbstractHVIApproximation = MeanHVIApproximation()
6062
) where N
6163
new(
6264
θM, f_batch, g, ϕg, ϕq, priors, py, transM, transP, cor_ends,
63-
train_dataloader, n_covar, n_site, n_batch, pbm_covars)
65+
train_dataloader, n_covar, n_site, n_batch, pbm_covars, approx)
6466
end
6567
end
6668

@@ -96,7 +98,10 @@ end
9698
Gather all information from another `AbstractHybridProblem` with possible
9799
updating of some of the entries.
98100
"""
99-
function HybridProblem(prob::AbstractHybridProblem; scenario = (),
101+
function HybridProblem(prob::AbstractHybridProblem; scenario = Val(()), kwargs...)
102+
update_hybridProblem(prob; scenario, kwargs...)
103+
end
104+
function update_hybridProblem(prob::AbstractHybridProblem; scenario,
100105
θM = get_hybridproblem_par_templates(prob; scenario).θM,
101106
g = get_hybridproblem_MLapplicator(prob; scenario)[1],
102107
ϕg = get_hybridproblem_MLapplicator(prob; scenario)[2],
@@ -114,6 +119,7 @@ function HybridProblem(prob::AbstractHybridProblem; scenario = (),
114119
ϕq = get_hybridproblem_ϕq(prob; scenario),
115120
θP = nothing,
116121
ϕunc = nothing,
122+
approx::AbstractHVIApproximation = MeanHVIApproximation(),
117123
)
118124
cor_ends_new = if !isnothing(cor_ends)
119125
# if new cor_ends was specified then re-initialize the ρsP and ρsM in ϕq
@@ -130,9 +136,14 @@ function HybridProblem(prob::AbstractHybridProblem; scenario = (),
130136
ϕq = CA.ComponentVector(ϕq; ϕunc...)
131137
end
132138
HybridProblem(θM, ϕq, g, ϕg, f_batch, priors, py, transM, transP, train_dataloader,
133-
n_covar, n_site, n_batch, cor_ends_new, pbm_covars)
139+
n_covar, n_site, n_batch, cor_ends_new, pbm_covars, approx)
140+
end
141+
142+
function HybridProblem(prob::HybridProblem; kwargs... )
143+
update_hybridProblem(prob; scenario = Val(()), kwargs..., approx = prob.approx)
134144
end
135145

146+
136147
# """
137148
# update(prob::HybridProblem; ...)
138149

src/HybridSolver.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ function CommonSolve.solve(prob::AbstractHybridProblem, solver::HybridPosteriorS
187187
θmean_quant=0.0,
188188
is_inferred::Val{is_infer} = Val(false),
189189
is_omit_priors::Val{omit_priors} = Val(false),
190+
approx = prob.approx,
190191
kwargs...
191192
) where {scen, is_infer, omit_priors}
192193
pt = get_hybridproblem_par_templates(prob; scenario)
@@ -240,7 +241,7 @@ function CommonSolve.solve(prob::AbstractHybridProblem, solver::HybridPosteriorS
240241
g_dev, transP, transMs, f_dev, py;
241242
solver.n_MC, solver.n_MC_cap, cor_ends, priors_θP_mean, priors_θMs_mean,
242243
cdev=infer_cdev(gdevs), pbm_covars, pt.θP, int_ϕq, int_ϕg_ϕq, priorsP, priorsM,
243-
is_omit_priors, zero_prior_logdensity,
244+
is_omit_priors, zero_prior_logdensity, approx,
244245
)
245246
# test loss function once
246247
# tmp = first(train_loader_dev)
@@ -294,7 +295,7 @@ function get_loss_elbo(g, transP, transMs, f, py;
294295
cor_ends, priors_θP_mean, priors_θMs_mean, cdev, pbm_covars, θP,
295296
int_ϕq, int_ϕg_ϕq,
296297
priorsP, priorsM, floss_penalty = zero_penalty_loss,
297-
is_omit_priors, zero_prior_logdensity,
298+
is_omit_priors, zero_prior_logdensity, approx,
298299
)
299300
let g = g, transP = transP, transMs = transMs, f = f, py = py,
300301
n_MC = n_MC, n_MC_cap = n_MC_cap, n_MC_mean = n_MC_mean,
@@ -305,7 +306,8 @@ function get_loss_elbo(g, transP, transMs, f, py;
305306
trans_mP=StackedArray(transP, n_MC_mean),
306307
trans_mMs=StackedArray(transMs.stacked, n_MC_mean),
307308
priorsP=priorsP, priorsM=priorsM, floss_penalty=floss_penalty,
308-
is_omit_priors = is_omit_priors, zero_prior_logdensity = zero_prior_logdensity
309+
is_omit_priors = is_omit_priors, zero_prior_logdensity = zero_prior_logdensity,
310+
approx = approx
309311

310312
function loss_elbo(ϕ, rng, xM, xP, y_o, y_unc, i_sites; is_testmode)
311313
#ϕc = int_ϕg_ϕq(ϕ)
@@ -315,7 +317,7 @@ function get_loss_elbo(g, transP, transMs, f, py;
315317
n_MC, n_MC_cap, n_MC_mean, cor_ends, priors_θP_mean, priors_θMs_mean,
316318
cdev, pbm_covar_indices, transP, transMs, trans_mP, trans_mMs,
317319
priorsP, priorsM, floss_penalty, #ϕg = ϕc.ϕg, ϕq = ϕc.ϕq,
318-
is_testmode, is_omit_priors, zero_prior_logdensity,
320+
is_testmode, is_omit_priors, zero_prior_logdensity, approx,
319321
)
320322
end
321323
end

src/HybridVariationalInference.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ VERSION >= v"1.11.0-DEV.469" && eval(Meta.parse("public Exp"))
4040
VERSION >= v"1.11.0-DEV.469" && eval(Meta.parse("public Logistic"))
4141
include("bijectors_utils.jl")
4242

43+
export AbstractHVIApproximation, AbstractMeanHVIApproximation
44+
export MeanHVIApproximation, MeanHVIApproximationMat
45+
include("HVIApproximation.jl")
46+
4347
export AbstractComponentArrayInterpreter, ComponentArrayInterpreter,
4448
StaticComponentArrayInterpreter
4549
export flatten1, get_concrete, get_positions, stack_ca_int, compose_interpreters
@@ -107,6 +111,7 @@ include("cholesky.jl")
107111

108112
export neg_elbo_gtf, sample_posterior, predict_hvi, zero_penalty_loss
109113
include("elbo.jl")
114+
include("elbo2.jl")
110115

111116
export init_hybrid_params, init_hybrid_ϕunc
112117
include("init_hybrid_params.jl")

src/cholesky.jl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ end
253253
"""
254254
transformU_block_cholesky1(v::AbstractVector, cor_ends)
255255
256-
Transform a parameterization v of a blockdiagonal of upper triangular matrices
256+
Transform a parameterization, `v`, of a blockdiagonal of upper triangular matrices
257257
into the this matrix.
258258
`cor_ends` is an AbstractVector of Integers specifying the last column of each block.
259259
E.g. For a matrix with a 3x3, a 2x2, and another single-entry block,
@@ -262,6 +262,26 @@ the blocks start at columns (3,5,6). It defaults to a single entire block.
262262
An correlation parameterization can parameterize a block of a single parameter,
263263
or an empty parameter block. To indicate the empty block, provide `cor_ends == [0]`.
264264
"""
265+
function transformU_blocks_cholesky1(
266+
v::AbstractVector{T}, cor_ends::AbstractVector{TI}=Int[]) where {T,TI<:Integer}
267+
if length(cor_ends) <= 1 # if there is only one block, return it
268+
# (cor_ends == [0]) no parameters at all (and also no correclation)
269+
# (cor_ends == [1]) a single parameter (and also no correclation)
270+
create_empty = (cor_ends == [0])
271+
return [transformU_cholesky1(v; create_empty)], 1:0
272+
end
273+
cor_counts = get_cor_counts(cor_ends) # number of correlation parameters
274+
#@show cor_counts
275+
ranges = ChainRulesCore.@ignore_derivatives (
276+
begin
277+
cor_start = (i == 1 ? one(TI) : cor_counts[i-1] + one(TI))
278+
cor_start:cor_counts[i]
279+
end for i in 1:length(cor_counts)
280+
)
281+
#@show collect(ranges)
282+
[transformU_cholesky1(v[r]) for r in ranges], ranges
283+
end
284+
265285
function transformU_block_cholesky1(
266286
v::AbstractVector{T}, cor_ends::AbstractVector{TI}=Int[]) where {T,TI<:Integer}
267287
# (cor_ends == [0]) no parameters at all (and also no correclation)
@@ -284,6 +304,7 @@ function transformU_block_cholesky1(
284304
return (U)
285305
end
286306

307+
287308
function _create_blockdiag(::AbstractArray{T}, blocks::AbstractArray) where {T}
288309
BlockDiagonal(blocks)
289310
end

src/elbo.jl

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ function neg_elbo_gtf_components(rng, ϕ::AbstractVector{FT}, g, f, py,
6262
is_testmode,
6363
is_omit_priors,
6464
zero_prior_logdensity,
65+
approx::AbstractHVIApproximation,
6566
) where {FT}
6667
n_MCr = isempty(priors_θP_mean) ? n_MC : max(n_MC, n_MC_mean)
67-
ζsP, ζsMs, σ = generate_ζ(rng, g, ϕ, xM; n_MC=n_MCr, cor_ends, pbm_covar_indices,
68+
ζsP, ζsMs, σ = generate_ζ(approx, rng, g, ϕ, xM; n_MC=n_MCr, cor_ends, pbm_covar_indices,
6869
int_ϕq, int_ϕg_ϕq, is_testmode)
6970
ζsP_cpu = cdev(ζsP) # fetch to CPU, because for <1000 sites (n_batch) this is faster
7071
ζsMs_cpu = cdev(ζsMs) # fetch to CPU, because for <1000 sites (n_batch) this is faster
@@ -382,6 +383,7 @@ function sample_posterior(rng, prob::AbstractHybridProblem, xM::AbstractMatrix;
382383
scenario=Val(()),
383384
n_sample_pred=200,
384385
gdevs = get_gdev_MP(scenario),
386+
approx = nothing,
385387
kwargs...
386388
)
387389
n_site, n_batch = get_hybridproblem_n_site_and_batch(prob; scenario)
@@ -400,9 +402,13 @@ function sample_posterior(rng, prob::AbstractHybridProblem, xM::AbstractMatrix;
400402
int_ϕq = interpreters.ϕq
401403
transMs = StackedArray(transM, n_batch)
402404
g_dev, ϕ_dev = gdevs.gdev_M(g), gdevs.gdev_M(ϕ)
405+
if isnothing(approx)
406+
approx = prob.approx # assuming has field approx, e.g. if its a HybridProblem
407+
end
403408
(; θsP, θsMs, entropy_ζ) = sample_posterior(rng, g_dev, ϕ_dev, xM;
404409
int_ϕg_ϕq, int_ϕq, transP, transM,
405-
n_sample_pred, cdev=infer_cdev(gdevs), cor_ends, pbm_covar_indices, kwargs...)
410+
n_sample_pred, cdev=infer_cdev(gdevs), cor_ends, pbm_covar_indices, approx,
411+
kwargs...)
406412
θsPc = ComponentArrayInterpreter(par_templates.θP, (n_sample_pred,))(θsP)
407413
θsMsc = ComponentArrayInterpreter((n_site,), par_templates.θM, (n_sample_pred,))(θsMs)
408414
(; θsP=θsPc, θsMs=θsMsc, entropy_ζ)
@@ -418,8 +424,9 @@ function sample_posterior(rng, g, ϕ::AbstractVector, xM::AbstractMatrix;
418424
pbm_covar_indices,
419425
is_inferred::Val{is_infer} = Val(false),
420426
is_testmode,
427+
approx::AbstractHVIApproximation,
421428
) where is_infer
422-
ζsP_gpu, ζsMs_gpu, σ = generate_ζ(rng, g, CA.getdata(ϕ), CA.getdata(xM);
429+
ζsP_gpu, ζsMs_gpu, σ = generate_ζ(approx, rng, g, CA.getdata(ϕ), CA.getdata(xM);
423430
int_ϕg_ϕq, int_ϕq,
424431
n_MC=n_sample_pred, cor_ends, pbm_covar_indices, is_testmode)
425432
ζsP = cdev(ζsP_gpu)
@@ -434,6 +441,7 @@ function sample_posterior(rng, g, ϕ::AbstractVector, xM::AbstractMatrix;
434441
(; θsP, θsMs, entropy_ζ)
435442
end
436443

444+
437445
"""
438446
Generate samples of (inv-transformed) model parameters, ζ,
439447
and the vector of standard deviations, σ, i.e. the diagonal of the cholesky-factor.
@@ -445,7 +453,8 @@ model.
445453
The output shape of size `(n_site x n_par x n_MC)` is tailored to iterating
446454
each MC sample and then transforming each parameter on block across sites.
447455
"""
448-
function generate_ζ(rng, g, ϕ::AbstractVector{FT}, xM::MT;
456+
function generate_ζ(approx::AbstractMeanHVIApproximation, rng::AbstractRNG,
457+
g, ϕ::AbstractVector{FT}, xM::MT;
449458
int_ϕg_ϕq::AbstractComponentArrayInterpreter,
450459
int_ϕq::AbstractComponentArrayInterpreter,
451460
n_MC=3, cor_ends, pbm_covar_indices,
@@ -462,7 +471,7 @@ function generate_ζ(rng, g, ϕ::AbstractVector{FT}, xM::MT;
462471
# TODO replace pbm_covar_indices by ComponentArray? dimensions to be type-inferred?
463472
xMP0 = _append_each_covars(xM, CA.getdata(μ_ζP), pbm_covar_indices)
464473
μ_ζMs0 = g(xMP0, ϕg; is_testmode)
465-
ζP_resids, ζMs_parfirst_resids, σ = sample_ζresid_norm(rng, μ_ζP, μ_ζMs0, ϕq; n_MC, cor_ends, int_ϕq)
474+
ζP_resids, ζMs_parfirst_resids, σ = sample_ζresid_norm(approx, rng, μ_ζP, μ_ζMs0, ϕq; n_MC, cor_ends, int_ϕq)
466475
if pbm_covar_indices isa SA.SVector{0}
467476
# do not need to predict again but just add the residuals to μ_ζP and μ_ζMs
468477
#ζsP = μ_ζP .+ ζP_resids # n_par x n_MC # .+ on empty view does not work
@@ -559,8 +568,9 @@ ML-model predcitions of size `(n_θM, n_site)`.
559568
* `int_ϕq`: Interpret vector as ComponentVector with components
560569
ρsP, ρsM, logσ2_ζP, coef_logσ2_ζMs(intercept + slope),
561570
"""
562-
function sample_ζresid_norm(rng::Random.AbstractRNG, ζP::AbstractVector, ζMs::AbstractMatrix,
563-
args...; n_MC, cor_ends, int_ϕq)
571+
function sample_ζresid_norm(approx::AbstractHVIApproximation, rng::Random.AbstractRNG,
572+
ζP::AbstractVector, ζMs::AbstractMatrix, args...;
573+
n_MC, cor_ends, int_ϕq)
564574
n_θP, n_θMs = length(ζP), length(ζMs)
565575
# intm_PMs_parfirst = !isnothing(intm_PMs_parfirst) ? intm_PMs_parfirst : begin
566576
# n_θM, n_site_batch = size(ζMs)
@@ -569,14 +579,14 @@ function sample_ζresid_norm(rng::Random.AbstractRNG, ζP::AbstractVector, ζMs:
569579
# end
570580
#urandn = _create_randn(rng, CA.getdata(ζP), n_MC, n_θP + n_θMs)
571581
urandn = _create_randn(rng, CA.getdata(ζP), n_θP + n_θMs, n_MC)
572-
sample_ζresid_norm(urandn, CA.getdata(ζP), CA.getdata(ζMs), args...;
582+
sample_ζresid_norm(approx, urandn, CA.getdata(ζP), CA.getdata(ζMs), args...;
573583
cor_ends,
574584
int_ϕq=get_concrete(int_ϕq)
575585
)
576586
end
577587

578-
function sample_ζresid_norm(urandn::AbstractMatrix, ζP::TP, ζMs::TM,
579-
ϕq::AbstractVector;
588+
function sample_ζresid_norm(approx::MeanHVIApproximationMat, urandn::AbstractMatrix,
589+
ζP::TP, ζMs::TM, ϕq::AbstractVector;
580590
int_ϕq=get_concrete(ComponentArrayInterpreter(ϕq)),
581591
cor_ends
582592
) where {T,TP<:AbstractVector{T},TM<:AbstractMatrix{T}}

src/elbo2.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function sample_ζresid_norm(app::MeanHVIApproximation, z::AbstractMatrix, ζP::TP, ζMs::TM,
2+
ϕq::AbstractVector;
3+
int_ϕq=get_concrete(ComponentArrayInterpreter(ϕq)),
4+
cor_ends
5+
) where {T,TP<:AbstractVector{T},TM<:AbstractMatrix{T}}
6+
ϕuncc = int_ϕq(CA.getdata(ϕq))
7+
n_θP, n_θMs, (n_θM, n_batch) = length(ζP), length(ζMs), size(ζMs)
8+
# do not create a UpperTriangular Matrix of an AbstractGÜUArray in transformU_cholesky1
9+
ρsP = isempty(ϕuncc[Val(:ρsP)]) ? similar(ϕuncc[Val(:ρsP)]) : ϕuncc[Val(:ρsP)] # required by zygote
10+
UPs, rangesP = transformU_blocks_cholesky1(ρsP, cor_ends.P)
11+
UP = transformU_block_cholesky1(ρsP, cor_ends.P)
12+
ρsM, rangesM = isempty(ϕuncc[Val(:ρsM)]) ? similar(ϕuncc[Val(:ρsM)]) : ϕuncc[Val(:ρsM)] # required by zygote
13+
# cholesky factor of the correlation: diag(UM' * UM) .== 1
14+
# coefficients ρsM can be larger than 1, still yielding correlations <1 in UM' * UM
15+
UMs = transformU_block_cholesky1(ρsM, cor_ends.M)
16+
cf = ϕuncc[Val(:coef_logσ2_ζMs)]
17+
logσ2_logMs = vec(cf[1, :] .+ cf[2, :] .* ζMs)
18+
logσ2_ζP = vec(CA.getdata(ϕuncc[Val(:logσ2_ζP)]))
19+
# CUDA cannot multiply BlockDiagonal * Diagonal, construct already those blocks
20+
σMs = reshape(exp.(logσ2_logMs ./ 2), n_θM, :)
21+
σP = exp.(logσ2_ζP ./ 2)
22+
# create random numbers from U diag(σ) z = (σ .* z)
23+
24+
25+
# # BlockDiagonal does work with CUDA, but not with combination of Zygote and CUDA
26+
# # need to construct full matrix for CUDA
27+
# Uσ, diagUσ = _compute_choleskyfactor(UP, UM, σP, σMs, n_batch) # inferred only BlockDiagonal
28+
# #diagUσ = diag(Uσ)::typeof(σP) # elements of the diagonal: standard deviations
29+
# n_MC = size(urandn, 2) # TODO transform urandn
30+
# # is this multiplication efficient if Uσ is not concrete but only sumtype BlockDiagonal?
31+
# ζ_resids_parfirst = (Uσ' * urandn) #::typeof(urandn) # n_par x n_MC
32+
# #ζ_resids_parfirst = urandn' * Uσ # n_MC x n_par
33+
# # need to handle empty(ζP) explicitly, otherwise Zygote tries to take gradient
34+
# ζP_resids = isempty(ζP) ? ζ_resids_parfirst[1:0, :] : ζ_resids_parfirst[1:n_θP, :]
35+
# ζMs_parfirst_resids = reshape(ζ_resids_parfirst[(n_θP+1):end, :], n_θM, n_batch, n_MC)
36+
37+
38+
ζP_resids, ζMs_parfirst_resids, diagUσ
39+
# #map(std, eachcol(ζ_resids_parfirst[:, 3:8]))
40+
# ζ_resid = transpose_mPMs_sitefirst(ζ_resids_parfirst; intm_PMs_parfirst)
41+
# #map(std, eachcol(ζ_resid[:, 3:8])) # all ~ 0.1 in sample_ζresid_norm cpu
42+
# #map(std, eachcol(ζ_resid[:, 2 + n_batch .+ (-1:5)])) # all ~ 100, except first two
43+
# # returns AbstractGPUuArrays to either continue on GPU or need to transfer to CPU
44+
# ζ_resid, diagUσ
45+
end

test/test_HybridProblem.jl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ using Functors
2323

2424
cdev = cpu_device()
2525

26-
#scenario = Val((:default,))
26+
#scenario = Val((:default, ))
27+
#scenario = Val((:MeanHVIApproxMat,))
2728
#scenario = Val((:covarK2,))
2829
#scen = CP._val_value(scenario)
2930

@@ -89,10 +90,15 @@ function construct_problem(; scenario::Val{scen}) where scen
8990
xPvec=xP[:,1])
9091
ϕunc0 = init_hybrid_ϕunc(cor_ends, zero(FT))
9192
ϕq = CP.update_μP_by_θP(ϕunc0, θP, transP)
93+
approx = if (:MeanHVIApproxMat scen)
94+
MeanHVIApproximationMat()
95+
else
96+
MeanHVIApproximation()
97+
end
9298
HybridProblem(θM, ϕq, g_chain_scaled, ϕg0,
9399
f_batch, priors_dict, py,
94100
transM, transP, train_dataloader, n_covar, n_site, n_batch,
95-
cor_ends, pbm_covars,
101+
cor_ends, pbm_covars, approx,
96102
#ϕunc0,
97103
)
98104
end
@@ -191,14 +197,16 @@ test_without_flux = (scenario) -> begin
191197
end
192198
end
193199

200+
#test_without_flux(Val((:MeanHVIApproximation,))) # not used in loss_gf
194201
test_without_flux(Val((:default,)))
195202
test_without_flux(Val((:covarK2,)))
196203

197204
import CUDA, cuDNN
198205
using GPUArraysCore
199206
import Flux
200207

201-
gdev = gpu_device()
208+
CUDA.device!(2) # TODO remove after GPU 0 becomes available again
209+
gdev = gpu_device()
202210
#methods(CP.vec2uutri)
203211

204212
test_with_flux = (scenario) -> begin
@@ -373,6 +381,7 @@ test_with_flux_gpu = (scenario) -> begin
373381
end # if gdev isa MLDataDevices.AbstractGPUDevice
374382
end # test_with flux
375383

384+
test_with_flux_gpu(Val((:MeanHVIApproxMat,)))
376385
test_with_flux_gpu(Val((:default,)))
377386
test_with_flux_gpu(Val((:covarK2,)))
378387
test_with_flux_gpu(Val((:default,:useSitePBM)))

0 commit comments

Comments
 (0)