I’m learning Turing. Can anyone help explain the following, I define two (hopefully) equivalent models one with loops and one without, the loop model is 50x slower, but actually produces useful results. This is a reduced version of my real model, two class mixture model where is class is described by a small number of 1D Gaussians:
@model function modelloop(x, configs, σ, ::Type{V} = Int64) where {V}
n = length(x)
w = [0.5, 0.5]
p = ones(5)/5
class = Vector{V}(undef, n)
pos = Vector{V}(undef, n)
for i = 1:n
class[i] ~ Categorical(w)
pos[i] ~ Categorical(p)
x[i] ~ Normal(configs[class[i]][pos[i]], σ)
end
end
@model function modelvec(x, configs, σ)
n = length(x)
w = [0.5, 0.5]
p = ones(5)/5
class ~ filldist(Categorical(w), n)
pos ~ filldist(Categorical(p), n)
x ~ arraydist(map((c, l) -> Normal(configs[c][l], σ), class, pos))
end
### data
n = 200
configs = [-820:180:-100, 280:180:1000]
class = rand(1:2, n);
pos = rand(1:5, n);
x = [rand(Normal(configs[c][p], 5)) for (c, p) in zip(class, pos)];
ml = modelloop(x, configs, 5)
mv = modelvec(x, configs, 5)
@time chain_loop = sample(ml, PG(5), 100); # 205 seconds
@time chain_vec = sample(mv, PG(5), 100); # 4 seconds!
counter(chain_loop.value.data[:, 1]), counter(chain_vec.value.data[:, 1])
(Accumulator(2.0 => 4, 1.0 => 96), Accumulator(2.0 => 44, 1.0 => 56))
In this case class 1 is correct for the first data point - modelloop
is producing good results, modelvec
appears to generate samples biased toward the correct class but with weight spread between the two.
Seems like I must be doing something stupid.