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

Я изучаю тетрадь "Введение в моделирование в 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 внутри комбо и делать поэлементное добавление к трассе, чтобы получить новую трассу. И не нужно случайным образом выбирать число, близкое к:intercept,:phase и т. Д., Чтобы я мог включить его в свой след позже.

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

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

я получил

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

2 ответа

Решение

Привет, спасибо за интерес к 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 Функция создает карту выбора ограничений, которая ограничивает каждый (:y, i) к стоимости ys[i] из набора данных, который вы передали. Это работает, потому что (:y, i) всегда имя i-го datapoint, независимо от значения :is_line,

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

Ты пишешь:

Я ожидаю, что смогу исследовать трассу sine / 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 метод (с помощью которого можно обновить трассировку при повторном вычислении любых соответствующих вероятностей и с ошибками, если ваши обновления недействительны), и в некоторых других местах.

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

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

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)

производство:

ht tps:https://stackru.com/images/f5f587d8e6eebd92c6cf6bc707c26b66cc1143e1.png

(или что-то более синусоидальное, если это было выведено)

Тогда наконец:

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
Другие вопросы по тегам