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.simulate
ed line
和 sine
来获取痕迹并将它们加在一起,如下所示:
@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_2
或sine_model_2
的任何地址,具体取决于调用的地址。
请注意,line_model_2
和 sine_model_2
的跟踪都包含地址 (:y, i)
对应于 1
和 length(xs)
之间的每个整数 i
。正因为如此,combined_model
的跟踪也将如此:这些是代表最终采样的y
值的地址,无论两个进程中的哪一个生成它们。
构建新数据集
“构造一个不确定的数据集是线还是正弦波模型是最好的”的问题不需要编写新的生成函数(使用@gen
),而是构造一个@987654334的列表@ 和一个 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
这样的生成函数之外。但是迹线不能以任意方式进行操作(例如“元素相加”):作为数据结构,迹线保持某些不变量,例如始终知道其当前值在生成它们的模型下的确切概率,并始终保存实际可能具有的值由模型生成。
您正在寻找的类似字典的数据结构是一个选择图。 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:如何将多个生成函数轨迹组合成一个高阶生成函数?的主要内容,如果未能解决你的问题,请参考以下文章