Gen: Как объединить несколько следов генеративной функции в генеративную функцию высшего порядка? - PullRequest
0 голосов
/ 04 июля 2019

Я изучаю «Введение в моделирование в Gen» в https://github.com/probcomp/gen-quickstart

Раздел 5 (Вызов других порождающих функций) просит «Построить набор данных, для которого он неоднозначенЛучшая ли модель - линейная или синусоидальная? "

Мне трудно понять, как я работаю со следами (и возвратами) функций компонента, чтобы создать значимую трассу высшего порядка, которую я могу использовать,

Для меня самая простая «неоднозначная» модель - line(xs).+sine(xs).Так что я Gen.simulate ed 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 to: intercept,: phase и т. Д., Чтобы я мог включить его в свой след позже.

Кстати, когда я сделаю:

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

Я получаю failed attempt at function

Пожалуйста, помогите спасибо!

Ответы [ 2 ]

1 голос
/ 08 июля 2019

Привет, спасибо за интерес к 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 (в простой Джулии), который, по вашему мнению, может сделать набор данных с неоднозначными затруднениями. Затем вы можете передать свои xs и ys в функцию do_inference, определенную ранее в записной книжке, чтобы увидеть, что система делает вывод о вашем наборе данных. Обратите внимание, что функция do_inference создает карту выбора constraint , которая ограничивает каждый (:y, i) значением ys[i] из набора данных, который вы передали. Это работает, потому что (:y, i) всегда является именем i-го назначения данных , независимо от значения :is_line.

Обновление / управление следами

Вы пишете:

Я бы ожидал, что смогу исследовать трассу синуса / line_model из комбо и делать поэлементное добавление к трассе, чтобы получить новую трассу. И не нужно случайным образом выбирать число, близкое к: intercept,: phase и т. Д., Чтобы я мог включить его в свой след позже.

Вы можете, конечно, дважды вызвать simulate, чтобы получить две трассировки, кроме порождающей функции, такой как combo. Но трассировками нельзя манипулировать произвольными способами (например, «поэлементное сложение»): в качестве структур данных трассировки поддерживают определенные инварианты, например всегда знают точную вероятность их текущих значений в модели, которая их сгенерировала, и всегда содержат значения, которые на самом деле могли иметь был сгенерирован из модели.

Словарная структура данных, которую вы ищете, является картой выбора. Карты выбора являются изменяемыми и могут быть созданы для включения произвольных значений по произвольным адресам. Например, вы можете написать:

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

Карты выбора могут использоваться в качестве ограничений для генерации новых трасс (с использованием Gen.generate), в качестве аргументов низкоуровневого метода Gen * Gen.update (с позволяет обновлять трассировку при повторном вычислении любых релевантных вероятностей и с ошибками, если ваши обновления недействительны) и в некоторых других местах.

Надеюсь, это поможет:)

0 голосов
/ 12 июля 2019

Благодаря разъяснениям Алекса Лью, ответ намного проще, чем я его представлял.Вот что я сделал:

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
...