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

Posted

技术标签:

【中文标题】Gen:如何将多个生成函数轨迹组合成一个高阶生成函数?【英文标题】:Gen: How to combine multiple generative function traces in a higher-order generative function? 【发布时间】:2019-11-14 21:41:43 【问题描述】:

我正在阅读https://github.com/probcomp/gen-quickstart 上的“Gen 建模简介”笔记本

第 5 节(调用其他生成函数)要求“构建一个数据集,其中线或正弦波模型是否最佳”

我很难理解如何使用组件函数的跟踪(和返回)来创建我可以使用的有意义的高阶跟踪。

对我来说,最直接的“模棱两可”的模型是line(xs).+sine(xs)。所以我 Gen.simulateed linesine 来获取痕迹并将它们加在一起,如下所示:

@gen function combo(xs::VectorFloat64)
    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 到 :intercept、:phase 等,因此我可以稍后将其包含在我的跟踪中。

顺便说一句,当我这样做时:

traces = [Gen.simulate(combo,(xs,)) for _=1:12];
grid(render_combined, traces)

我明白了

请帮忙谢谢!

【问题讨论】:

你可能想在 repo 上问这个问题,因为 Gen 是全新的,所以这里还没有多少人知道它。 谢谢@ChrisRackauckas 我在回购上问过 -> 问题,但这不是正确的地方。希望我在继续阅读教程时能得到一些指导 【参考方案1】:

您好 — 感谢您对 Gen 的关注! :)

组合模型轨迹的地址

教程中的组合模型如下所示:

@gen function combined_model(xs::VectorFloat64)
    if @trace(bernoulli(0.5), :is_line)
        @trace(line_model_2(xs))
    else
        @trace(sine_model_2(xs))
    end
end;

它的踪迹将有以下地址:

:is_line,存储一个布尔值,指示生成的数据集是否是线性的。 来自line_model_2sine_model_2 的任何地址,具体取决于调用的地址。

请注意,line_model_2sine_model_2 的跟踪都包含地址 (:y, i) 对应于 1length(xs) 之间的每个整数 i。正因为如此,combined_model 的跟踪也将如此:这些是代表最终采样的y 值的地址,无论两个进程中的哪一个生成它们。

构建新数据集

“构造一个不确定的数据集是线还是正弦波模型是最好的”的问题不需要编写新的生成函数(使用@gen),而是构造一个@987654334的列表@ 和一个 ys 列表(纯 Julia),您认为它们可能会构成一个难以消除歧义的数据集。然后,您可以将 xsys 传递到笔记本前面定义的 do_inference 函数中,以查看系统对您的数据集的结论。请注意,do_inference 函数构造了一个 constraint 选择映射,该选择映射将每个 (:y, i) 约束为您传入的数据集中的值 ys[i]。这是有效的,因为 (:y, i) 始终是第 i 个的名称数据点,无论:is_line 的值如何。

更新/操作痕迹

你写:

我希望能够从组合中内省 sine/line_model 的迹线,并对迹线进行元素添加以获得新的迹线。并且不必随机选择接近 :intercept、:phase 等的数字,因此我可以稍后将其包含在我的跟踪中。

你当然可以调用simulate 两次来获得两条轨迹,在像combo 这样的生成函数之外。但是迹线不能以任意方式进行操作(例如“元素相加”):作为数据结构,迹线保持某些不变量,例如始终知道其当前值在生成它们的模型下的确切概率,并始终保存实际可能具有的值由模型生成。

您正在寻找的类似字典的数据结构是一个选择图。 Choicemaps 是可变的,可以构建为在任意地址包含任意值。例如,你可以写:

observations = Gen.choicemap()
for (i, y) in enumerate(ys)
  observations[(:y, i)] = y
end

Choicemaps 可用作生成新轨迹的约束(使用 Gen.generate),作为 Gen 的低级 Gen.update 方法的参数(允许您在重新计算任何相关概率时更新轨迹,并在更新时出错无效),以及在其他几个地方。

希望有帮助:)

【讨论】:

【参考方案2】:

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

【讨论】:

以上是关于Gen:如何将多个生成函数轨迹组合成一个高阶生成函数?的主要内容,如果未能解决你的问题,请参考以下文章

将多个集合组合成一个逻辑集合?

如何避免使用函数调用 WSAsend 将多个缓冲区组合成一个 UDP 数据包?

如何在matlab中存储和检索多个决策树

如何将两个特征/分类器组合成一个统一且更好的分类器?

AS3 加色合成。播放多个生成的声音

每天学一点Scala之 高阶函数 flatten