Compare two Turing models with LOO: SE is NaN

I am trying to compare two SequentialSamplingModels with loo using ParetoSmooth.jl, but I think I am doing something wrong:

using Turing
using SequentialSamplingModels
using Random
using Distributions
using DataFrames
using StatsPlots
using StatsModels
using StatsBase
using ParetoSmooth

# Generate data (1000 obs)
Random.seed!(6)

dist = LBA(Ξ½=[3.0, 2.0], A=0.8, k=0.2, Ο„=0.3)
data = rand(dist, 1000)


# ---------------------
# Models
@model function model_lba(data; min_rt=minimum(data.rt))
    Ξ½ ~ filldist(Normal(0, 1), 2)
    A ~ truncated(Normal(0.8, 0.4), 0.0, Inf)
    k ~ truncated(Normal(0.2, 0.2), 0.0, Inf)
    Ο„ ~ Uniform(0.0, min_rt)

    data ~ LBA(; Ξ½, A, k, Ο„)
end
chain_lba = sample(model_lba(data), NUTS(), 1000)


@model function model_lnr(data; min_rt=minimum(data.rt))
    Ξ½ ~ filldist(Normal(0, 1), 2)
    Οƒ ~ truncated(Normal(0, 1), 0.0, Inf)
    Ο„ ~ Uniform(0.0, min_rt)

    data ~ LNR(; Ξ½, Οƒ, Ο„)
end
chain_lnr = sample(model_lnr(data), NUTS(), 1000)

When I run the following:

rez1 = psis_loo(model_lba(data), chain_lba)
rez2 = psis_loo(model_lnr(data), chain_lnr)
loo_compare((lba=rez1, lnr=rez2))

While the comparison works, the psis_loo() function returns

β”Œ Warning: Some Pareto k values are extremely high (>1). PSIS will not produce consistent estimates.
β”” @ ParetoSmooth C:\Users\domma\.julia\packages\ParetoSmooth\Ml7Gb\src\InternalHelpers.jl:47
Results of PSIS-LOO-CV with 1000 Monte Carlo samples and 1 data points. Total Monte Carlo SE of NaN.
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           β”‚  total β”‚ se_total β”‚   mean β”‚ se_mean β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   cv_elpd β”‚ 452.85 β”‚      NaN β”‚ 452.85 β”‚     NaN β”‚
β”‚ naive_lpd β”‚ 456.28 β”‚      NaN β”‚ 456.28 β”‚     NaN β”‚
β”‚     p_eff β”‚   3.43 β”‚      NaN β”‚   3.43 β”‚     NaN β”‚

I am not sure where it gets the β€œ1 data points” from, as there are 1000 observations :thinking:

Moreover, in this post, Aki mentions that it is useful to compare the ELPD relative to their SEs to have an idea of the magnitude of the difference. Hence I am wondering if this info (or some standardized difference) is available or can be computed? Thanks for any tips for model comparison!

I think the problem is that pointwise_log_likelihoods does not compute pointwise correctly for this type of model. The following should be 1000X1000X1 I believe

pointwise_log_likelihoods(model_lba(data), chain_lba)

I’ll continue digging to see where the error occurs.

I thought the issue was that nsamples was not defined. Adding that definition didn’t fix the problem. I’m not sure where in Turing the data size is computed.

It works if we use the list of tuples specification:

@model function model_lba(data; min_rt=0.2)
    # Priors
    Ξ½ ~ filldist(Normal(0, 1), 2)
    A ~ truncated(Normal(0.8, 0.4), 0.0, Inf)
    k ~ truncated(Normal(0.2, 0.2), 0.0, Inf)
    Ο„ ~ Uniform(0.0, min_rt)

    # Likelihood
    for i in 1:length(data)
        data[i] ~ LBA(; Ξ½, A, k, Ο„)
    end
end

dat = [(choice=data.choice[i], rt=data.rt[i]) for i in 1:length(data.rt)]
chain_lba = sample(model_lba(dat, min_rt=minimum(data.rt)), NUTS(), 1000)

rez1 = psis_loo(model_lba(dat, min_rt=minimum(data.rt)), chain_lba)
[ Info: No source provided for samples; variables are assumed to be from a Markov Chain. If the samples are independent, specify this with keyword argument `source=:other`.
Results of PSIS-LOO-CV with 1000 Monte Carlo samples and 1000 data points. Total Monte Carlo SE of 0.084.
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           β”‚  total β”‚ se_total β”‚  mean β”‚ se_mean β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   cv_elpd β”‚ 453.32 β”‚    27.43 β”‚  0.45 β”‚    0.03 β”‚
β”‚ naive_lpd β”‚ 457.57 β”‚    27.26 β”‚  0.46 β”‚    0.03 β”‚
β”‚     p_eff β”‚   4.25 β”‚     0.30 β”‚  0.00 β”‚    0.00 β”‚

That makes sense. Thanks for reporting. My guess is that length or something similar is called to extract the length of the vector.

I thought maybe the problem is that SequentialSamplingModels was not complying with the interface, but the problem occurs with other models. Consider the following:

using Turing
using ParetoSmooth
using Distributions

@model function model(data)
    ΞΌ ~ Normal()
    data ~ Normal(ΞΌ, 1)
end

data = rand(Normal(0, 1), 100)

chain = sample(model(data), NUTS(), 1000)
rez1 = psis_loo(model(data), chain)

Replacing the vectorized form with a for loop fixes the problem. I wonder whether the Turing should destructure the arrays to compute pointwise correctly. Of course, that may lead to other problems.

Using a for loop is currently the proper approach for using LOO with ParetoSmooth.jl. I will make a PR to explain that in the documentation. There might be a plan to improve the interface at some point in the future. Another alternative is Arviz.jl.

1 Like