Gen:如何将多个生成函数迹组合成一个高阶生成函数?

问题描述 投票:0回答:2

我正在阅读“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)

我明白了 failed attempt at function

请帮忙谢谢!

julia inference probabilistic-programming generative-programming
2个回答
1
投票

您好——感谢您对 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
方法的参数(允许您在重新计算任何相关概率时更新轨迹,如果更新无效则出错),以及其他几个地方。

希望有帮助:)


0
投票

感谢 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)

生产:

ambiguous 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
© www.soinside.com 2019 - 2024. All rights reserved.