我正在阅读“Gen 建模简介”笔记本,网址为 https://github.com/probcomp/gen-quickstart
第 5 节(调用其他生成函数)要求“构造一个数据集,对于该数据集,线模型还是正弦波模型最好不明确”
我很难理解如何使用组件函数的跟踪(和返回)来创建我可以使用的有意义的高阶跟踪。
对我来说,最直接的“模糊”模型是
line(xs).+sine(xs)
。所以我Gen.simulate
编辑了line
和sine
来获取痕迹并将它们添加在一起,如下所示:
@gen function combo(xs::Vector{Float64})
my_sin = simulate(sine_model_2,(xs,))
my_lin = simulate(line_model_2,(xs,))
if @trace(bernoulli(0.5), :is_line)
@trace(normal(get_choices(my_lin)[:slope], 0.01), :slope)
@trace(normal(get_choices(my_lin)[:intercept], 0.01), :intercept)
@trace(normal(get_choices(my_lin)[:noise], 0.01), :noise)
else
@trace(normal(get_choices(my_sin)[:phase], 0.01), :phase)
@trace(normal(get_choices(my_sin)[:period], 0.01), :period)
@trace(normal(get_choices(my_sin)[:amplitude], 0.01), :amplitude)
@trace(normal(get_choices(my_sin)[:noise], 0.01), :noise)
end
combo = [get_choices(my_sin)[(:y, i)] + get_choices(my_lin)[(:y, i)] for i=1:length(xs)]
for (i, c) in enumerate(combo)
@trace(normal(c, 0.1), (:y, i))
end
end;
这显然是错误的,我知道我错过了 Gen 中跟踪和概率编程的整个想法中的一些基本知识。
我希望能够从组合内内省 sine/line_model 的跟踪,并对跟踪进行按元素相加以获得新的跟踪。并且不必随机选择一个数字close来:截距、:相位等,这样我以后就可以将其包含在我的跟踪中。
顺便说一句,当我这样做时:
traces = [Gen.simulate(combo,(xs,)) for _=1:12];
grid(render_combined, traces)
请帮忙谢谢!
您好——感谢您对 Gen 的兴趣! :)
组合模型轨迹的地址
教程中的组合模型如下所示:
@gen function combined_model(xs::Vector{Float64})
if @trace(bernoulli(0.5), :is_line)
@trace(line_model_2(xs))
else
@trace(sine_model_2(xs))
end
end;
其痕迹将具有以下地址:
:is_line
,存储一个布尔值,指示生成的数据集是否是线性的。line_model_2
或 sine_model_2
的任何地址,具体取决于所调用的地址。 请注意,
line_model_2
和sine_model_2
的迹线都包含(:y, i)
和i
之间每个整数1
的地址length(xs)
。因此,combined_model
的痕迹也将如此:这些是代表最终采样的 y
值的地址,无论是两个进程中的哪一个生成的。
构建新数据集
“构造一个数据集,对于该数据集,直线波模型还是正弦波模型最好”并不需要编写新的生成函数(使用
@gen
),而是构建一个 xs
和 的列表您认为可能会形成难以消除歧义的数据集的 ys
列表(用普通的 Julia 表示)。然后,您可以将 xs
和 ys
传递到笔记本前面定义的 do_inference
函数中,以查看系统对您的数据集得出的结论。请注意,do_inference
函数构造了一个constraint选择映射,将每个(:y, i)
限制为您传入的数据集中的值ys[i]
。这是有效的,因为(:y, i)
始终是第i个数据点的名称,无论:is_line
的值。
更新/操作痕迹
你写:
我希望能够从组合内内省 sine/line_model 的跟踪,并对跟踪进行按元素相加以获得新的跟踪。并且不必随机选择一个接近 :intercept、:phase 等的数字,这样我就可以稍后将其包含在我的跟踪中。
您当然可以在像
simulate
这样的生成函数之外调用两次combo
来获取两条轨迹。但是迹线不能以任意方式操作(例如“元素加法”):作为数据结构,迹线保持某些不变量,例如始终知道生成它们的模型下其当前值的确切概率,并且始终保留实际可能具有的值是从模型生成的。
您正在寻找的类似字典的数据结构是选择图。选择映射是可变的,并且可以构建为包含任意地址处的任意值。例如,您可以写:
observations = Gen.choicemap()
for (i, y) in enumerate(ys)
observations[(:y, i)] = y
end
Choicemaps 可以用作生成新轨迹的约束(使用
Gen.generate
),作为 Gen 的低级 Gen.update
方法的参数(允许您在重新计算任何相关概率时更新轨迹,如果更新无效则出错),以及其他几个地方。
希望有帮助:)
感谢 Alex Lew 的澄清,答案比我想象的要简单得多。这就是我所做的:
xs = [-5:0.1;5;]
ambiguous = [0.3*x+0.2*sin(x)+normal(0,.5) for x in xs];
ambig_trace = do_inference(combined_model,xs, ambiguous, 100)
render_combined(ambig_trace)
生产:
(或者更正弦的东西,如果推断出的话)
最后:
n_infers = 100
is_sine = 0
for i=1:n_infers
curr_trace = do_inference(combined_model, xs, ambiguous, 100)
if !curr_trace[:is_line] is_sine+=1 end
end
println("posterior probability of sine wave model is $(is_sine/n_infers)")
# => posterior probability of sine wave model is 0.52